]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-567.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
119 #define kInterfaceSpecificOption "interface="
120
121 #define mDNS_IOREG_KEY "mDNS_KEY"
122 #define mDNS_IOREG_VALUE "2009-07-30"
123 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
124 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
125
126 // cache the InterfaceID of the AWDL interface
127 static mDNSInterfaceID AWDLInterfaceID;
128
129 // ***************************************************************************
130 // Globals
131
132 #if COMPILER_LIKES_PRAGMA_MARK
133 #pragma mark - Globals
134 #endif
135
136 // By default we don't offer sleep proxy service
137 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
138 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
139 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
140 mDNSexport int OfferSleepProxyService = 0;
141 mDNSexport int DisableSleepProxyClient = 0;
142 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
143
144 mDNSexport int OSXVers, iOSVers;
145 mDNSexport int KQueueFD;
146
147 #ifndef NO_SECURITYFRAMEWORK
148 static CFArrayRef ServerCerts;
149 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
150 #endif /* NO_SECURITYFRAMEWORK */
151
152 static CFStringRef NetworkChangedKey_IPv4;
153 static CFStringRef NetworkChangedKey_IPv6;
154 static CFStringRef NetworkChangedKey_Hostnames;
155 static CFStringRef NetworkChangedKey_Computername;
156 static CFStringRef NetworkChangedKey_DNS;
157 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
158 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
159 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
160 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
161 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
162
163 static char HINFO_HWstring_buffer[32];
164 static char *HINFO_HWstring = "Device";
165 static int HINFO_HWstring_prefixlen = 6;
166
167 mDNSexport int WatchDogReportingThreshold = 250;
168
169 dispatch_queue_t SSLqueue;
170
171 //To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue
172 static dispatch_queue_t DynamicStoreQueue;
173
174 #if TARGET_OS_EMBEDDED
175 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
176 #endif
177
178 #if APPLE_OSX_mDNSResponder
179 static mDNSu8 SPMetricPortability = 99;
180 static mDNSu8 SPMetricMarginalPower = 99;
181 static mDNSu8 SPMetricTotalPower = 99;
182 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
183 mDNSexport domainname ActiveDirectoryPrimaryDomain;
184 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
185 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
186 #endif // APPLE_OSX_mDNSResponder
187
188 // Don't send triggers too often. We arbitrarily limit it to three minutes.
189 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
190
191 // Used by AutoTunnel
192 const char btmmprefix[] = "btmmdns:";
193 const char dnsprefix[] = "dns:";
194
195 // String Array used to write list of private domains to Dynamic Store
196 static CFArrayRef privateDnsArray = NULL;
197
198 // ***************************************************************************
199 #if COMPILER_LIKES_PRAGMA_MARK
200 #pragma mark -
201 #pragma mark - D2D Support
202 #endif
203
204 #if !NO_D2D
205
206 mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
207 {
208 // AWDL wants the address and reverse address PTR record communicated
209 // via the D2D interface layer.
210 if (interface->InterfaceID == AWDLInterfaceID)
211 {
212 // only log if we have a valid record to start advertising
213 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
214 LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
215
216 if (interface->RR_A.resrec.RecordType)
217 external_start_advertising_service(&interface->RR_A.resrec, NULL);
218 if (interface->RR_PTR.resrec.RecordType)
219 external_start_advertising_service(&interface->RR_PTR.resrec, NULL);
220 }
221 }
222
223 mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
224 {
225 if (interface->InterfaceID == AWDLInterfaceID)
226 {
227 // only log if we have a valid record to stop advertising
228 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
229 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
230
231 if (interface->RR_A.resrec.RecordType)
232 external_stop_advertising_service(&interface->RR_A.resrec, NULL);
233 if (interface->RR_PTR.resrec.RecordType)
234 external_stop_advertising_service(&interface->RR_PTR.resrec, NULL);
235 }
236 }
237
238 // Name compression items for fake packet version number 1
239 static const mDNSu8 compression_packet_v1 = 0x01;
240
241 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" };
242 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
243 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
244
245 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
246 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
247
248 typedef struct D2DRecordListElem
249 {
250 struct D2DRecordListElem *next;
251 D2DServiceInstance instanceHandle;
252 D2DTransportType transportType;
253 AuthRecord ar; // must be last in the structure to accomodate extra space
254 // allocated for large records.
255 } D2DRecordListElem;
256
257 static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
258
259 typedef struct D2DBrowseListElem
260 {
261 struct D2DBrowseListElem *next;
262 domainname name;
263 mDNSu16 type;
264 unsigned int refCount;
265 } D2DBrowseListElem;
266
267 D2DBrowseListElem* D2DBrowseList = NULL;
268
269 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
270 {
271 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
272 ptr[1] = (mDNSu8)((val ) & 0xFF);
273 return ptr + sizeof(mDNSu16);
274 }
275
276 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
277 {
278 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
279 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
280 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
281 ptr[3] = (mDNSu8)((val ) & 0xFF);
282 return ptr + sizeof(mDNSu32);
283 }
284
285 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
286 {
287 const mDNSu8 * const start = (const mDNSu8 * const)in;
288 mDNSu8 *ptr = (mDNSu8*)start;
289 while(*ptr)
290 {
291 mDNSu8 c = *ptr;
292 out->c[ptr-start] = *ptr;
293 ptr++;
294 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
295 }
296 out->c[ptr-start] = *ptr;
297 }
298
299 mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
300 {
301 if (mDNS_LoggingEnabled)
302 {
303 LogInfo("%s", __func__);
304 LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
305 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
306 }
307
308 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
309
310 // Check to make sure we're not going to go past the end of the DNSMessage data
311 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
312 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
313
314 // Copy the LHS onto our fake wire packet
315 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
316 ptr += lhs_len - 1;
317
318 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
319 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
320
321 // two bytes of CLASS
322 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
323
324 // four bytes of TTL
325 ptr = putVal32(ptr, 120);
326
327 // Copy the RHS length into the RDLENGTH of our fake wire packet
328 ptr = putVal16(ptr, rhs_len);
329
330 // Copy the RHS onto our fake wire packet
331 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
332 ptr += rhs_len;
333
334 if (mDNS_LoggingEnabled)
335 {
336 LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
337 PrintHex(compression_lhs, ptr - compression_lhs);
338 }
339
340 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
341 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
342 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
343 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
344
345 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
346 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
347 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
348 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
349 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
350 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
351 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
352
353 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
354
355 return mStatus_NoError;
356 }
357
358 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
359 {
360 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
361 if (!ptr) return ptr;
362 *ptr = (qtype >> 8) & 0xff;
363 ptr += 1;
364 *ptr = qtype & 0xff;
365 ptr += 1;
366 *ptr = compression_packet_v1;
367 return ptr + 1;
368 }
369
370 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
371 {
372 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
373 }
374
375 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
376
377 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
378 {
379 mDNSu8 *end;
380 char buffer[49] = {0};
381 char *bufend = buffer + sizeof(buffer);
382
383 if (len > PRINT_DEBUG_BYTES_LIMIT)
384 {
385 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
386 len = PRINT_DEBUG_BYTES_LIMIT;
387 }
388 end = data + len;
389
390 while(data < end)
391 {
392 char *ptr = buffer;
393 for(; data < end && ptr < bufend-1; ptr+=3,data++)
394 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
395 LogInfo(" %s", buffer);
396 }
397 }
398
399 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
400 {
401 if (!mDNS_LoggingEnabled) return;
402
403 LogInfo("%s:", tag);
404 LogInfo(" LHS: (%d bytes)", lhs_len);
405 PrintHex(lhs, lhs_len);
406
407 if (!rhs) return;
408
409 LogInfo(" RHS: (%d bytes)", rhs_len);
410 PrintHex(rhs, rhs_len);
411 }
412
413 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
414 {
415 (void)m; // unused
416 if (result == mStatus_MemFree)
417 {
418 D2DRecordListElem **ptr = &D2DRecords;
419 D2DRecordListElem *tmp;
420 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
421 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
422 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
423 tmp = *ptr;
424 *ptr = (*ptr)->next;
425 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
426 mDNSPlatformMemFree(tmp);
427 }
428 }
429
430 mDNSexport void external_connection_release(const domainname *instance)
431 {
432 (void) instance;
433 D2DRecordListElem *ptr = D2DRecords;
434
435 for ( ; ptr ; ptr = ptr->next)
436 {
437 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
438 SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
439 {
440 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
441 ptr->instanceHandle, ptr->transportType);
442 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
443 }
444 }
445 }
446
447 mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
448 {
449 D2DRecordListElem *ptr = D2DRecords;
450 for ( ; ptr ; ptr = ptr->next)
451 {
452 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
453 {
454 mDNS_Deregister(&mDNSStorage, &ptr->ar);
455 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
456 }
457 }
458 }
459
460 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
461 {
462 D2DBrowseListElem **ptr = &D2DBrowseList;
463
464 for ( ; *ptr; ptr = &(*ptr)->next)
465 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
466 break;
467
468 return ptr;
469 }
470
471 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
472 {
473 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
474 return *ptr ? (*ptr)->refCount : 0;
475 }
476
477 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
478 {
479 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
480
481 if (!*ptr)
482 {
483 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
484 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
485 (*ptr)->type = type;
486 AssignDomainName(&(*ptr)->name, name);
487 }
488 (*ptr)->refCount += 1;
489
490 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
491 }
492
493 mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
494 {
495 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
496
497 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
498
499 (*ptr)->refCount -= 1;
500
501 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
502
503 if (!(*ptr)->refCount)
504 {
505 D2DBrowseListElem *tmp = *ptr;
506 *ptr = (*ptr)->next;
507 mDNSPlatformMemFree(tmp);
508 }
509 }
510
511 mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
512 {
513 if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
514 return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
515 else
516 return mStatus_Incompatible;
517 }
518
519 mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
520 {
521 if (result == kD2DSuccess)
522 {
523 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
524
525 mStatus err;
526 D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
527
528 if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
529
530 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
531 if (err)
532 {
533 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
534 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
535 mDNSPlatformMemFree(ptr);
536 return;
537 }
538 err = mDNS_Register(m, &ptr->ar);
539 if (err)
540 {
541 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
542 mDNSPlatformMemFree(ptr);
543 return;
544 }
545
546 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
547 ptr->instanceHandle = instanceHandle;
548 ptr->transportType = transportType;
549 ptr->next = D2DRecords;
550 D2DRecords = ptr;
551 }
552 else
553 LogMsg("xD2DAddToCache: Unexpected result %d", result);
554 }
555
556 mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
557 {
558 D2DRecordListElem *ptr = D2DRecords;
559 D2DRecordListElem *arptr;
560
561 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
562
563 arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
564 if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
565
566 if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
567 {
568 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
569 mDNSPlatformMemFree(arptr);
570 return NULL;
571 }
572
573 while (ptr)
574 {
575 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
576 ptr = ptr->next;
577 }
578
579 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
580 mDNSPlatformMemFree(arptr);
581 return ptr;
582 }
583
584 mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
585 {
586 (void)transportType; // We don't care about this, yet.
587 (void)instanceHandle; // We don't care about this, yet.
588
589 if (result == kD2DSuccess)
590 {
591 D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
592 if (ptr)
593 {
594 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
595 mDNS_Deregister(m, &ptr->ar);
596 }
597 }
598 else
599 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
600 }
601
602 mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
603 {
604 (void)m;
605 (void)key;
606 (void)keySize;
607 (void)value;
608 (void)valueSize;
609
610 if (result == kD2DSuccess)
611 {
612 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
613 if (D2DRetain) D2DRetain(instanceHandle, transportType);
614 }
615 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
616 }
617
618 mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
619 {
620 (void)m;
621 (void)instanceHandle;
622 (void)transportType;
623 (void)key;
624 (void)keySize;
625 (void)value;
626 (void)valueSize;
627
628 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
629 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
630 }
631
632 mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
633 {
634 (void)m;
635 (void)instanceHandle;
636 (void)transportType;
637 (void)key;
638 (void)keySize;
639 (void)value;
640 (void)valueSize;
641
642 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
643 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
644 }
645
646 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)
647 {
648 mDNS *m = (mDNS *) userData;
649 const char *eventString = "unknown";
650
651 KQueueLock(m);
652
653 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
654 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
655
656 switch (event)
657 {
658 case D2DServiceFound:
659 eventString = "D2DServiceFound";
660 break;
661 case D2DServiceLost:
662 eventString = "D2DServiceLost";
663 break;
664 case D2DServiceResolved:
665 eventString = "D2DServiceResolved";
666 break;
667 case D2DServiceRetained:
668 eventString = "D2DServiceRetained";
669 break;
670 case D2DServiceReleased:
671 eventString = "D2DServiceReleased";
672 break;
673 default:
674 break;
675 }
676
677 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);
678 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
679
680 switch (event)
681 {
682 case D2DServiceFound:
683 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
684 break;
685 case D2DServiceLost:
686 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
687 break;
688 case D2DServiceResolved:
689 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
690 break;
691 case D2DServiceRetained:
692 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
693 break;
694 case D2DServiceReleased:
695 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
696 break;
697 default:
698 break;
699 }
700
701 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
702 KQueueUnlock(m, "xD2DServiceCallback");
703 }
704
705 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
706 // should be called.
707 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
708 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
709 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
710
711 mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
712 {
713 NetworkInterfaceInfoOSX *info;
714
715 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
716 *excludedTransportType = D2DAWDLTransport;
717
718 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
719 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
720 {
721 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
722 *excludedTransportType = D2DTransportMax;
723 return D2DTransportMax;
724 }
725 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
726 else if (flags & kDNSServiceFlagsIncludeP2P)
727 {
728 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
729 return D2DTransportMax;
730 }
731 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
732 else if (flags & kDNSServiceFlagsIncludeAWDL)
733 {
734 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
735 return D2DAWDLTransport;
736 }
737
738 if (InterfaceID == mDNSInterface_P2P)
739 {
740 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
741 return D2DTransportMax;
742 }
743
744 // Compare to cached AWDL interface ID.
745 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
746 {
747 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
748 return D2DAWDLTransport;
749 }
750
751 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
752 if (info == NULL)
753 {
754 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
755 return D2DTransportMax;
756 }
757
758 // Recognize AirDrop specific p2p* interface based on interface name.
759 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
760 {
761 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
762 return D2DWifiPeerToPeerTransport;
763 }
764
765 // Currently there is no way to identify Bluetooth interface by name,
766 // since they use "en*" based name strings.
767
768 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
769 return D2DTransportMax;
770 }
771
772 mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
773 {
774 domainname lower;
775
776 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
777 {
778 LogInfo("external_start_browsing_for_service: ignoring address record");
779 return;
780 }
781
782 DomainnameToLower(typeDomain, &lower);
783
784 if (!D2DBrowseListRefCount(&lower, qtype))
785 {
786 D2DTransportType transportType, excludedTransport;
787
788 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
789 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
790 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
791
792 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
793 if (transportType == D2DTransportMax)
794 {
795 D2DTransportType i;
796 for (i = 0; i < D2DTransportMax; i++)
797 {
798 if (i == excludedTransport) continue;
799 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
800 }
801 }
802 else
803 {
804 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
805 }
806 }
807 D2DBrowseListRetain(&lower, qtype);
808 }
809
810 mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
811 {
812 domainname lower;
813
814 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
815 {
816 LogInfo("external_stop_browsing_for_service: ignoring address record");
817 return;
818 }
819
820 DomainnameToLower(typeDomain, &lower);
821
822 D2DBrowseListRelease(&lower, qtype);
823 if (!D2DBrowseListRefCount(&lower, qtype))
824 {
825 D2DTransportType transportType, excludedTransport;
826
827 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
828 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
829 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
830
831 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
832 if (transportType == D2DTransportMax)
833 {
834 D2DTransportType i;
835 for (i = 0; i < D2DTransportMax; i++)
836 {
837 if (i == excludedTransport) continue;
838 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
839 }
840 }
841 else
842 {
843 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
844 }
845
846 // The D2D driver may not generate the D2DServiceLost event for this key after
847 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
848 // record cache now.
849 xD2DClearCache(&lower, qtype);
850 }
851 }
852
853 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
854 {
855 domainname lower;
856 mDNSu8 *rhs = NULL;
857 mDNSu8 *end = NULL;
858 D2DTransportType transportType, excludedTransport;
859 DomainnameToLower(resourceRecord->name, &lower);
860
861 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
862 // For SRV records, update packet filter if p2p interface already exists, otherwise,
863 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
864 if (resourceRecord->rrtype == kDNSType_SRV)
865 mDNSUpdatePacketFilter(NULL);
866
867 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
868 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
869 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
870
871 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
872 if (transportType == D2DTransportMax)
873 {
874 D2DTransportType i;
875 for (i = 0; i < D2DTransportMax; i++)
876 {
877 if (i == excludedTransport) continue;
878 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
879 }
880 }
881 else
882 {
883 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
884 }
885 }
886
887 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
888 {
889 domainname lower;
890 mDNSu8 *rhs = NULL;
891 mDNSu8 *end = NULL;
892 D2DTransportType transportType, excludedTransport;
893 DomainnameToLower(resourceRecord->name, &lower);
894
895 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
896
897 // For SRV records, update packet filter to to remove this port from list
898 if (resourceRecord->rrtype == kDNSType_SRV)
899 mDNSUpdatePacketFilter(resourceRecord);
900
901 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
902 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
903 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
904
905 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
906 if (transportType == D2DTransportMax)
907 {
908 D2DTransportType i;
909 for (i = 0; i < D2DTransportMax; i++)
910 {
911 if (i == excludedTransport) continue;
912 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
913 }
914 }
915 else
916 {
917 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
918 }
919 }
920
921 mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
922 {
923 domainname lower;
924 mDNSu8 *rhs = NULL;
925 mDNSu8 *end = NULL;
926 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
927 D2DTransportType transportType, excludedTransport;
928 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
929
930 LogInfo("external_start_resolving_service: %##s", fqdn->c);
931 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
932 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
933 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
934
935 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
936 if (transportType == D2DTransportMax)
937 {
938 // Resolving over all the transports, except for excludedTransport if set.
939 D2DTransportType i;
940 for (i = 0; i < D2DTransportMax; i++)
941 {
942 if (i == excludedTransport) continue;
943 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
944
945 if (i == D2DAWDLTransport)
946 AWDL_used = true;
947 }
948 }
949 else
950 {
951 // Resolving over one specific transport.
952 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
953
954 if (transportType == D2DAWDLTransport)
955 AWDL_used = true;
956 }
957
958 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
959 // We only want these records going to AWDL, so use AWDLInterfaceID as the
960 // interface and don't set any other flags.
961 if (AWDL_used && AWDLInterfaceID)
962 {
963 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
964 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
965 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
966 }
967 }
968
969 mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
970 {
971 domainname lower;
972 mDNSu8 *rhs = NULL;
973 mDNSu8 *end = NULL;
974 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
975 D2DTransportType transportType, excludedTransport;
976 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
977
978 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
979 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
980 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
981 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
982
983 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
984 if (transportType == D2DTransportMax)
985 {
986 D2DTransportType i;
987 for (i = 0; i < D2DTransportMax; i++)
988 {
989 if (i == excludedTransport) continue;
990 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
991
992 if (i == D2DAWDLTransport)
993 AWDL_used = true;
994 }
995 }
996 else
997 {
998 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
999
1000 if (transportType == D2DAWDLTransport)
1001 AWDL_used = true;
1002 }
1003
1004 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1005 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1006 // interface and don't set any other flags.
1007 if (AWDL_used && AWDLInterfaceID)
1008 {
1009 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1010 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
1011 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
1012 }
1013 }
1014
1015 #elif APPLE_OSX_mDNSResponder
1016
1017 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;}
1018 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;}
1019 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1020 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1021 mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1022 mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1023
1024 #endif // ! NO_D2D
1025
1026 // ***************************************************************************
1027 // Functions
1028
1029 #if COMPILER_LIKES_PRAGMA_MARK
1030 #pragma mark -
1031 #pragma mark - Utility Functions
1032 #endif
1033
1034 // We only attempt to send and receive multicast packets on interfaces that are
1035 // (a) flagged as multicast-capable
1036 // (b) *not* flagged as point-to-point (e.g. modem)
1037 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1038 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1039 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1040 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1041
1042 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
1043 {
1044 static int notifyCount = 0;
1045 if (notifyCount) return;
1046
1047 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1048 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1049 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
1050
1051 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1052 #if !ForceAlerts
1053 {
1054 // Determine if we're at Apple (17.*.*.*)
1055 NetworkInterfaceInfoOSX *i;
1056 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1057 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1058 break;
1059 if (!i) return; // If not at Apple, don't show the alert
1060 }
1061 #endif
1062
1063 LogMsg("%s", title);
1064 LogMsg("%s", msg);
1065 // Display a notification to the user
1066 notifyCount++;
1067
1068 #ifndef NO_CFUSERNOTIFICATION
1069 mDNSNotify(title, msg);
1070 #endif /* NO_CFUSERNOTIFICATION */
1071 }
1072
1073 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
1074 mDNSlocal mDNSBool IsAppleTV(void)
1075 {
1076 #if TARGET_OS_EMBEDDED
1077 static mDNSBool sInitialized = mDNSfalse;
1078 static mDNSBool sIsAppleTV = mDNSfalse;
1079 CFStringRef deviceClass = NULL;
1080
1081 if(!sInitialized)
1082 {
1083 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
1084 if(deviceClass)
1085 {
1086 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
1087 sIsAppleTV = mDNStrue;
1088 CFRelease(deviceClass);
1089 }
1090 sInitialized = mDNStrue;
1091 }
1092 return(sIsAppleTV);
1093 #else
1094 return mDNSfalse;
1095 #endif // TARGET_OS_EMBEDDED
1096 }
1097
1098 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
1099 {
1100 static struct ifaddrs *ifa = NULL;
1101
1102 if (refresh && ifa)
1103 {
1104 freeifaddrs(ifa);
1105 ifa = NULL;
1106 }
1107
1108 if (ifa == NULL)
1109 getifaddrs(&ifa);
1110 return ifa;
1111 }
1112
1113 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
1114 {
1115 CFStringRef sckey = NULL;
1116 Boolean release_sckey = FALSE;
1117 CFDataRef bytes = NULL;
1118 CFPropertyListRef plist = NULL;
1119 SCDynamicStoreRef store = NULL;
1120
1121 switch ((enum mDNSDynamicStoreSetConfigKey)key)
1122 {
1123 case kmDNSMulticastConfig:
1124 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
1125 break;
1126 case kmDNSDynamicConfig:
1127 sckey = CFSTR("State:/Network/DynamicDNS");
1128 break;
1129 case kmDNSPrivateConfig:
1130 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
1131 break;
1132 case kmDNSBackToMyMacConfig:
1133 sckey = CFSTR("State:/Network/BackToMyMac");
1134 break;
1135 case kmDNSSleepProxyServersState:
1136 {
1137 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
1138 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
1139 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
1140 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
1141 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
1142 release_sckey = TRUE;
1143 CFRelease(tmp);
1144 break;
1145 }
1146 case kmDNSDebugState:
1147 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
1148 break;
1149 default:
1150 LogMsg("unrecognized key %d", key);
1151 goto fin;
1152 }
1153 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
1154 valueCnt, kCFAllocatorNull)))
1155 {
1156 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
1157 goto fin;
1158 }
1159 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
1160 kCFPropertyListImmutable, NULL)))
1161 {
1162 LogMsg("CFPropertyListCreateFromXMLData of bytes failed");
1163 goto fin;
1164 }
1165 CFRelease(bytes);
1166 bytes = NULL;
1167 if (NULL == (store = SCDynamicStoreCreate(NULL,
1168 CFSTR(kmDNSResponderServName), NULL, NULL)))
1169 {
1170 LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
1171 goto fin;
1172 }
1173 SCDynamicStoreSetValue(store, sckey, plist);
1174
1175 fin:
1176 if (NULL != bytes)
1177 CFRelease(bytes);
1178 if (NULL != plist)
1179 CFRelease(plist);
1180 if (NULL != store)
1181 CFRelease(store);
1182 if (release_sckey && sckey)
1183 CFRelease(sckey);
1184 }
1185
1186 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
1187 {
1188 CFPropertyListRef valueCopy;
1189 char *subkeyCopy = NULL;
1190 if (!value)
1191 return;
1192
1193 // We need to copy the key and value before we dispatch off the block below as the
1194 // caller will free the memory once we return from this function.
1195 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
1196 if (!valueCopy)
1197 {
1198 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
1199 return;
1200 }
1201 if (subkey)
1202 {
1203 int len = strlen(subkey);
1204 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
1205 if (!subkeyCopy)
1206 {
1207 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
1208 return;
1209 }
1210 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
1211 subkeyCopy[len] = 0;
1212 }
1213
1214 dispatch_async(DynamicStoreQueue, ^{
1215 CFWriteStreamRef stream = NULL;
1216 CFDataRef bytes = NULL;
1217 CFStringRef error;
1218 CFIndex ret;
1219
1220 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
1221 {
1222 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
1223 goto END;
1224 }
1225 CFWriteStreamOpen(stream);
1226 ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error);
1227 if (ret == 0)
1228 {
1229 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
1230 goto END;
1231 }
1232 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
1233 {
1234 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
1235 goto END;
1236 }
1237 CFWriteStreamClose(stream);
1238 CFRelease(stream);
1239 stream = NULL;
1240 LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy);
1241 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
1242
1243 END:
1244 CFRelease(valueCopy);
1245 if (NULL != stream)
1246 {
1247 CFWriteStreamClose(stream);
1248 CFRelease(stream);
1249 }
1250 if (NULL != bytes)
1251 CFRelease(bytes);
1252 if (subkeyCopy)
1253 mDNSPlatformMemFree(subkeyCopy);
1254 });
1255 }
1256
1257 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1258 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1259 {
1260 NetworkInterfaceInfoOSX *i;
1261 for (i = m->p->InterfaceList; i; i = i->next)
1262 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
1263 ((type == AF_UNSPEC ) ||
1264 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1265 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
1266 return(NULL);
1267 }
1268
1269 #if TARGET_OS_EMBEDDED
1270 mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void)
1271 {
1272 SCPreferencesRef smDNSManagedPrefs = NULL;
1273 smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID);
1274
1275 return (smDNSManagedPrefs);
1276 }
1277
1278 mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key)
1279 {
1280 mDNSBool val = mDNSfalse;
1281 CFBooleanRef val_cf = NULL;
1282
1283 if (prefs != NULL)
1284 {
1285 val_cf = SCPreferencesGetValue(prefs, key);
1286 if (isA_CFBoolean(val_cf) != NULL)
1287 val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed
1288 else
1289 val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled
1290 }
1291 else
1292 {
1293 LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!");
1294 val = mDNSfalse;
1295 }
1296 if (val_cf)
1297 CFRelease(val_cf);
1298 return (val);
1299 }
1300
1301 mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key)
1302 {
1303 SCPreferencesRef managed = NULL;
1304 mDNSBool ret_value;
1305
1306 managed = mDNSManagedPrefsGet();
1307 ret_value = GetmDNSManagedPrefKeyVal(managed, key);
1308
1309 if (managed)
1310 CFRelease(managed);
1311 return (ret_value);
1312 }
1313 #endif //TARGET_OS_EMBEDDED
1314
1315 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
1316 {
1317 struct ifaddrs *ifa;
1318 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1319 if (ifa->ifa_addr->sa_family == AF_LINK)
1320 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
1321 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1322 return -1;
1323 }
1324
1325 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
1326 {
1327 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
1328 NetworkInterfaceInfoOSX *i;
1329
1330 // Don't get tricked by inactive interfaces
1331 for (i = m->p->InterfaceList; i; i = i->next)
1332 if (i->Registered && i->scope_id == scope_id) return(i);
1333
1334 return mDNSNULL;
1335 }
1336
1337 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
1338 {
1339 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1340 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
1341 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
1342
1343 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1344 if (!ifi)
1345 {
1346 // Not found. Make sure our interface list is up to date, then try again.
1347 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
1348 mDNSMacOSXNetworkChanged(m);
1349 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1350 }
1351
1352 if (!ifi) return(mDNSNULL);
1353
1354 return(ifi->ifinfo.InterfaceID);
1355 }
1356
1357
1358 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
1359 {
1360 NetworkInterfaceInfoOSX *i;
1361 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1362 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
1363 if (id == mDNSInterface_Any ) return(0);
1364
1365 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
1366
1367 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
1368 for (i = m->p->InterfaceList; i; i = i->next)
1369 if (i->scope_id == scope_id) return(i->scope_id);
1370
1371 // If we are supposed to suppress network change, return "id" back
1372 if (suppressNetworkChange) return scope_id;
1373
1374 // Not found. Make sure our interface list is up to date, then try again.
1375 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
1376 mDNSMacOSXNetworkChanged(m);
1377 for (i = m->p->InterfaceList; i; i = i->next)
1378 if (i->scope_id == scope_id) return(i->scope_id);
1379
1380 return(0);
1381 }
1382
1383 #if APPLE_OSX_mDNSResponder
1384 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
1385 {
1386 if (iOSVers)
1387 return; // No ASL on iOS
1388
1389 static char buffer[512];
1390 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
1391
1392 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1393 if (uuid)
1394 {
1395 char uuidStr[37];
1396 uuid_unparse(*uuid, uuidStr);
1397 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
1398 }
1399
1400 static char domainBase[] = "com.apple.mDNSResponder.%s";
1401 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
1402 asl_set (asl_msg, "com.apple.message.domain", buffer);
1403
1404 if (result) asl_set(asl_msg, "com.apple.message.result", result);
1405 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
1406
1407 va_list ptr;
1408 va_start(ptr,fmt);
1409 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
1410 va_end(ptr);
1411
1412 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1413 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
1414 asl_set_filter(NULL, old_filter);
1415 asl_free(asl_msg);
1416 }
1417
1418
1419 mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
1420 {
1421 char buffer[16];
1422
1423 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1424
1425 // If we failed to allocate an aslmsg structure, keep accumulating
1426 // the statistics and try again at the next log interval.
1427 if (!aslmsg)
1428 {
1429 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
1430 return;
1431 }
1432
1433 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
1434
1435 if (m->rrcache_totalused_unicast)
1436 {
1437 mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
1438 }
1439 else
1440 {
1441 LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
1442 buffer[0] = 0;
1443 }
1444 asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
1445
1446 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
1447 asl_set(aslmsg,"com.apple.message.Latency0", buffer);
1448 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
1449 asl_set(aslmsg,"com.apple.message.Latency10", buffer);
1450 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
1451 asl_set(aslmsg,"com.apple.message.Latency20", buffer);
1452 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
1453 asl_set(aslmsg,"com.apple.message.Latency50", buffer);
1454 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
1455 asl_set(aslmsg,"com.apple.message.Latency100", buffer);
1456
1457 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
1458 asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
1459 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
1460 asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
1461 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
1462 asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
1463 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
1464 asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
1465
1466 // Ignore IndeterminateStatus as we don't log them
1467 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
1468 asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
1469 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
1470 asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
1471 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
1472 asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
1473 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
1474 asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
1475
1476 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
1477 asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
1478 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
1479 asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
1480 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
1481 asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
1482 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
1483 asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
1484
1485 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1486 asl_free(aslmsg);
1487 }
1488
1489 // Calculate packets per hour given total packet count and interval in seconds.
1490 // Cast one term of multiplication to (long) to use 64-bit arithmetic
1491 // and avoid a potential 32-bit overflow prior to the division.
1492 #define ONE_HOUR 3600
1493 #define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
1494
1495 // Put packet rate data in discrete buckets.
1496 mDNSlocal int mDNSBucketData(int inputData, int interval)
1497 {
1498 if (!interval)
1499 {
1500 LogMsg("mDNSBucketData: interval is zero!");
1501 return 0;
1502 }
1503
1504 int ratePerHour = PACKET_RATE(inputData, interval);
1505 int bucket;
1506
1507 if (ratePerHour == 0)
1508 bucket = 0;
1509 else if (ratePerHour <= 10)
1510 bucket = 10;
1511 else if (ratePerHour <= 100)
1512 bucket = 100;
1513 else if (ratePerHour <= 1000)
1514 bucket = 1000;
1515 else if (ratePerHour <= 5000)
1516 bucket = 5000;
1517 else if (ratePerHour <= 10000)
1518 bucket = 10000;
1519 else if (ratePerHour <= 50000)
1520 bucket = 50000;
1521 else if (ratePerHour <= 100000)
1522 bucket = 100000;
1523 else if (ratePerHour <= 250000)
1524 bucket = 250000;
1525 else if (ratePerHour <= 500000)
1526 bucket = 500000;
1527 else
1528 bucket = 1000000;
1529
1530 return bucket;
1531 }
1532
1533 mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
1534 {
1535 static mDNSs32 last_PktNum, last_MPktNum;
1536 static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
1537 static mDNSs32 last_RemoteSubnet;
1538
1539 mDNSs32 interval;
1540 char buffer[16];
1541 mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
1542 mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
1543 mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
1544 mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
1545 mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
1546
1547
1548 // save starting values for new interval
1549 last_PktNum = m->PktNum;
1550 last_MPktNum = m->MPktNum;
1551 last_UnicastPacketsSent = m->UnicastPacketsSent;
1552 last_MulticastPacketsSent = m->MulticastPacketsSent;
1553 last_RemoteSubnet = m->RemoteSubnet;
1554
1555 // Need a non-zero active time interval.
1556 if (!m->ActiveStatTime)
1557 return;
1558
1559 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
1560 interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
1561
1562 // Use a minimum of 30 minutes of awake time to calculate average packet rates.
1563 // The rounded awake interval should not be greater than the rounded reporting
1564 // interval.
1565 if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
1566 return;
1567
1568 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1569
1570 if (!aslmsg)
1571 {
1572 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
1573 return;
1574 }
1575 // log in MessageTracer format
1576 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
1577
1578 snprintf(buffer, sizeof(buffer), "%d", interval);
1579 asl_set(aslmsg,"com.apple.message.interval", buffer);
1580
1581 // log the packet rates as packets per hour
1582 snprintf(buffer, sizeof(buffer), "%d",
1583 mDNSBucketData(inUnicast, m->ActiveStatTime));
1584 asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
1585
1586 snprintf(buffer, sizeof(buffer), "%d",
1587 mDNSBucketData(inMulticast, m->ActiveStatTime));
1588 asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
1589
1590 snprintf(buffer, sizeof(buffer), "%d",
1591 mDNSBucketData(outUnicast, m->ActiveStatTime));
1592 asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
1593
1594 snprintf(buffer, sizeof(buffer), "%d",
1595 mDNSBucketData(outMulticast, m->ActiveStatTime));
1596 asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
1597
1598 snprintf(buffer, sizeof(buffer), "%d",
1599 mDNSBucketData(remoteSubnet, m->ActiveStatTime));
1600 asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
1601
1602 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1603
1604 asl_free(aslmsg);
1605 }
1606
1607 // Log multicast and unicast traffic statistics to MessageTracer on OSX
1608 mDNSexport void mDNSLogStatistics(mDNS *const m)
1609 {
1610 // MessageTracer only available on OSX
1611 if (iOSVers)
1612 return;
1613
1614 mDNSs32 currentUTC = mDNSPlatformUTC();
1615
1616 // log runtime statistics
1617 if ((currentUTC - m->NextStatLogTime) >= 0)
1618 {
1619 m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
1620 // If StatStartTime is zero, it hasn't been reinitialized yet
1621 // in the wakeup code path.
1622 if (m->StatStartTime)
1623 {
1624 m->ActiveStatTime += currentUTC - m->StatStartTime;
1625 }
1626
1627 // Only log statistics if we have recorded some active time during
1628 // this statistics interval.
1629 if (m->ActiveStatTime)
1630 {
1631 mDNSLogBonjourStatistics(m);
1632 mDNSLogDNSSECStatistics(m);
1633 }
1634
1635 // Start a new statistics gathering interval.
1636 m->StatStartTime = currentUTC;
1637 m->ActiveStatTime = 0;
1638 }
1639 }
1640
1641 #endif // APPLE_OSX_mDNSResponder
1642
1643 #if COMPILER_LIKES_PRAGMA_MARK
1644 #pragma mark -
1645 #pragma mark - UDP & TCP send & receive
1646 #endif
1647
1648 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1649 {
1650 mDNSBool result = mDNSfalse;
1651 SCNetworkConnectionFlags flags;
1652 CFDataRef remote_addr;
1653 CFMutableDictionaryRef options;
1654 SCNetworkReachabilityRef ReachRef = NULL;
1655
1656 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1657 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
1658 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
1659 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
1660 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
1661 CFRelease(options);
1662 CFRelease(remote_addr);
1663
1664 if (!ReachRef)
1665 {
1666 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
1667 goto end;
1668 }
1669 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
1670 {
1671 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
1672 goto end;
1673 }
1674 result = flags & kSCNetworkFlagsConnectionRequired;
1675
1676 end:
1677 if (ReachRef)
1678 CFRelease(ReachRef);
1679 return result;
1680 }
1681
1682 // Set traffic class for socket
1683 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
1684 {
1685 int traffic_class;
1686
1687 if (useBackgroundTrafficClass)
1688 traffic_class = SO_TC_BK_SYS;
1689 else
1690 traffic_class = SO_TC_CTL;
1691
1692 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
1693 }
1694
1695 mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
1696 {
1697 if (src)
1698 {
1699 int s;
1700
1701 if (dst->type == mDNSAddrType_IPv4)
1702 {
1703 s = src->ss.sktv4;
1704 }
1705 else
1706 {
1707 s = src->ss.sktv6;
1708 }
1709
1710 if (q->pid)
1711 {
1712 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
1713 {
1714 LogInfo("mDNSPlatformSetDelegatePID: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
1715 }
1716 }
1717 else
1718 {
1719 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
1720 {
1721 LogInfo("mDNSPlatformSetDelegatePID: Delegate UUID failed %s", strerror(errno));
1722 }
1723 }
1724 }
1725 }
1726
1727 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1728 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1729 // OR send via our primary v4 unicast socket
1730 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1731 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1732 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
1733 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1734 {
1735 NetworkInterfaceInfoOSX *info = mDNSNULL;
1736 struct sockaddr_storage to;
1737 int s = -1, err;
1738 mStatus result = mStatus_NoError;
1739
1740 if (InterfaceID)
1741 {
1742 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
1743 if (info == NULL)
1744 {
1745 // We may not have registered interfaces with the "core" as we may not have
1746 // seen any interface notifications yet. This typically happens during wakeup
1747 // where we might try to send DNS requests (non-SuppressUnusable questions internal
1748 // to mDNSResponder) before we receive network notifications.
1749 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
1750 return mStatus_BadParamErr;
1751 }
1752 }
1753
1754 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
1755
1756 if (dst->type == mDNSAddrType_IPv4)
1757 {
1758 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1759 sin_to->sin_len = sizeof(*sin_to);
1760 sin_to->sin_family = AF_INET;
1761 sin_to->sin_port = dstPort.NotAnInteger;
1762 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1763 s = (src ? src->ss : m->p->permanentsockets).sktv4;
1764
1765 if (info) // Specify outgoing interface
1766 {
1767 if (!mDNSAddrIsDNSMulticast(dst))
1768 {
1769 #ifdef IP_BOUND_IF
1770 if (info->scope_id == 0)
1771 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1772 else
1773 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1774 #else
1775 {
1776 static int displayed = 0;
1777 if (displayed < 1000)
1778 {
1779 displayed++;
1780 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1781 }
1782 }
1783 #endif
1784 }
1785 else
1786 #ifdef IP_MULTICAST_IFINDEX
1787 {
1788 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
1789 // We get an error when we compile on a machine that supports this option and run the binary on
1790 // a different machine that does not support it
1791 if (err < 0)
1792 {
1793 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
1794 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1795 if (err < 0 && !m->p->NetworkChanged)
1796 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1797 }
1798 }
1799 #else
1800 {
1801 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1802 if (err < 0 && !m->p->NetworkChanged)
1803 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1804
1805 }
1806 #endif
1807 }
1808 }
1809
1810 else if (dst->type == mDNSAddrType_IPv6)
1811 {
1812 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1813 sin6_to->sin6_len = sizeof(*sin6_to);
1814 sin6_to->sin6_family = AF_INET6;
1815 sin6_to->sin6_port = dstPort.NotAnInteger;
1816 sin6_to->sin6_flowinfo = 0;
1817 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1818 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1819 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1820 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1821 {
1822 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1823 if (err < 0)
1824 {
1825 char name[IFNAMSIZ];
1826 if (if_indextoname(info->scope_id, name) != NULL)
1827 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1828 else
1829 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
1830 }
1831 }
1832 }
1833
1834 else
1835 {
1836 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1837 #if ForceAlerts
1838 *(long*)0 = 0;
1839 #endif
1840 return mStatus_BadParamErr;
1841 }
1842
1843 if (s >= 0)
1844 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1845 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1846 else
1847 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1848 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1849
1850 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1851 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1852 if (s < 0) return(mStatus_Invalid);
1853
1854 // switch to background traffic class for this message if requested
1855 if (useBackgroundTrafficClass)
1856 setTrafficClass(s, useBackgroundTrafficClass);
1857
1858 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1859
1860 // set traffic class back to default value
1861 if (useBackgroundTrafficClass)
1862 setTrafficClass(s, mDNSfalse);
1863
1864 if (err < 0)
1865 {
1866 static int MessageCount = 0;
1867 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1868 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1869 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1870 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1871 // Don't report EHOSTUNREACH in the first three minutes after boot
1872 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1873 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1874 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1875 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1876 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1877 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1878 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1879 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1880 else
1881 {
1882 MessageCount++;
1883 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
1884 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",
1885 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1886 else // If logging is enabled, remove the cap and log aggressively
1887 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",
1888 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1889 }
1890
1891 result = mStatus_UnknownErr;
1892 }
1893
1894 #ifdef IP_BOUND_IF
1895 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1896 {
1897 static const mDNSu32 ifindex = 0;
1898 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1899 }
1900 #endif
1901
1902 return(result);
1903 }
1904
1905 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1906 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1907 {
1908 static unsigned int numLogMessages = 0;
1909 struct iovec databuffers = { (char *)buffer, max };
1910 struct msghdr msg;
1911 ssize_t n;
1912 struct cmsghdr *cmPtr;
1913 char ancillary[1024];
1914
1915 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1916
1917 // Set up the message
1918 msg.msg_name = (caddr_t)from;
1919 msg.msg_namelen = *fromlen;
1920 msg.msg_iov = &databuffers;
1921 msg.msg_iovlen = 1;
1922 msg.msg_control = (caddr_t)&ancillary;
1923 msg.msg_controllen = sizeof(ancillary);
1924 msg.msg_flags = 0;
1925
1926 // Receive the data
1927 n = recvmsg(s, &msg, 0);
1928 if (n<0)
1929 {
1930 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1931 return(-1);
1932 }
1933 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1934 {
1935 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
1936 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
1937 return(-1);
1938 }
1939 if (msg.msg_flags & MSG_CTRUNC)
1940 {
1941 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1942 return(-1);
1943 }
1944
1945 *fromlen = msg.msg_namelen;
1946
1947 // Parse each option out of the ancillary data.
1948 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1949 {
1950 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1951 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1952 {
1953 dstaddr->type = mDNSAddrType_IPv4;
1954 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1955 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1956 }
1957 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1958 {
1959 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1960 if (sdl->sdl_nlen < IF_NAMESIZE)
1961 {
1962 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1963 ifname[sdl->sdl_nlen] = 0;
1964 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1965 }
1966 }
1967 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1968 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1969 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1970 {
1971 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1972 dstaddr->type = mDNSAddrType_IPv6;
1973 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1974 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1975 }
1976 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1977 *ttl = *(int*)CMSG_DATA(cmPtr);
1978 }
1979
1980 return(n);
1981 }
1982
1983 mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
1984 {
1985 NetworkInterfaceInfo *intf;
1986
1987 if (addr->type == mDNSAddrType_IPv4)
1988 {
1989 for (intf = m->HostInterfaces; intf; intf = intf->next)
1990 {
1991 if (intf->ip.type == addr->type && intf->McastTxRx)
1992 {
1993 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
1994 {
1995 return(intf->InterfaceID);
1996 }
1997 }
1998 }
1999 }
2000
2001 if (addr->type == mDNSAddrType_IPv6)
2002 {
2003 for (intf = m->HostInterfaces; intf; intf = intf->next)
2004 {
2005 if (intf->ip.type == addr->type && intf->McastTxRx)
2006 {
2007 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
2008 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
2009 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
2010 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
2011 {
2012 return(intf->InterfaceID);
2013 }
2014 }
2015 }
2016 }
2017 return(mDNSInterface_Any);
2018 }
2019
2020 mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
2021 {
2022 // We should have a DNSMessage header followed by the question and an answer
2023 // which also includes a CNAME (that's when this function is called). To keep it
2024 // simple, we expect at least the size of DNSMessage header(12) and size of "A"
2025 // record (14 bytes).
2026 char buffer[26];
2027 int ret;
2028
2029 (void) m;
2030
2031 if (!src)
2032 return mDNSfalse;
2033
2034 ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK);
2035 if (ret > 0)
2036 return mDNStrue;
2037 else
2038 return mDNSfalse;
2039 }
2040
2041 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
2042 {
2043 KQSocketSet *const ss = (KQSocketSet *)context;
2044 mDNS *const m = ss->m;
2045 int err = 0, count = 0, closed = 0;
2046
2047 if (filter != EVFILT_READ)
2048 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
2049
2050 if (s1 != ss->sktv4 && s1 != ss->sktv6)
2051 {
2052 LogMsg("myKQSocketCallBack: native socket %d", s1);
2053 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
2054 }
2055
2056 while (!closed)
2057 {
2058 mDNSAddr senderAddr, destAddr;
2059 mDNSIPPort senderPort;
2060 struct sockaddr_storage from;
2061 size_t fromlen = sizeof(from);
2062 char packetifname[IF_NAMESIZE] = "";
2063 mDNSu8 ttl;
2064 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
2065 if (err < 0) break;
2066
2067 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
2068 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
2069
2070 count++;
2071 if (from.ss_family == AF_INET)
2072 {
2073 struct sockaddr_in *s = (struct sockaddr_in*)&from;
2074 senderAddr.type = mDNSAddrType_IPv4;
2075 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
2076 senderPort.NotAnInteger = s->sin_port;
2077 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2078 }
2079 else if (from.ss_family == AF_INET6)
2080 {
2081 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
2082 senderAddr.type = mDNSAddrType_IPv6;
2083 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
2084 senderPort.NotAnInteger = sin6->sin6_port;
2085 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2086 }
2087 else
2088 {
2089 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
2090 return;
2091 }
2092
2093 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
2094 mDNSInterfaceID InterfaceID = mDNSNULL;
2095 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
2096 while (intf)
2097 {
2098 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
2099 break;
2100 intf = intf->next;
2101 }
2102
2103 // When going to sleep we deregister all our interfaces, but if the machine
2104 // takes a few seconds to sleep we may continue to receive multicasts
2105 // during that time, which would confuse mDNSCoreReceive, because as far
2106 // as it's concerned, we should have no active interfaces any more.
2107 // Hence we ignore multicasts for which we can find no matching InterfaceID.
2108 if (intf)
2109 InterfaceID = intf->ifinfo.InterfaceID;
2110 else if (mDNSAddrIsDNSMulticast(&destAddr))
2111 continue;
2112
2113 if (!InterfaceID)
2114 {
2115 InterfaceID = FindMyInterface(m, &destAddr);
2116 }
2117
2118 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
2119 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
2120
2121 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
2122 // loop when that happens, or we may try to read from an invalid FD. We do this by
2123 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
2124 // if it closes the socketset.
2125 ss->closeFlag = &closed;
2126
2127 if (ss->proxy)
2128 {
2129 m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
2130 senderPort, &destAddr, ss->port, InterfaceID, NULL);
2131 }
2132 else
2133 {
2134 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
2135 }
2136
2137 // if we didn't close, we can safely dereference the socketset, and should to
2138 // reset the closeFlag, since it points to something on the stack
2139 if (!closed) ss->closeFlag = mDNSNULL;
2140 }
2141
2142 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
2143 {
2144 // Something is busted here.
2145 // kqueue says there is a packet, but myrecvfrom says there is not.
2146 // Try calling select() to get another opinion.
2147 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
2148 // All of this is racy, as data may have arrived after the call to select()
2149 static unsigned int numLogMessages = 0;
2150 int save_errno = errno;
2151 int so_error = -1;
2152 int so_nread = -1;
2153 int fionread = -1;
2154 socklen_t solen = sizeof(int);
2155 fd_set readfds;
2156 struct timeval timeout;
2157 int selectresult;
2158 FD_ZERO(&readfds);
2159 FD_SET(s1, &readfds);
2160 timeout.tv_sec = 0;
2161 timeout.tv_usec = 0;
2162 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
2163 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
2164 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
2165 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
2166 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
2167 if (ioctl(s1, FIONREAD, &fionread) == -1)
2168 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
2169 if (numLogMessages++ < 100)
2170 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
2171 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
2172 if (numLogMessages > 5)
2173 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
2174 "Congratulations, you've reproduced an elusive bug.\r"
2175 "Please contact the current assignee of <rdar://problem/3375328>.\r"
2176 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2177 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2178
2179 sleep(1); // After logging this error, rate limit so we don't flood syslog
2180 }
2181 }
2182
2183 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
2184 {
2185 mDNSBool c = !sock->connected;
2186 sock->connected = mDNStrue;
2187 sock->callback(sock, sock->context, c, sock->err);
2188 // Note: the callback may call CloseConnection here, which frees the context structure!
2189 }
2190
2191 #ifndef NO_SECURITYFRAMEWORK
2192
2193 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
2194 {
2195 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2196 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2197 if (ret >= 0) { *dataLength = ret; return(noErr); }
2198 *dataLength = 0;
2199 if (errno == EAGAIN ) return(errSSLWouldBlock);
2200 if (errno == ENOENT ) return(errSSLClosedGraceful);
2201 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
2202 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
2203 return(errSSLClosedAbort);
2204 }
2205
2206 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
2207 {
2208 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2209 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2210 if (ret > 0) { *dataLength = ret; return(noErr); }
2211 *dataLength = 0;
2212 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
2213 if ( errno == EAGAIN ) return(errSSLWouldBlock);
2214 if ( errno == ECONNRESET) return(errSSLClosedAbort);
2215 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
2216 return(errSSLClosedAbort);
2217 }
2218
2219 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
2220 {
2221 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
2222
2223 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
2224 if (!sock->tlsContext)
2225 {
2226 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
2227 return(mStatus_UnknownErr);
2228 }
2229
2230 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
2231 if (err)
2232 {
2233 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
2234 goto fail;
2235 }
2236
2237 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
2238 if (err)
2239 {
2240 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
2241 goto fail;
2242 }
2243
2244 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
2245 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
2246 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
2247 if (err)
2248 {
2249 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
2250 goto fail;
2251 }
2252
2253 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
2254 // (error not in OSStatus space) is okay.
2255 if (!sock->hostname.c[0])
2256 {
2257 LogMsg("ERROR: tlsSetupSock: hostname NULL");
2258 err = -1;
2259 goto fail;
2260 }
2261
2262 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
2263 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
2264 if (err)
2265 {
2266 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
2267 goto fail;
2268 }
2269
2270 return(err);
2271
2272 fail:
2273 if (sock->tlsContext)
2274 CFRelease(sock->tlsContext);
2275 return(err);
2276 }
2277
2278 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2279 mDNSlocal void doSSLHandshake(TCPSocket *sock)
2280 {
2281 mStatus err = SSLHandshake(sock->tlsContext);
2282
2283 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
2284 //defined, KQueueLock is a noop. Hence we need to serialize here
2285 //
2286 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
2287 //We need the rest of the logic also. Otherwise, we can enable the READ
2288 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
2289 //ConnFailed which means we are going to free the tcpInfo. While it
2290 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
2291 //and potentially call doTCPCallback with error which can close the fd and free the
2292 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
2293 //is already freed.
2294
2295 dispatch_async(dispatch_get_main_queue(), ^{
2296
2297 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2298
2299 if (sock->handshake == handshake_to_be_closed)
2300 {
2301 LogInfo("SSLHandshake completed after close");
2302 mDNSPlatformTCPCloseConnection(sock);
2303 }
2304 else
2305 {
2306 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2307 else LogMsg("doSSLHandshake: sock->fd is -1");
2308
2309 if (err == errSSLWouldBlock)
2310 sock->handshake = handshake_required;
2311 else
2312 {
2313 if (err)
2314 {
2315 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2316 CFRelease(sock->tlsContext);
2317 sock->tlsContext = NULL;
2318 }
2319
2320 sock->err = err ? mStatus_ConnFailed : 0;
2321 sock->handshake = handshake_completed;
2322
2323 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2324 doTcpSocketCallback(sock);
2325 }
2326 }
2327
2328 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2329 return;
2330 });
2331 }
2332 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2333 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
2334 {
2335 // Warning: Touching sock without the kqueue lock!
2336 // We're protected because sock->handshake == handshake_in_progress
2337 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
2338 mStatus err = SSLHandshake(sock->tlsContext);
2339
2340 KQueueLock(m);
2341 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2342
2343 if (sock->handshake == handshake_to_be_closed)
2344 {
2345 LogInfo("SSLHandshake completed after close");
2346 mDNSPlatformTCPCloseConnection(sock);
2347 }
2348 else
2349 {
2350 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2351 else LogMsg("doSSLHandshake: sock->fd is -1");
2352
2353 if (err == errSSLWouldBlock)
2354 sock->handshake = handshake_required;
2355 else
2356 {
2357 if (err)
2358 {
2359 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2360 CFRelease(sock->tlsContext);
2361 sock->tlsContext = NULL;
2362 }
2363
2364 sock->err = err ? mStatus_ConnFailed : 0;
2365 sock->handshake = handshake_completed;
2366
2367 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2368 doTcpSocketCallback(sock);
2369 }
2370 }
2371
2372 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2373 KQueueUnlock(m, "doSSLHandshake");
2374 return NULL;
2375 }
2376 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2377
2378 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
2379 {
2380 debugf("spawnSSLHandshake %p: entry", sock);
2381
2382 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
2383 sock->handshake = handshake_in_progress;
2384 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
2385
2386 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
2387 // to limit the number of threads used for SSLHandshake
2388 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
2389
2390 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
2391 }
2392
2393 #endif /* NO_SECURITYFRAMEWORK */
2394
2395 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
2396 {
2397 TCPSocket *sock = context;
2398 sock->err = mStatus_NoError;
2399
2400 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2401 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2402 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2403 if (filter == EVFILT_WRITE)
2404 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
2405
2406 if (sock->flags & kTCPSocketFlags_UseTLS)
2407 {
2408 #ifndef NO_SECURITYFRAMEWORK
2409 if (!sock->setup)
2410 {
2411 sock->setup = mDNStrue;
2412 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
2413 if (sock->err)
2414 {
2415 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
2416 return;
2417 }
2418 }
2419 if (sock->handshake == handshake_required)
2420 {
2421 spawnSSLHandshake(sock);
2422 return;
2423 }
2424 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
2425 {
2426 return;
2427 }
2428 else if (sock->handshake != handshake_completed)
2429 {
2430 if (!sock->err)
2431 sock->err = mStatus_UnknownErr;
2432 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
2433 }
2434 #else /* NO_SECURITYFRAMEWORK */
2435 sock->err = mStatus_UnsupportedErr;
2436 #endif /* NO_SECURITYFRAMEWORK */
2437 }
2438
2439 doTcpSocketCallback(sock);
2440 }
2441
2442 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2443 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
2444 {
2445 dispatch_queue_t queue = dispatch_get_main_queue();
2446 dispatch_source_t source;
2447 if (flags == EV_DELETE)
2448 {
2449 if (filter == EVFILT_READ)
2450 {
2451 dispatch_source_cancel(entryRef->readSource);
2452 dispatch_release(entryRef->readSource);
2453 entryRef->readSource = mDNSNULL;
2454 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
2455 }
2456 else if (filter == EVFILT_WRITE)
2457 {
2458 dispatch_source_cancel(entryRef->writeSource);
2459 dispatch_release(entryRef->writeSource);
2460 entryRef->writeSource = mDNSNULL;
2461 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
2462 }
2463 else
2464 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
2465 return 0;
2466 }
2467 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
2468
2469 if (filter == EVFILT_READ)
2470 {
2471 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
2472 }
2473 else if (filter == EVFILT_WRITE)
2474 {
2475 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
2476 }
2477 else
2478 {
2479 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
2480 return -1;
2481 }
2482 if (!source) return -1;
2483 dispatch_source_set_event_handler(source, ^{
2484
2485 mDNSs32 stime = mDNSPlatformRawTime();
2486 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
2487 mDNSs32 etime = mDNSPlatformRawTime();
2488 if (etime - stime >= WatchDogReportingThreshold)
2489 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
2490
2491 // Trigger the event delivery to the application. Even though we trigger the
2492 // event completion after handling every event source, these all will hopefully
2493 // get merged
2494 TriggerEventCompletion();
2495
2496 });
2497 dispatch_source_set_cancel_handler(source, ^{
2498 if (entryRef->fdClosed)
2499 {
2500 //LogMsg("CancelHandler: closing fd %d", fd);
2501 close(fd);
2502 }
2503 });
2504 dispatch_resume(source);
2505 if (filter == EVFILT_READ)
2506 entryRef->readSource = source;
2507 else
2508 entryRef->writeSource = source;
2509
2510 return 0;
2511 }
2512
2513 mDNSexport void KQueueLock(mDNS *const m)
2514 {
2515 (void)m; //unused
2516 }
2517 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
2518 {
2519 (void)m; //unused
2520 (void)task; //unused
2521 }
2522 #else
2523 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
2524 {
2525 struct kevent new_event;
2526 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
2527 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
2528 }
2529
2530 mDNSexport void KQueueLock(mDNS *const m)
2531 {
2532 pthread_mutex_lock(&m->p->BigMutex);
2533 m->p->BigMutexStartTime = mDNSPlatformRawTime();
2534 }
2535
2536 mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
2537 {
2538 mDNSs32 end = mDNSPlatformRawTime();
2539 (void)task;
2540 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
2541 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
2542
2543 pthread_mutex_unlock(&m->p->BigMutex);
2544
2545 char wake = 1;
2546 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
2547 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
2548 }
2549 #endif
2550
2551 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
2552 {
2553 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2554 (void) fd; //unused
2555 if (kq->readSource)
2556 {
2557 dispatch_source_cancel(kq->readSource);
2558 kq->readSource = mDNSNULL;
2559 }
2560 if (kq->writeSource)
2561 {
2562 dispatch_source_cancel(kq->writeSource);
2563 kq->writeSource = mDNSNULL;
2564 }
2565 // Close happens in the cancellation handler
2566 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
2567 kq->fdClosed = mDNStrue;
2568 #else
2569 (void)kq; //unused
2570 close(fd);
2571 #endif
2572 }
2573
2574 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2575 {
2576 KQSocketSet *cp = &sock->ss;
2577 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2578 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2579 const int on = 1; // "on" for setsockopt
2580 mStatus err;
2581
2582 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
2583 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2584
2585 // for TCP sockets, the traffic class is set once and not changed
2586 setTrafficClass(skt, useBackgroundTrafficClass);
2587
2588 if (sa_family == AF_INET)
2589 {
2590 // Bind it
2591 struct sockaddr_in addr;
2592 mDNSPlatformMemZero(&addr, sizeof(addr));
2593 addr.sin_family = AF_INET;
2594 addr.sin_port = port->NotAnInteger;
2595 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
2596 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
2597
2598 // Receive interface identifiers
2599 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2600 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
2601
2602 mDNSPlatformMemZero(&addr, sizeof(addr));
2603 socklen_t len = sizeof(addr);
2604 err = getsockname(skt, (struct sockaddr*) &addr, &len);
2605 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
2606
2607 port->NotAnInteger = addr.sin_port;
2608 }
2609 else
2610 {
2611 // Bind it
2612 struct sockaddr_in6 addr6;
2613 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2614 addr6.sin6_family = AF_INET6;
2615 addr6.sin6_port = port->NotAnInteger;
2616 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
2617 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
2618
2619 // We want to receive destination addresses and receive interface identifiers
2620 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
2621 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; }
2622
2623 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2624 socklen_t len = sizeof(addr6);
2625 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
2626 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
2627
2628 port->NotAnInteger = addr6.sin6_port;
2629
2630 }
2631 *s = skt;
2632 k->KQcallback = tcpKQSocketCallback;
2633 k->KQcontext = sock;
2634 k->KQtask = "mDNSPlatformTCPSocket";
2635 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2636 k->readSource = mDNSNULL;
2637 k->writeSource = mDNSNULL;
2638 k->fdClosed = mDNSfalse;
2639 #endif
2640 return mStatus_NoError;
2641 }
2642
2643 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2644 {
2645 mStatus err;
2646 (void) m;
2647
2648 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
2649 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
2650
2651 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
2652
2653 sock->ss.m = m;
2654 sock->ss.sktv4 = -1;
2655 sock->ss.sktv6 = -1;
2656 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
2657
2658 if (!err)
2659 {
2660 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
2661 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
2662 }
2663 if (err)
2664 {
2665 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
2666 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2667 return(mDNSNULL);
2668 }
2669 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
2670 sock->fd = sock->ss.sktv4;
2671 sock->callback = mDNSNULL;
2672 sock->flags = flags;
2673 sock->context = mDNSNULL;
2674 sock->setup = mDNSfalse;
2675 sock->connected = mDNSfalse;
2676 sock->handshake = handshake_required;
2677 sock->m = m;
2678 sock->err = mStatus_NoError;
2679
2680 return sock;
2681 }
2682
2683 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
2684 {
2685 KQSocketSet *cp = &sock->ss;
2686 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
2687 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
2688 mStatus err = mStatus_NoError;
2689 struct sockaddr_storage ss;
2690
2691 sock->callback = callback;
2692 sock->context = context;
2693 sock->setup = mDNSfalse;
2694 sock->connected = mDNSfalse;
2695 sock->handshake = handshake_required;
2696 sock->err = mStatus_NoError;
2697
2698 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
2699
2700 if (dst->type == mDNSAddrType_IPv4)
2701 {
2702 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
2703 mDNSPlatformMemZero(saddr, sizeof(*saddr));
2704 saddr->sin_family = AF_INET;
2705 saddr->sin_port = dstport.NotAnInteger;
2706 saddr->sin_len = sizeof(*saddr);
2707 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
2708 }
2709 else
2710 {
2711 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
2712 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
2713 saddr6->sin6_family = AF_INET6;
2714 saddr6->sin6_port = dstport.NotAnInteger;
2715 saddr6->sin6_len = sizeof(*saddr6);
2716 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
2717 }
2718
2719 // Watch for connect complete (write is ready)
2720 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2721 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
2722 {
2723 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2724 return errno;
2725 }
2726
2727 // Watch for incoming data
2728 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
2729 {
2730 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2731 return errno;
2732 }
2733
2734 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2735 {
2736 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
2737 return mStatus_UnknownErr;
2738 }
2739
2740 // We bind to the interface and all subsequent packets including the SYN will be sent out
2741 // on this interface
2742 //
2743 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
2744 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
2745 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
2746 {
2747 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
2748 if (dst->type == mDNSAddrType_IPv4)
2749 {
2750 #ifdef IP_BOUND_IF
2751 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2752 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2753 #else
2754 (void)InterfaceID; // Unused
2755 (void)info; // Unused
2756 #endif
2757 }
2758 else
2759 {
2760 #ifdef IPV6_BOUND_IF
2761 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2762 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2763 #else
2764 (void)InterfaceID; // Unused
2765 (void)info; // Unused
2766 #endif
2767 }
2768 }
2769
2770 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
2771 // from which we can infer the destination address family. Hence we need to remember that here.
2772 // Instead of remembering the address family, we remember the right fd.
2773 sock->fd = *s;
2774 sock->kqEntry = k;
2775 // initiate connection wth peer
2776 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
2777 {
2778 if (errno == EINPROGRESS) return mStatus_ConnPending;
2779 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2780 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2781 else
2782 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
2783 return mStatus_ConnFailed;
2784 }
2785
2786 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2787 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2788 return err;
2789 }
2790
2791 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2792 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
2793 {
2794 mStatus err = mStatus_NoError;
2795
2796 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
2797 if (!sock) return(mDNSNULL);
2798
2799 mDNSPlatformMemZero(sock, sizeof(*sock));
2800 sock->fd = fd;
2801 sock->flags = flags;
2802
2803 if (flags & kTCPSocketFlags_UseTLS)
2804 {
2805 #ifndef NO_SECURITYFRAMEWORK
2806 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
2807
2808 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
2809 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
2810
2811 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
2812 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
2813 #else
2814 err = mStatus_UnsupportedErr;
2815 #endif /* NO_SECURITYFRAMEWORK */
2816 }
2817 #ifndef NO_SECURITYFRAMEWORK
2818 exit:
2819 #endif
2820
2821 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
2822 return(sock);
2823 }
2824
2825 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
2826 {
2827 mDNSu16 port;
2828
2829 port = -1;
2830 if (sock)
2831 {
2832 port = sock->ss.port.NotAnInteger;
2833 }
2834 return port;
2835 }
2836
2837 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2838 {
2839 if (ss->sktv4 != -1)
2840 {
2841 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
2842 ss->sktv4 = -1;
2843 }
2844 if (ss->sktv6 != -1)
2845 {
2846 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
2847 ss->sktv6 = -1;
2848 }
2849 if (ss->closeFlag) *ss->closeFlag = 1;
2850 }
2851
2852 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2853 {
2854 if (sock)
2855 {
2856 #ifndef NO_SECURITYFRAMEWORK
2857 if (sock->tlsContext)
2858 {
2859 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2860 {
2861 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2862 // When we come back from SSLHandshake, we will notice that a close was here and
2863 // call this function again which will do the cleanup then.
2864 sock->handshake = handshake_to_be_closed;
2865 return;
2866 }
2867
2868 SSLClose(sock->tlsContext);
2869 CFRelease(sock->tlsContext);
2870 sock->tlsContext = NULL;
2871 }
2872 #endif /* NO_SECURITYFRAMEWORK */
2873 if (sock->ss.sktv4 != -1)
2874 shutdown(sock->ss.sktv4, 2);
2875 if (sock->ss.sktv6 != -1)
2876 shutdown(sock->ss.sktv6, 2);
2877 CloseSocketSet(&sock->ss);
2878 sock->fd = -1;
2879
2880 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2881 }
2882 }
2883
2884 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2885 {
2886 ssize_t nread = 0;
2887 *closed = mDNSfalse;
2888
2889 if (sock->flags & kTCPSocketFlags_UseTLS)
2890 {
2891 #ifndef NO_SECURITYFRAMEWORK
2892 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2893 else if (sock->handshake == handshake_in_progress) return 0;
2894 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2895
2896 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2897 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
2898 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2899 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2900 else if (err && err != errSSLWouldBlock)
2901 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2902 #else
2903 nread = -1;
2904 *closed = mDNStrue;
2905 #endif /* NO_SECURITYFRAMEWORK */
2906 }
2907 else
2908 {
2909 static int CLOSEDcount = 0;
2910 static int EAGAINcount = 0;
2911 nread = recv(sock->fd, buf, buflen, 0);
2912
2913 if (nread > 0)
2914 {
2915 CLOSEDcount = 0;
2916 EAGAINcount = 0;
2917 } // On success, clear our error counters
2918 else if (nread == 0)
2919 {
2920 *closed = mDNStrue;
2921 if ((++CLOSEDcount % 1000) == 0)
2922 {
2923 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
2924 assert(CLOSEDcount < 1000);
2925 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
2926 // crash mDNSResponder using assert() and restart fresh. See advantages below:
2927 // 1.Better User Experience
2928 // 2.CrashLogs frequency can be monitored
2929 // 3.StackTrace can be used for more info
2930 }
2931 }
2932 // else nread is negative -- see what kind of error we got
2933 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
2934 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
2935 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2936 {
2937 nread = 0;
2938 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
2939 }
2940 }
2941
2942 return nread;
2943 }
2944
2945 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2946 {
2947 int nsent;
2948
2949 if (sock->flags & kTCPSocketFlags_UseTLS)
2950 {
2951 #ifndef NO_SECURITYFRAMEWORK
2952 size_t processed;
2953 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2954 if (sock->handshake == handshake_in_progress) return 0;
2955 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2956
2957 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2958
2959 if (!err) nsent = (int) processed;
2960 else if (err == errSSLWouldBlock) nsent = 0;
2961 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2962 #else
2963 nsent = -1;
2964 #endif /* NO_SECURITYFRAMEWORK */
2965 }
2966 else
2967 {
2968 nsent = send(sock->fd, msg, len, 0);
2969 if (nsent < 0)
2970 {
2971 if (errno == EAGAIN) nsent = 0;
2972 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
2973 }
2974 }
2975
2976 return nsent;
2977 }
2978
2979 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
2980 {
2981 return sock->fd;
2982 }
2983
2984 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2985 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2986 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
2987 {
2988 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2989 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2990 const int on = 1;
2991 const int twofivefive = 255;
2992 mStatus err = mStatus_NoError;
2993 char *errstr = mDNSNULL;
2994 const int mtu = 0;
2995
2996 cp->closeFlag = mDNSNULL;
2997
2998 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
2999 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
3000
3001 // set default traffic class
3002 setTrafficClass(skt, mDNSfalse);
3003
3004 #ifdef SO_RECV_ANYIF
3005 // Enable inbound packets on IFEF_AWDL interface.
3006 // Only done for multicast sockets, since we don't expect unicast socket operations
3007 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
3008 if (mDNSSameIPPort(port, MulticastDNSPort))
3009 {
3010 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
3011 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
3012 }
3013 #endif // SO_RECV_ANYIF
3014
3015 // ... with a shared UDP port, if it's for multicast receiving
3016 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
3017 {
3018 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
3019 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
3020 }
3021
3022 if (sa_family == AF_INET)
3023 {
3024 // We want to receive destination addresses
3025 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
3026 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
3027
3028 // We want to receive interface identifiers
3029 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
3030 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
3031
3032 // We want to receive packet TTL value so we can check it
3033 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
3034 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
3035
3036 // Send unicast packets with TTL 255
3037 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
3038 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
3039
3040 // And multicast packets with TTL 255 too
3041 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
3042 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
3043
3044 // And start listening for packets
3045 struct sockaddr_in listening_sockaddr;
3046 listening_sockaddr.sin_family = AF_INET;
3047 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3048 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
3049 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
3050 if (err) { errstr = "bind"; goto fail; }
3051 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
3052 }
3053 else if (sa_family == AF_INET6)
3054 {
3055 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
3056 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; }
3057
3058 // We want to receive destination addresses and receive interface identifiers
3059 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
3060 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
3061
3062 // We want to receive packet hop count value so we can check it
3063 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
3064 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
3065
3066 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
3067 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
3068 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
3069 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
3070
3071 // Send unicast packets with TTL 255
3072 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
3073 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
3074
3075 // And multicast packets with TTL 255 too
3076 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
3077 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
3078
3079 // Want to receive our own packets
3080 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
3081 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
3082
3083 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
3084 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
3085 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
3086 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
3087 skt, err, errno, strerror(errno));
3088
3089 // And start listening for packets
3090 struct sockaddr_in6 listening_sockaddr6;
3091 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
3092 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
3093 listening_sockaddr6.sin6_family = AF_INET6;
3094 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3095 listening_sockaddr6.sin6_flowinfo = 0;
3096 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
3097 listening_sockaddr6.sin6_scope_id = 0;
3098 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
3099 if (err) { errstr = "bind"; goto fail; }
3100 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
3101 }
3102
3103 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
3104 fcntl(skt, F_SETFD, 1); // set close-on-exec
3105 *s = skt;
3106 k->KQcallback = myKQSocketCallBack;
3107 k->KQcontext = cp;
3108 k->KQtask = "UDP packet reception";
3109 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3110 k->readSource = mDNSNULL;
3111 k->writeSource = mDNSNULL;
3112 k->fdClosed = mDNSfalse;
3113 #endif
3114 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
3115
3116 return(err);
3117
3118 fail:
3119 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
3120 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
3121 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
3122
3123 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
3124 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
3125 {
3126 err = EADDRINUSE;
3127 if (mDNSSameIPPort(port, MulticastDNSPort))
3128 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
3129 "Congratulations, you've reproduced an elusive bug.\r"
3130 "Please contact the current assignee of <rdar://problem/3814904>.\r"
3131 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
3132 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
3133 }
3134
3135 mDNSPlatformCloseFD(k, skt);
3136 return(err);
3137 }
3138
3139 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
3140 {
3141 mStatus err;
3142 mDNSIPPort port = requestedport;
3143 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
3144 int i = 10000; // Try at most 10000 times to get a unique random port
3145 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
3146 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
3147 mDNSPlatformMemZero(p, sizeof(UDPSocket));
3148 p->ss.port = zeroIPPort;
3149 p->ss.m = m;
3150 p->ss.sktv4 = -1;
3151 p->ss.sktv6 = -1;
3152 p->ss.proxy = mDNSfalse;
3153
3154 do
3155 {
3156 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
3157 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
3158 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
3159 if (!err)
3160 {
3161 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
3162 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
3163 }
3164 i--;
3165 } while (err == EADDRINUSE && randomizePort && i);
3166
3167 if (err)
3168 {
3169 // In customer builds we don't want to log failures with port 5351, because this is a known issue
3170 // of failing to bind to this port when Internet Sharing has already bound to it
3171 // We also don't want to log about port 5350, due to a known bug when some other
3172 // process is bound to it.
3173 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
3174 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3175 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3176 freeL("UDPSocket", p);
3177 return(mDNSNULL);
3178 }
3179 return(p);
3180 }
3181
3182 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
3183 {
3184 CloseSocketSet(&sock->ss);
3185 freeL("UDPSocket", sock);
3186 }
3187
3188 #if COMPILER_LIKES_PRAGMA_MARK
3189 #pragma mark -
3190 #pragma mark - BPF Raw packet sending/receiving
3191 #endif
3192
3193 #if APPLE_OSX_mDNSResponder
3194
3195 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
3196 {
3197 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
3198 NetworkInterfaceInfoOSX *info;
3199
3200 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
3201 if (info == NULL)
3202 {
3203 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
3204 return;
3205 }
3206 if (info->BPF_fd < 0)
3207 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
3208 else
3209 {
3210 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
3211 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
3212 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
3213 }
3214 }
3215
3216 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
3217 {
3218 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
3219 NetworkInterfaceInfoOSX *info;
3220 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
3221 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
3222 // Manually inject an entry into our local ARP cache.
3223 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
3224 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL))
3225 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3226 else
3227 {
3228 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
3229 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
3230 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3231 }
3232 }
3233
3234 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
3235 {
3236 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
3237 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3238 // close will happen in the cancel handler
3239 dispatch_source_cancel(i->BPF_source);
3240 #else
3241
3242 // Note: MUST NOT close() the underlying native BSD sockets.
3243 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
3244 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
3245 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3246 CFRelease(i->BPF_rls);
3247 CFSocketInvalidate(i->BPF_cfs);
3248 CFRelease(i->BPF_cfs);
3249 #endif
3250 i->BPF_fd = -1;
3251 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
3252 }
3253
3254 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
3255 {
3256 KQueueLock(info->m);
3257
3258 // 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
3259 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
3260 if (info->BPF_fd < 0) goto exit;
3261
3262 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
3263 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
3264 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
3265 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
3266
3267 if (n<0)
3268 {
3269 /* <rdar://problem/10287386>
3270 * sometimes there can be a race condition btw when the bpf socket
3271 * gets data and the callback get scheduled and when we call BIOCSETF (which
3272 * clears the socket). this can cause the read to hang for a really long time
3273 * and effectively prevent us from responding to requests for long periods of time.
3274 * to prevent this make the socket non blocking and just bail if we dont get anything
3275 */
3276 if (errno == EAGAIN)
3277 {
3278 LogMsg("bpf_callback got EAGAIN bailing");
3279 goto exit;
3280 }
3281 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
3282 CloseBPF(info);
3283 goto exit;
3284 }
3285
3286 while (ptr < end)
3287 {
3288 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
3289 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
3290 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
3291 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
3292 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
3293 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
3294 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
3295 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
3296 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
3297 }
3298 exit:
3299 KQueueUnlock(info->m, "bpf_callback");
3300 }
3301 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3302 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
3303 {
3304 bpf_callback_common(info);
3305 }
3306 #else
3307 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
3308 {
3309 (void)cfs;
3310 (void)CallBackType;
3311 (void)address;
3312 (void)data;
3313 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
3314 }
3315 #endif
3316
3317 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
3318 {
3319 LogMsg("mDNSPlatformSendKeepalive called\n");
3320 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
3321 }
3322
3323 mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
3324 {
3325 SCDynamicStoreRef store = NULL;
3326 CFStringRef entityname = NULL;
3327
3328 if ((store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ClearSPSMACAddress"), NULL, NULL)))
3329 {
3330 if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
3331 {
3332 if (SCDynamicStoreRemoveValue(store, entityname) == false)
3333 LogMsg("mDNSPlatformClearSPSMACAddr: Unable to remove key");
3334 }
3335 }
3336
3337 if (entityname) CFRelease(entityname);
3338 if (store) CFRelease(store);
3339 return KERN_SUCCESS;
3340 }
3341
3342 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
3343 {
3344 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3345 LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
3346 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
3347 return KERN_SUCCESS;
3348 }
3349
3350 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
3351 {
3352 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3353
3354 mDNSGetRemoteMAC(m, family, raddr->ip.v6.b);
3355 return KERN_SUCCESS;
3356 }
3357
3358 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
3359 {
3360 mDNSs32 intfid;
3361 mDNSs32 error = 0;
3362 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3363
3364 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);
3365 if (error != KERN_SUCCESS)
3366 {
3367 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
3368 return error;
3369 }
3370 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
3371 return error;
3372 }
3373
3374 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
3375
3376 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
3377 {
3378 int numv4 = 0, numv6 = 0;
3379 AuthRecord *rr;
3380
3381 for (rr = m->ResourceRecords; rr; rr=rr->next)
3382 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3383 {
3384 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
3385 numv4++;
3386 }
3387
3388 for (rr = m->ResourceRecords; rr; rr=rr->next)
3389 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3390 {
3391 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
3392 numv6++;
3393 }
3394
3395 if (p4) *p4 = numv4;
3396 if (p6) *p6 = numv6;
3397 return(numv4 + numv6);
3398 }
3399
3400 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
3401 {
3402 NetworkInterfaceInfoOSX *x;
3403
3404 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3405 for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
3406
3407 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
3408
3409 #define MAX_BPF_ADDRS 250
3410 int numv4 = 0, numv6 = 0;
3411
3412 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
3413 {
3414 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
3415 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
3416 numv6 = MAX_BPF_ADDRS - numv4;
3417 }
3418
3419 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
3420
3421 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3422 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3423 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
3424 {
3425 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
3426
3427 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
3428 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
3429
3430 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3431
3432 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
3433 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
3434 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3435 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
3436
3437 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3438 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
3439 };
3440
3441 struct bpf_insn *pc = &filter[9];
3442 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
3443 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
3444 struct bpf_insn *ret4 = fail + 1;
3445 struct bpf_insn *ret6 = ret4 + 4;
3446
3447 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
3448
3449 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
3450
3451 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
3452 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)
3453 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
3454 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3455
3456 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3457
3458 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
3459 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
3460
3461 // BPF Byte-Order Note
3462 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3463 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3464 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3465 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3466 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3467 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3468 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3469 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3470 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3471 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3472
3473 // IPSEC capture size notes:
3474 // 8 bytes UDP header
3475 // 4 bytes Non-ESP Marker
3476 // 28 bytes IKE Header
3477 // --
3478 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3479
3480 AuthRecord *rr;
3481 for (rr = m->ResourceRecords; rr; rr=rr->next)
3482 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3483 {
3484 mDNSv4Addr a = rr->AddressProxy.ip.v4;
3485 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3486 BPF_SetOffset(pc, jt, ret4);
3487 pc->jf = 0;
3488 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];
3489 pc++;
3490 }
3491 *pc++ = rf;
3492
3493 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
3494 *pc++ = g6; // chk6 points here
3495
3496 // First cancel any previous ND group memberships we had, then create a fresh socket
3497 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
3498 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
3499
3500 for (rr = m->ResourceRecords; rr; rr=rr->next)
3501 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3502 {
3503 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
3504 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3505 BPF_SetOffset(pc, jt, ret6);
3506 pc->jf = 0;
3507 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];
3508 pc++;
3509
3510 struct ipv6_mreq i6mr;
3511 i6mr.ipv6mr_interface = x->scope_id;
3512 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
3513 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
3514 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
3515 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
3516
3517 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
3518 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
3519 if (err < 0 && (errno != EADDRNOTAVAIL))
3520 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3521
3522 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
3523 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
3524 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3525
3526 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
3527 }
3528
3529 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
3530 *pc++ = rf; // fail points here
3531
3532 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
3533 *pc++ = r4a; // ret4 points here
3534 *pc++ = r4b;
3535 *pc++ = r4c;
3536 *pc++ = r4d;
3537
3538 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
3539 *pc++ = r6a; // ret6 points here
3540
3541 struct bpf_program prog = { pc - filter, filter };
3542
3543 #if 0
3544 // For debugging BPF filter program
3545 unsigned int q;
3546 for (q=0; q<prog.bf_len; q++)
3547 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);
3548 #endif
3549
3550 if (!numv4 && !numv6)
3551 {
3552 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
3553 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
3554 // Schedule check to see if we can close this BPF_fd now
3555 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
3556 // prog.bf_len = 0; This seems to panic the kernel
3557 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
3558 }
3559
3560 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
3561 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
3562 }
3563
3564 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
3565 {
3566 mDNS_Lock(m);
3567
3568 NetworkInterfaceInfoOSX *i;
3569 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
3570 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
3571 else
3572 {
3573 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
3574
3575 struct bpf_version v;
3576 if (ioctl(fd, BIOCVERSION, &v) < 0)
3577 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3578 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
3579 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
3580 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
3581
3582 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
3583 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3584
3585 if (i->BPF_len > sizeof(m->imsg))
3586 {
3587 i->BPF_len = sizeof(m->imsg);
3588 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
3589 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3590 else
3591 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
3592 }
3593
3594 static const u_int opt_one = 1;
3595 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
3596 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3597
3598 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
3599 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3600
3601 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
3602 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3603
3604 /* <rdar://problem/10287386>
3605 * make socket non blocking see comments in bpf_callback_common for more info
3606 */
3607 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
3608 {
3609 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3610 }
3611
3612 struct ifreq ifr;
3613 mDNSPlatformMemZero(&ifr, sizeof(ifr));
3614 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3615 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
3616 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
3617 else
3618 {
3619 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3620 i->BPF_fd = fd;
3621 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
3622 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
3623 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
3624 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
3625 dispatch_resume(i->BPF_source);
3626 #else
3627 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
3628 i->BPF_fd = fd;
3629 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
3630 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
3631 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3632 #endif
3633 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
3634 }
3635 }
3636
3637 mDNS_Unlock(m);
3638 }
3639
3640 #endif // APPLE_OSX_mDNSResponder
3641
3642 #if COMPILER_LIKES_PRAGMA_MARK
3643 #pragma mark -
3644 #pragma mark - Key Management
3645 #endif
3646
3647 #ifndef NO_SECURITYFRAMEWORK
3648 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
3649 {
3650 CFMutableArrayRef certChain = NULL;
3651 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
3652 SecCertificateRef cert;
3653 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
3654 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
3655 else
3656 {
3657 SecPolicySearchRef searchRef;
3658 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
3659 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
3660 else
3661 {
3662 SecPolicyRef policy;
3663 err = SecPolicySearchCopyNext(searchRef, &policy);
3664 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
3665 else
3666 {
3667 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
3668 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
3669 else
3670 {
3671 SecTrustRef trust;
3672 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
3673 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
3674 else
3675 {
3676 err = SecTrustEvaluate(trust, NULL);
3677 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
3678 else
3679 {
3680 CFArrayRef rawCertChain;
3681 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3682 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3683 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
3684 else
3685 {
3686 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3687 if (!certChain) LogMsg("getCertChain: certChain is NULL");
3688 else
3689 {
3690 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3691 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3692 CFArraySetValueAtIndex(certChain, 0, identity);
3693 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3694 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3695 }
3696 CFRelease(rawCertChain);
3697 // Do not free statusChain:
3698 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3699 // certChain: Call the CFRelease function to release this object when you are finished with it.
3700 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3701 }
3702 }
3703 CFRelease(trust);
3704 }
3705 CFRelease(wrappedCert);
3706 }
3707 CFRelease(policy);
3708 }
3709 CFRelease(searchRef);
3710 }
3711 CFRelease(cert);
3712 }
3713 return certChain;
3714 }
3715 #endif /* NO_SECURITYFRAMEWORK */
3716
3717 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3718 {
3719 #ifdef NO_SECURITYFRAMEWORK
3720 return mStatus_UnsupportedErr;
3721 #else
3722 SecIdentityRef identity = nil;
3723 SecIdentitySearchRef srchRef = nil;
3724 OSStatus err;
3725
3726 // search for "any" identity matching specified key use
3727 // In this app, we expect there to be exactly one
3728 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3729 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3730
3731 err = SecIdentitySearchCopyNext(srchRef, &identity);
3732 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3733
3734 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3735 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3736
3737 // Found one. Call getCertChain to create the correct certificate chain.
3738 ServerCerts = GetCertChain(identity);
3739 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
3740
3741 return mStatus_NoError;
3742 #endif /* NO_SECURITYFRAMEWORK */
3743 }
3744
3745 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3746 {
3747 #ifndef NO_SECURITYFRAMEWORK
3748 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3749 #endif /* NO_SECURITYFRAMEWORK */
3750 }
3751
3752 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3753 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3754 {
3755 CFStringEncoding encoding = kCFStringEncodingUTF8;
3756 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3757 if (cfs)
3758 {
3759 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3760 CFRelease(cfs);
3761 }
3762 }
3763
3764 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3765 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3766 {
3767 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3768 if (cfs)
3769 {
3770 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3771 CFRelease(cfs);
3772 }
3773 }
3774
3775 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3776 {
3777 mDNSs32 val;
3778 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3779 if (!state) return mDNSfalse;
3780 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3781 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3782 return val ? mDNStrue : mDNSfalse;
3783 }
3784
3785 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3786 {
3787 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3788
3789 if (sa->sa_family == AF_INET)
3790 {
3791 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3792 ip->type = mDNSAddrType_IPv4;
3793 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3794 return(mStatus_NoError);
3795 }
3796
3797 if (sa->sa_family == AF_INET6)
3798 {
3799 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3800 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3801 // value into the second word of the IPv6 link-local address, so they can just
3802 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3803 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3804 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3805 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3806 ip->type = mDNSAddrType_IPv6;
3807 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3808 return(mStatus_NoError);
3809 }
3810
3811 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3812 return(mStatus_Invalid);
3813 }
3814
3815 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3816 {
3817 mDNSEthAddr eth = zeroEthAddr;
3818 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
3819 if (!store)
3820 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3821 else
3822 {
3823 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3824 if (entityname)
3825 {
3826 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
3827 if (dict)
3828 {
3829 CFRange range = { 0, 6 }; // Offset, length
3830 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3831 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
3832 CFRelease(dict);
3833 }
3834 CFRelease(entityname);
3835 }
3836 CFRelease(store);
3837 }
3838 return(eth);
3839 }
3840
3841 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3842 {
3843 struct ifaddrs *ifa;
3844 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3845 if (ifa->ifa_addr->sa_family == AF_LINK)
3846 {
3847 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3848 if (sdl->sdl_index == ifindex)
3849 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3850 }
3851 *eth = zeroEthAddr;
3852 return -1;
3853 }
3854
3855 #ifndef SIOCGIFWAKEFLAGS
3856 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3857 #endif
3858
3859 #ifndef IF_WAKE_ON_MAGIC_PACKET
3860 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3861 #endif
3862
3863 #ifndef ifr_wake_flags
3864 #define ifr_wake_flags ifr_ifru.ifru_intval
3865 #endif
3866
3867 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3868 {
3869 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3870 if (!service)
3871 {
3872 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3873 return mDNSfalse;
3874 }
3875
3876 io_name_t n1, n2;
3877 IOObjectGetClass(service, n1);
3878 io_object_t parent;
3879 mDNSBool ret = mDNSfalse;
3880 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3881 if (kr == KERN_SUCCESS)
3882 {
3883 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3884 IOObjectGetClass(parent, n2);
3885 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
3886 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3887 if (!ref)
3888 {
3889 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
3890 ret = mDNSfalse;
3891 }
3892 else
3893 {
3894 ret = mDNStrue;
3895 CFRelease(ref);
3896 }
3897 IOObjectRelease(parent);
3898 CFRelease(keystr);
3899 }
3900 else
3901 {
3902 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3903 ret = mDNSfalse;
3904 }
3905 IOObjectRelease(service);
3906 return ret;
3907 }
3908
3909
3910 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3911 {
3912 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3913 }
3914
3915 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3916 {
3917 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
3918 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
3919
3920 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3921 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3922 // when the power source is not AC Power.
3923 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3924 {
3925 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3926 return mDNStrue;
3927 }
3928
3929 int s = socket(AF_INET, SOCK_DGRAM, 0);
3930 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3931
3932 struct ifreq ifr;
3933 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3934 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3935 {
3936 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3937 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3938 // error code is being returned from the kernel, we need to use the kernel version.
3939 #define KERNEL_EOPNOTSUPP 102
3940 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3941 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
3942 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3943 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3944 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3945 }
3946
3947 close(s);
3948
3949 // 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
3950
3951 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3952
3953 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3954 }
3955
3956 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3957 {
3958 int sockFD;
3959 struct ifreq ifr;
3960
3961 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3962 if (sockFD < 0)
3963 {
3964 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3965 return 0;
3966 }
3967
3968 ifr.ifr_addr.sa_family = AF_INET;
3969 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3970
3971 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3972 {
3973 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3974 ifr.ifr_eflags = 0;
3975 }
3976 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
3977
3978 close(sockFD);
3979 return ifr.ifr_eflags;
3980 }
3981
3982 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3983 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3984 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3985 // (e.g. sa_family not AF_INET or AF_INET6)
3986 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
3987 {
3988 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3989 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3990 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3991
3992 mDNSAddr ip, mask;
3993 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3994 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3995
3996 NetworkInterfaceInfoOSX **p;
3997 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3998 if (scope_id == (*p)->scope_id &&
3999 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
4000 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
4001 {
4002 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);
4003 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
4004 // When interfaces are created with same MAC address, kernel resurrects the old interface.
4005 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
4006 // we get the corresponding name for the interface index on which the packet was received and check against
4007 // the InterfaceList for a matching name. So, keep the name in sync
4008 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
4009 (*p)->Exists = mDNStrue;
4010 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
4011 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
4012
4013 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
4014 // we may need to start or stop or sleep proxy browse operation
4015 const mDNSBool NetWake = NetWakeInterface(*p);
4016 if ((*p)->ifinfo.NetWake != NetWake)
4017 {
4018 (*p)->ifinfo.NetWake = NetWake;
4019 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
4020 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
4021 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
4022 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
4023 if ((*p)->Registered)
4024 {
4025 mDNS_Lock(m);
4026 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
4027 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
4028 mDNS_Unlock(m);
4029 }
4030 }
4031 // Reset the flag if it has changed this time.
4032 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4033
4034 return(*p);
4035 }
4036
4037 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
4038 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
4039 if (!i) return(mDNSNULL);
4040 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
4041 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
4042 i->ifinfo.ip = ip;
4043 i->ifinfo.mask = mask;
4044 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
4045 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
4046 // We can be configured to disable multicast advertisement, but we want to to support
4047 // local-only services, which need a loopback address record.
4048 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
4049 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
4050 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
4051 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4052 i->ifinfo.DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse;
4053
4054 i->next = mDNSNULL;
4055 i->m = m;
4056 i->Exists = mDNStrue;
4057 i->Flashing = mDNSfalse;
4058 i->Occulting = mDNSfalse;
4059 i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
4060 if (eflags & IFEF_AWDL)
4061 {
4062 AWDLInterfaceID = i->ifinfo.InterfaceID;
4063 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
4064 }
4065 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
4066 i->LastSeen = utc;
4067 i->ifa_flags = ifa->ifa_flags;
4068 i->scope_id = scope_id;
4069 i->BSSID = bssid;
4070 i->sa_family = ifa->ifa_addr->sa_family;
4071 i->BPF_fd = -1;
4072 i->BPF_mcfd = -1;
4073 i->BPF_len = 0;
4074 i->Registered = mDNSNULL;
4075
4076 // Do this AFTER i->BSSID has been set up
4077 i->ifinfo.NetWake = NetWakeInterface(i);
4078 GetMAC(&i->ifinfo.MAC, scope_id);
4079 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
4080 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
4081
4082 *p = i;
4083 return(i);
4084 }
4085
4086 #if APPLE_OSX_mDNSResponder
4087
4088 #if COMPILER_LIKES_PRAGMA_MARK
4089 #pragma mark -
4090 #pragma mark - AutoTunnel
4091 #endif
4092
4093 #define kRacoonPort 4500
4094
4095 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
4096
4097 #ifndef NO_SECURITYFRAMEWORK
4098
4099 static CFMutableDictionaryRef domainStatusDict = NULL;
4100
4101 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
4102 {
4103 if (q->LongLived)
4104 {
4105 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
4106 return mStatus_NoSuchRecord;
4107 else if (q->state == LLQ_Poll)
4108 return mStatus_PollingMode;
4109 else if (q->state != LLQ_Established && !q->DuplicateOf)
4110 return mStatus_TransientErr;
4111 }
4112
4113 return mStatus_NoError;
4114 }
4115
4116 mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4117 {
4118 mStatus status = mStatus_NoError;
4119 DNSQuestion* q, *worst_q = mDNSNULL;
4120 for (q = m->Questions; q; q=q->next)
4121 if (q->AuthInfo == info)
4122 {
4123 mStatus newStatus = CheckQuestionForStatus(q);
4124 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
4125 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
4126 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
4127 }
4128
4129 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
4130 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
4131 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
4132 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
4133 return status;
4134 }
4135
4136 mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4137 {
4138 AuthRecord *r;
4139
4140 if (info->deltime) return mStatus_NoError;
4141 for (r = m->ResourceRecords; r; r = r->next)
4142 {
4143 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
4144 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
4145 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
4146 // has already checked
4147 const domainname *n = r->resrec.name;
4148 while (n->c[0])
4149 {
4150 DomainAuthInfo *ptr;
4151 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
4152 if (SameDomainName(&ptr->domain, n))
4153 {
4154 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
4155 {
4156 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
4157 return r->updateError;
4158 }
4159 }
4160 n = (const domainname *)(n->c + 1 + n->c[0]);
4161 }
4162 }
4163 return mStatus_NoError;
4164 }
4165
4166 #endif // ndef NO_SECURITYFRAMEWORK
4167
4168 // MUST be called with lock held
4169 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
4170 {
4171 #ifdef NO_SECURITYFRAMEWORK
4172 (void) m;
4173 (void)info;
4174 #else
4175 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
4176 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
4177 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
4178 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
4179 char buffer[1024];
4180 mDNSu32 buflen = 0;
4181 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4182 CFStringRef domain = NULL;
4183 CFStringRef tmp = NULL;
4184 CFNumberRef num = NULL;
4185 mStatus status = mStatus_NoError;
4186 mStatus llqStatus = mStatus_NoError;
4187 char llqBuffer[1024];
4188
4189 mDNS_CheckLock(m);
4190
4191 if (!domainStatusDict)
4192 {
4193 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4194 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
4195 }
4196
4197 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
4198
4199 buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
4200 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4201 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
4202
4203 if (info->deltime)
4204 {
4205 if (CFDictionaryContainsKey(domainStatusDict, domain))
4206 {
4207 CFDictionaryRemoveValue(domainStatusDict, domain);
4208 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4209 }
4210 CFRelease(domain);
4211 CFRelease(dict);
4212
4213 return;
4214 }
4215
4216 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
4217 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4218 if (!tmp)
4219 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
4220 else
4221 {
4222 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
4223 CFRelease(tmp);
4224 }
4225
4226 if (llq)
4227 {
4228 mDNSu32 port = mDNSVal16(llq->ExternalPort);
4229
4230 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4231 if (!num)
4232 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
4233 else
4234 {
4235 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
4236 CFRelease(num);
4237 }
4238
4239 if (llq->Result)
4240 {
4241 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
4242 if (!num)
4243 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
4244 else
4245 {
4246 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
4247 CFRelease(num);
4248 }
4249 }
4250 }
4251
4252 if (tun)
4253 {
4254 mDNSu32 port = mDNSVal16(tun->ExternalPort);
4255
4256 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4257 if (!num)
4258 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
4259 else
4260 {
4261 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
4262 CFRelease(num);
4263 }
4264
4265 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
4266 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4267 if (!tmp)
4268 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
4269 else
4270 {
4271 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
4272 CFRelease(tmp);
4273 }
4274
4275 if (tun->Result)
4276 {
4277 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
4278 if (!num)
4279 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
4280 else
4281 {
4282 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
4283 CFRelease(num);
4284 }
4285 }
4286 }
4287 if (tun || llq)
4288 {
4289 mDNSu32 code = m->LastNATMapResultCode;
4290
4291 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
4292 if (!num)
4293 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
4294 else
4295 {
4296 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
4297 CFRelease(num);
4298 }
4299 }
4300
4301 mDNS_snprintf(buffer, sizeof(buffer), "Success");
4302 llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
4303 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
4304
4305 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
4306 // reported so that it can be fixed automatically (or the user needs to be notified)
4307 if (status != mStatus_NoError)
4308 {
4309 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
4310 }
4311 else if (m->Router.type == mDNSAddrType_None)
4312 {
4313 status = mStatus_NoRouter;
4314 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
4315 }
4316 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
4317 {
4318 status = mStatus_NoRouter;
4319 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
4320 }
4321 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
4322 {
4323 status = mStatus_ServiceNotRunning;
4324 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
4325 }
4326 else if (!llq && !tun)
4327 {
4328 status = mStatus_NotInitializedErr;
4329 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4330 }
4331 else if (llqStatus == mStatus_NoSuchRecord)
4332 {
4333 status = llqStatus;
4334 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4335 }
4336 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
4337 {
4338 status = mStatus_DoubleNAT;
4339 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
4340 }
4341 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
4342 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
4343 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
4344 {
4345 status = mStatus_NATPortMappingDisabled;
4346 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
4347 }
4348 else if ((llq && llq->Result) || (tun && tun->Result))
4349 {
4350 status = mStatus_NATTraversal;
4351 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
4352 }
4353 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
4354 {
4355 status = mStatus_NATTraversal;
4356 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
4357 }
4358 else
4359 {
4360 status = llqStatus;
4361 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4362 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
4363 }
4364
4365 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
4366 if (!num)
4367 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
4368 else
4369 {
4370 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
4371 CFRelease(num);
4372 }
4373
4374 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4375 if (!tmp)
4376 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
4377 else
4378 {
4379 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
4380 CFRelease(tmp);
4381 }
4382
4383 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
4384 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
4385 {
4386 CFDictionarySetValue(domainStatusDict, domain, dict);
4387 if (!m->ShutdownTime)
4388 {
4389 static char statusBuf[16];
4390 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
4391 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
4392 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4393 }
4394 }
4395
4396 CFRelease(domain);
4397 CFRelease(dict);
4398
4399 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
4400 #endif // def NO_SECURITYFRAMEWORK
4401 }
4402
4403 // MUST be called with lock held
4404 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
4405 {
4406 #ifdef NO_SECURITYFRAMEWORK
4407 (void) m;
4408 #else
4409 mDNS_CheckLock(m);
4410 DomainAuthInfo* info;
4411 for (info = m->AuthInfoList; info; info = info->next)
4412 if (info->AutoTunnel && !info->deltime)
4413 UpdateAutoTunnelDomainStatus(m, info);
4414 #endif // def NO_SECURITYFRAMEWORK
4415 }
4416
4417 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
4418 {
4419 DomainAuthInfo *info;
4420
4421 for (info = m->AuthInfoList; info; info = info->next)
4422 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
4423 break;
4424
4425 if (info != AnonymousRacoonConfig)
4426 {
4427 AnonymousRacoonConfig = info;
4428 // Create or revert configuration file, and start (or SIGHUP) Racoon
4429 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
4430 }
4431 }
4432
4433 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
4434
4435 // Caller must hold the lock
4436 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
4437 {
4438 mDNS_CheckLock(m);
4439
4440 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4441
4442 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4443 {
4444 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4445 if (err)
4446 {
4447 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4448 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4449 return mDNSfalse;
4450 }
4451 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4452 }
4453 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4454
4455 return mDNStrue;
4456 }
4457
4458 // Caller must hold the lock
4459 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4460 {
4461 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4462 {
4463 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4464 m->NextSRVUpdate = NonZeroTime(m->timenow);
4465 }
4466 }
4467
4468 // Caller must hold the lock
4469 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4470 {
4471 mStatus err;
4472 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4473
4474 mDNS_CheckLock(m);
4475
4476 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4477 {
4478 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4479 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4480 DeregisterAutoTunnelHostRecord(m, info);
4481 }
4482 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4483 {
4484 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4485 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4486 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4487 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4488 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4489 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4490 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4491
4492 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4493 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4494 else
4495 {
4496 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4497 m->NextSRVUpdate = NonZeroTime(m->timenow);
4498 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4499 }
4500 }
4501 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4502 }
4503
4504 // Caller must hold the lock
4505 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4506 {
4507 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4508
4509 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4510 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4511 UpdateAutoTunnelHostRecord(m, info);
4512 }
4513
4514 // Caller must hold the lock
4515 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4516 {
4517 mDNS_CheckLock(m);
4518
4519 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4520 {
4521 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);
4522 DeregisterAutoTunnelServiceRecords(m, info);
4523 }
4524 else
4525 {
4526 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4527 {
4528 // 1. Set up our address record for the external tunnel address
4529 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4530 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4531 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4532 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4533 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4534 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4535 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4536 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4537
4538 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4539 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4540 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4541 }
4542 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4543
4544 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4545 {
4546 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4547 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4548 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4549 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4550 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4551 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4552 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4553 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4554 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4555 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4556 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4557
4558 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4559 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4560 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4561 }
4562 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4563
4564 UpdateAutoTunnelHostRecord(m, info);
4565
4566 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4567 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4568 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4569
4570 }
4571 }
4572
4573 // Caller must hold the lock
4574 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4575 {
4576 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4577 }
4578
4579 // Caller must hold the lock
4580 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4581 {
4582 mDNS_CheckLock(m);
4583
4584 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4585 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4586 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4587 {
4588 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4589 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4590
4591 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4592 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4593
4594 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4595 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4596 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4597 }
4598 else
4599 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4600 }
4601
4602 // Caller must hold the lock
4603 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4604 {
4605 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4606
4607 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4608 UpdateAutoTunnelHostRecord(m, info);
4609 UpdateAutoTunnelDomainStatus(m, info);
4610 }
4611
4612 // Caller must hold the lock
4613 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4614 {
4615 mDNS_CheckLock(m);
4616
4617 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4618 DeregisterAutoTunnel6Record(m, info);
4619 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4620 {
4621 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4622 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4623 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4624 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4625 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4626 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4627 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4628
4629 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4630 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4631 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4632
4633 UpdateAutoTunnelHostRecord(m, info);
4634
4635 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4636 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4637 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4638
4639 }
4640 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4641 }
4642
4643 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4644 {
4645 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4646 if (result == mStatus_MemFree)
4647 {
4648 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4649
4650 mDNS_Lock(m);
4651
4652 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4653 if (rr == &info->AutoTunnelHostRecord)
4654 {
4655 rr->namestorage.c[0] = 0;
4656 m->NextSRVUpdate = NonZeroTime(m->timenow);
4657 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4658 }
4659 if (m->ShutdownTime)
4660 {
4661 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4662 mDNS_Unlock(m);
4663 return;
4664 }
4665 if (rr == &info->AutoTunnelHostRecord)
4666 {
4667 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4668 UpdateAutoTunnelHostRecord(m,info);
4669 }
4670 else if (rr == &info->AutoTunnelDeviceInfo)
4671 {
4672 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4673 UpdateAutoTunnelDeviceInfoRecord(m,info);
4674 }
4675 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4676 {
4677 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4678 UpdateAutoTunnelServiceRecords(m,info);
4679 }
4680 else if (rr == &info->AutoTunnel6Record)
4681 {
4682 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4683 UpdateAutoTunnel6Record(m,info);
4684 }
4685
4686 mDNS_Unlock(m);
4687 }
4688 }
4689
4690 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4691 {
4692 DomainAuthInfo *info;
4693
4694 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4695 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4696
4697 mDNS_Lock(m);
4698
4699 m->NextSRVUpdate = NonZeroTime(m->timenow);
4700 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4701
4702 for (info = m->AuthInfoList; info; info = info->next)
4703 if (info->AutoTunnel)
4704 UpdateAutoTunnelServiceRecords(m, info);
4705
4706 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4707
4708 UpdateAutoTunnelDomainStatuses(m);
4709
4710 mDNS_Unlock(m);
4711 }
4712
4713 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4714 {
4715 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4716
4717 mDNS_Lock(m);
4718 // We forcibly deregister the records that are based on the hostname.
4719 // When deregistration of each completes, the MemFree callback will make the
4720 // appropriate Update* call to use the new name to reregister.
4721 DeregisterAutoTunnelHostRecord(m, info);
4722 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4723 DeregisterAutoTunnelServiceRecords(m, info);
4724 DeregisterAutoTunnel6Record(m, info);
4725 m->NextSRVUpdate = NonZeroTime(m->timenow);
4726 mDNS_Unlock(m);
4727 }
4728
4729 // Must be called with the lock held
4730 mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
4731 {
4732 if (info->deltime) return;
4733
4734 if (info->AutoTunnelServiceStarted)
4735 {
4736 // On wake from sleep, this function will be called when determining SRV targets,
4737 // and needs to re-register the host record for the target to be set correctly
4738 UpdateAutoTunnelHostRecord(m, info);
4739 return;
4740 }
4741
4742 info->AutoTunnelServiceStarted = mDNStrue;
4743
4744 // Now that we have a service in this domain, we need to try to register the
4745 // AutoTunnel records, because the relay connection & NAT-T may have already been
4746 // started for another domain. If the relay connection is not up or the NAT-T has not
4747 // yet succeeded, the Update* functions are smart enough to not register the records.
4748 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4749 // decide whether to register the AutoTunnel records in the calls below.
4750 UpdateAutoTunnelServiceRecords(m, info);
4751 UpdateAutoTunnel6Record(m, info);
4752 UpdateAutoTunnelDeviceInfoRecord(m, info);
4753 UpdateAutoTunnelHostRecord(m, info);
4754
4755 // If the global AutoTunnel NAT-T is not yet started, start it.
4756 if (!m->AutoTunnelNAT.clientContext)
4757 {
4758 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4759 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4760 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4761 m->AutoTunnelNAT.IntPort = IPSECPort;
4762 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4763 m->AutoTunnelNAT.NATLease = 0;
4764 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4765 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4766 }
4767 }
4768
4769 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4770 {
4771 mDNSv6Addr loc_outer6;
4772 mDNSv6Addr rmt_outer6;
4773
4774 // When we are tunneling over IPv6 Relay address, the port number is zero
4775 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4776 {
4777 loc_outer6 = tun->loc_outer6;
4778 rmt_outer6 = tun->rmt_outer6;
4779 }
4780 else
4781 {
4782 loc_outer6 = zerov6Addr;
4783 loc_outer6.b[0] = tun->loc_outer.b[0];
4784 loc_outer6.b[1] = tun->loc_outer.b[1];
4785 loc_outer6.b[2] = tun->loc_outer.b[2];
4786 loc_outer6.b[3] = tun->loc_outer.b[3];
4787
4788 rmt_outer6 = zerov6Addr;
4789 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4790 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4791 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4792 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4793 }
4794
4795 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)));
4796 }
4797
4798 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4799 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4800
4801 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
4802 {
4803 DNSQuestion *q = m->Questions;
4804 while (q)
4805 {
4806 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4807 {
4808 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4809 mDNSQuestionCallback *tmp = q->QuestionCallback;
4810 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4811 mDNS_StopQuery(m, q);
4812 mDNS_StartQuery(m, q);
4813 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4814 if (!success) q->NoAnswer = NoAnswer_Fail;
4815 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4816 // In general we have to assume that the question list might have changed in arbitrary ways.
4817 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4818 // already in use. The safest solution is just to go back to the start of the list and start again.
4819 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4820 // just one suspended question, so it's really a 2n algorithm.
4821 q = m->Questions;
4822 }
4823 else
4824 q = q->next;
4825 }
4826 }
4827
4828 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
4829 {
4830 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4831 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4832 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4833 // 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.
4834 // 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.
4835 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
4836 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
4837 }
4838
4839 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
4840 {
4841 ClientTunnel **p = &m->TunnelClients;
4842 while (*p != tun && *p) p = &(*p)->next;
4843 if (*p) *p = tun->next;
4844 ReissueBlockedQuestions(m, &tun->dstname, success);
4845 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4846 freeL("ClientTunnel", tun);
4847 }
4848
4849 mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4850 {
4851 ClientTunnel **p;
4852 mDNSBool needSetKeys = mDNStrue;
4853
4854 p = &tun->next;
4855 while (*p)
4856 {
4857 // Is this a tunnel to the same host that we are trying to setup now?
4858 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4859 else
4860 {
4861 ClientTunnel *old = *p;
4862 if (v6Tunnel)
4863 {
4864 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4865 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4866 if (old->q.ThisQInterval >= 0)
4867 {
4868 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4869 mDNS_StopQuery(m, &old->q);
4870 }
4871 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4872 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4873 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4874 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4875 {
4876 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4877 // the other parameters of the tunnel are different
4878 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4879 AutoTunnelSetKeys(old, mDNSfalse);
4880 }
4881 else
4882 {
4883 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4884 // as "tun" and "old" are identical
4885 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4886 &old->rmt_inner);
4887 needSetKeys = mDNSfalse;
4888 }
4889 }
4890 else
4891 {
4892 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4893 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4894 if (old->q.ThisQInterval >= 0)
4895 {
4896 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4897 mDNS_StopQuery(m, &old->q);
4898 }
4899 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4900 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4901 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4902 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4903 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4904 {
4905 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4906 // the other parameters of the tunnel are different
4907 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4908 AutoTunnelSetKeys(old, mDNSfalse);
4909 }
4910 else
4911 {
4912 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4913 // as "tun" and "old" are identical
4914 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4915 &old->rmt_inner);
4916 needSetKeys = mDNSfalse;
4917 }
4918 }
4919
4920 *p = old->next;
4921 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4922 freeL("ClientTunnel", old);
4923 }
4924 }
4925 return needSetKeys;
4926 }
4927
4928 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4929 // tunnel will be deleted
4930 mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4931 {
4932 ClientTunnel **p;
4933
4934 p = &tun->next;
4935 while (*p)
4936 {
4937 // If there is more than one client tunnel to the same host, delete all of them.
4938 // We do this by just checking against the EUI64 rather than the full address
4939 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4940 else
4941 {
4942 ClientTunnel *old = *p;
4943 if (v6Tunnel)
4944 {
4945 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4946 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4947 }
4948 else
4949 {
4950 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4951 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4952 }
4953 if (old->q.ThisQInterval >= 0)
4954 {
4955 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4956 mDNS_StopQuery(m, &old->q);
4957 }
4958 else
4959 {
4960 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4961 AutoTunnelSetKeys(old, mDNSfalse);
4962 }
4963 *p = old->next;
4964 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4965 freeL("ClientTunnel", old);
4966 }
4967 }
4968 }
4969
4970 mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
4971 {
4972 mDNSBool needSetKeys = mDNStrue;
4973 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4974 mDNSBool v6Tunnel = mDNSfalse;
4975 DomainAuthInfo *info;
4976
4977 // If the port is zero, then we have a relay address of the peer
4978 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4979 v6Tunnel = mDNStrue;
4980
4981 if (v6Tunnel)
4982 {
4983 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4984 tun->rmt_outer6 = answer->rdata->u.ipv6;
4985 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4986 }
4987 else
4988 {
4989 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4990 tun->rmt_outer = answer->rdata->u.ipv4;
4991 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4992 tmpDst.ip.v4 = tun->rmt_outer;
4993 mDNSAddr tmpSrc = zeroAddr;
4994 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4995 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4996 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4997 }
4998
4999 question->ThisQInterval = -1; // So we know this tunnel setup has completed
5000
5001 info = GetAuthInfoForName(m, &tun->dstname);
5002 if (!info)
5003 {
5004 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
5005 ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
5006 return;
5007 }
5008
5009 tun->loc_inner = info->AutoTunnelInnerAddress;
5010
5011 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
5012 // look for existing tunnels to see whether they have the same information for our peer.
5013 // If not, delete them and need to create a new tunnel. If they are same, just use the
5014 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
5015 TunnelClientDeleteAny(m, tun, !v6Tunnel);
5016 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
5017
5018 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5019 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5020
5021 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
5022 static char msgbuf[32];
5023 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
5024 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
5025 // Kick off any questions that were held pending this tunnel setup
5026 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
5027 }
5028
5029 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5030 {
5031 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5032 DomainAuthInfo *info;
5033
5034 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
5035
5036 if (!AddRecord) return;
5037 mDNS_StopQuery(m, question);
5038
5039 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
5040 // The code below will look for _autotunnel._udp SRV record followed by A record
5041 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
5042 {
5043 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5044 static char msgbuf[16];
5045 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
5046 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
5047 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
5048 return;
5049 }
5050
5051 switch (tun->tc_state)
5052 {
5053 case TC_STATE_AAAA_PEER:
5054 if (question->qtype != kDNSType_AAAA)
5055 {
5056 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
5057 }
5058 info = GetAuthInfoForName(m, &tun->dstname);
5059 if (!info)
5060 {
5061 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
5062 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5063 return;
5064 }
5065 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5066 {
5067 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
5068 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5069 return;
5070 }
5071 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5072 {
5073 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
5074 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5075 return;
5076 }
5077 tun->rmt_inner = answer->rdata->u.ipv6;
5078 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
5079 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
5080 {
5081 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
5082 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
5083 question->qtype = kDNSType_AAAA;
5084 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
5085 }
5086 else
5087 {
5088 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5089 tun->tc_state = TC_STATE_SRV_PEER;
5090 question->qtype = kDNSType_SRV;
5091 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5092 }
5093 AppendDomainName(&question->qname, &tun->dstname);
5094 mDNS_StartQuery(m, &tun->q);
5095 return;
5096 case TC_STATE_AAAA_PEER_RELAY:
5097 if (question->qtype != kDNSType_AAAA)
5098 {
5099 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
5100 }
5101 // If it failed, look for the SRV record.
5102 if (!answer->rdlength)
5103 {
5104 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5105 tun->tc_state = TC_STATE_SRV_PEER;
5106 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5107 AppendDomainName(&question->qname, &tun->dstname);
5108 question->qtype = kDNSType_SRV;
5109 mDNS_StartQuery(m, &tun->q);
5110 return;
5111 }
5112 TunnelClientFinish(m, question, answer);
5113 return;
5114 case TC_STATE_SRV_PEER:
5115 if (question->qtype != kDNSType_SRV)
5116 {
5117 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
5118 }
5119 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
5120 tun->tc_state = TC_STATE_ADDR_PEER;
5121 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
5122 tun->rmt_outer_port = answer->rdata->u.srv.port;
5123 question->qtype = kDNSType_A;
5124 mDNS_StartQuery(m, &tun->q);
5125 return;
5126 case TC_STATE_ADDR_PEER:
5127 if (question->qtype != kDNSType_A)
5128 {
5129 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
5130 }
5131 TunnelClientFinish(m, question, answer);
5132 return;
5133 default:
5134 LogMsg("AutoTunnelCallback: Unknown question %p", question);
5135 }
5136 }
5137
5138 // Must be called with the lock held
5139 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
5140 {
5141 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
5142 if (!p) return;
5143 AssignDomainName(&p->dstname, &q->qname);
5144 p->MarkedForDeletion = mDNSfalse;
5145 p->loc_inner = zerov6Addr;
5146 p->loc_outer = zerov4Addr;
5147 p->loc_outer6 = zerov6Addr;
5148 p->rmt_inner = zerov6Addr;
5149 p->rmt_outer = zerov4Addr;
5150 p->rmt_outer6 = zerov6Addr;
5151 p->rmt_outer_port = zeroIPPort;
5152 p->tc_state = TC_STATE_AAAA_PEER;
5153 p->next = m->TunnelClients;
5154 m->TunnelClients = p; // We intentionally build list in reverse order
5155
5156 p->q.InterfaceID = mDNSInterface_Any;
5157 p->q.flags = 0;
5158 p->q.Target = zeroAddr;
5159 AssignDomainName(&p->q.qname, &q->qname);
5160 p->q.qtype = kDNSType_AAAA;
5161 p->q.qclass = kDNSClass_IN;
5162 p->q.LongLived = mDNSfalse;
5163 p->q.ExpectUnique = mDNStrue;
5164 p->q.ForceMCast = mDNSfalse;
5165 p->q.ReturnIntermed = mDNStrue;
5166 p->q.SuppressUnusable = mDNSfalse;
5167 p->q.SearchListIndex = 0;
5168 p->q.AppendSearchDomains = 0;
5169 p->q.RetryWithSearchDomains = mDNSfalse;
5170 p->q.TimeoutQuestion = 0;
5171 p->q.WakeOnResolve = 0;
5172 p->q.UseBackgroundTrafficClass = mDNSfalse;
5173 p->q.ValidationRequired = 0;
5174 p->q.ValidatingResponse = 0;
5175 p->q.ProxyQuestion = 0;
5176 p->q.qnameOrig = mDNSNULL;
5177 p->q.AnonInfo = mDNSNULL;
5178 p->q.pid = mDNSPlatformGetPID();
5179 p->q.QuestionCallback = AutoTunnelCallback;
5180 p->q.QuestionContext = p;
5181
5182 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
5183 mDNS_StartQuery_internal(m, &p->q);
5184 }
5185
5186 #endif // APPLE_OSX_mDNSResponder
5187
5188 #if COMPILER_LIKES_PRAGMA_MARK
5189 #pragma mark -
5190 #pragma mark - Power State & Configuration Change Management
5191 #endif
5192
5193 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
5194 {
5195 mDNSBool foundav4 = mDNSfalse;
5196 mDNSBool foundav6 = mDNSfalse;
5197 struct ifaddrs *ifa = myGetIfAddrs(1);
5198 struct ifaddrs *v4Loopback = NULL;
5199 struct ifaddrs *v6Loopback = NULL;
5200 char defaultname[64];
5201 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
5202 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
5203 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
5204
5205 while (ifa)
5206 {
5207 #if LIST_ALL_INTERFACES
5208 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
5209 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5210 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5211 else if (ifa->ifa_addr->sa_family == AF_LINK)
5212 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5213 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5214 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
5215 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5216 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5217 if (!(ifa->ifa_flags & IFF_UP))
5218 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5219 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5220 if (!(ifa->ifa_flags & IFF_MULTICAST))
5221 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5222 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5223 if (ifa->ifa_flags & IFF_POINTOPOINT)
5224 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5225 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5226 if (ifa->ifa_flags & IFF_LOOPBACK)
5227 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5228 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5229 #endif
5230
5231 if (ifa->ifa_addr->sa_family == AF_LINK)
5232 {
5233 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
5234 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
5235 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
5236 }
5237
5238 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
5239 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
5240 {
5241 if (!ifa->ifa_netmask)
5242 {
5243 mDNSAddr ip;
5244 SetupAddr(&ip, ifa->ifa_addr);
5245 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5246 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
5247 }
5248 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5249 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5250 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
5251 {
5252 mDNSAddr ip;
5253 SetupAddr(&ip, ifa->ifa_addr);
5254 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5255 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
5256 }
5257 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5258 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
5259 {
5260 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
5261 }
5262 else
5263 {
5264 // Make sure ifa_netmask->sa_family is set correctly
5265 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5266 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
5267 int ifru_flags6 = 0;
5268
5269 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
5270 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
5271 {
5272 struct in6_ifreq ifr6;
5273 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
5274 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
5275 ifr6.ifr_addr = *sin6;
5276 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
5277 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
5278 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
5279 }
5280
5281 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
5282 {
5283 if (ifa->ifa_flags & IFF_LOOPBACK)
5284 {
5285 if (ifa->ifa_addr->sa_family == AF_INET)
5286 v4Loopback = ifa;
5287 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
5288 v6Loopback = ifa;
5289 }
5290 else
5291 {
5292 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
5293 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
5294 {
5295 if (ifa->ifa_addr->sa_family == AF_INET)
5296 foundav4 = mDNStrue;
5297 else
5298 foundav6 = mDNStrue;
5299 }
5300 }
5301 }
5302 }
5303 }
5304 ifa = ifa->ifa_next;
5305 }
5306
5307 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5308 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
5309 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
5310
5311 // Now the list is complete, set the McastTxRx setting for each interface.
5312 NetworkInterfaceInfoOSX *i;
5313 for (i = m->p->InterfaceList; i; i = i->next)
5314 if (i->Exists)
5315 {
5316 mDNSBool txrx = MulticastInterface(i);
5317 if (i->ifinfo.McastTxRx != txrx)
5318 {
5319 i->ifinfo.McastTxRx = txrx;
5320 i->Exists = 2; // State change; need to deregister and reregister this interface
5321 }
5322 }
5323
5324 if (InfoSocket >= 0)
5325 close(InfoSocket);
5326
5327 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
5328 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
5329
5330 // Set up the nice label
5331 domainlabel nicelabel;
5332 nicelabel.c[0] = 0;
5333 GetUserSpecifiedFriendlyComputerName(&nicelabel);
5334 if (nicelabel.c[0] == 0)
5335 {
5336 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
5337 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
5338 }
5339
5340 // Set up the RFC 1034-compliant label
5341 domainlabel hostlabel;
5342 hostlabel.c[0] = 0;
5343 GetUserSpecifiedLocalHostName(&hostlabel);
5344 if (hostlabel.c[0] == 0)
5345 {
5346 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
5347 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
5348 }
5349
5350 mDNSBool namechange = mDNSfalse;
5351
5352 // We use a case-sensitive comparison here because even though changing the capitalization
5353 // of the name alone is not significant to DNS, it's still a change from the user's point of view
5354 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
5355 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
5356 else
5357 {
5358 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5359 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
5360 m->p->usernicelabel = m->nicelabel = nicelabel;
5361 namechange = mDNStrue;
5362 }
5363
5364 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
5365 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
5366 else
5367 {
5368 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5369 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
5370 m->p->userhostlabel = m->hostlabel = hostlabel;
5371 mDNS_SetFQDN(m);
5372 namechange = mDNStrue;
5373 }
5374
5375 #if APPLE_OSX_mDNSResponder
5376 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5377 {
5378 DomainAuthInfo *info;
5379 for (info = m->AuthInfoList; info; info = info->next)
5380 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5381 }
5382 #endif // APPLE_OSX_mDNSResponder
5383
5384 return(mStatus_NoError);
5385 }
5386
5387 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5388 // Returns -1 if all the one-bits are not contiguous
5389 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5390 {
5391 int i = 0, bits = 0;
5392 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5393 while (i < bytes)
5394 {
5395 mDNSu8 b = mask->ip.v6.b[i++];
5396 while (b & 0x80) { bits++; b <<= 1; }
5397 if (b) return(-1);
5398 }
5399 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5400 return(bits);
5401 }
5402
5403 // returns count of non-link local V4 addresses registered
5404 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
5405 {
5406 NetworkInterfaceInfoOSX *i;
5407 int count = 0;
5408 for (i = m->p->InterfaceList; i; i = i->next)
5409 if (i->Exists)
5410 {
5411 NetworkInterfaceInfo *const n = &i->ifinfo;
5412 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5413 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5414
5415 if (i->Registered && i->Registered != primary) // Sanity check
5416 {
5417 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5418 i->Registered = mDNSNULL;
5419 }
5420
5421 if (!i->Registered)
5422 {
5423 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5424 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5425 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
5426 //
5427
5428 i->Registered = primary;
5429
5430 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5431 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5432 // 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.
5433 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5434
5435 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5436 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5437 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5438 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5439 // logs a warning message to system.log noting frequent interface transitions.
5440 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5441 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5442 {
5443 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
5444 i->Flashing ? " (Flashing)" : "",
5445 i->Occulting ? " (Occulting)" : "");
5446 mDNS_RegisterInterface(m, n, 0);
5447 }
5448 else
5449 {
5450 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
5451 }
5452
5453 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5454 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5455 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
5456 i->Flashing ? " (Flashing)" : "",
5457 i->Occulting ? " (Occulting)" : "",
5458 n->InterfaceActive ? " (Primary)" : "");
5459
5460 if (!n->McastTxRx)
5461 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);
5462 else
5463 {
5464 if (i->sa_family == AF_INET)
5465 {
5466 struct ip_mreq imr;
5467 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5468 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5469 imr.imr_interface = primary->ifa_v4addr;
5470
5471 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5472 // before trying to join the group, to clear out stale kernel state which may be lingering.
5473 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5474 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5475 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5476 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5477 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5478 // because by the time we get the configuration change notification, the interface is already gone,
5479 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5480 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5481 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
5482 {
5483 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);
5484 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5485 if (err < 0 && (errno != EADDRNOTAVAIL))
5486 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5487 }
5488
5489 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5490 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5491 // Joining same group twice can give "Address already in use" error -- no need to report that
5492 if (err < 0 && (errno != EADDRINUSE))
5493 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5494 }
5495 if (i->sa_family == AF_INET6)
5496 {
5497 struct ipv6_mreq i6mr;
5498 i6mr.ipv6mr_interface = primary->scope_id;
5499 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5500
5501 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
5502 {
5503 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);
5504 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5505 if (err < 0 && (errno != EADDRNOTAVAIL))
5506 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5507 }
5508
5509 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5510 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5511 // Joining same group twice can give "Address already in use" error -- no need to report that
5512 if (err < 0 && (errno != EADDRINUSE))
5513 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5514 }
5515 }
5516 }
5517 }
5518
5519 return count;
5520 }
5521
5522 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
5523 {
5524 NetworkInterfaceInfoOSX *i;
5525 for (i = m->p->InterfaceList; i; i = i->next)
5526 {
5527 if (i->Exists) i->LastSeen = utc;
5528 i->Exists = mDNSfalse;
5529 }
5530 }
5531
5532 // returns count of non-link local V4 addresses deregistered
5533 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
5534 {
5535 // First pass:
5536 // If an interface is going away, then deregister this from the mDNSCore.
5537 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5538 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5539 // it refers to has gone away we'll crash.
5540 NetworkInterfaceInfoOSX *i;
5541 int count = 0;
5542 for (i = m->p->InterfaceList; i; i = i->next)
5543 {
5544 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5545 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5546 if (i->Registered)
5547 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
5548 {
5549 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5550 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5551 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5552 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5553 i->Flashing ? " (Flashing)" : "",
5554 i->Occulting ? " (Occulting)" : "",
5555 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5556
5557 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5558 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5559 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5560 // stale data returned to the application even after the interface is removed. The application
5561 // then starts to send data but the new interface is not yet created.
5562 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5563 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
5564 {
5565 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
5566 i->Flashing ? " (Flashing)" : "",
5567 i->Occulting ? " (Occulting)" : "");
5568 mDNS_DeregisterInterface(m, &i->ifinfo, 0);
5569 }
5570 else
5571 {
5572 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
5573 }
5574 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5575 i->Registered = mDNSNULL;
5576 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5577 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5578 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5579
5580 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5581 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5582 }
5583 }
5584
5585 // Second pass:
5586 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5587 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5588 while (*p)
5589 {
5590 i = *p;
5591 // If no longer active, delete interface from list and free memory
5592 if (!i->Exists)
5593 {
5594 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5595 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
5596 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5597 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5598 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5599 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5600 #if APPLE_OSX_mDNSResponder
5601 if (i->BPF_fd >= 0) CloseBPF(i);
5602 #endif // APPLE_OSX_mDNSResponder
5603 if (delete)
5604 {
5605 *p = i->next;
5606 freeL("NetworkInterfaceInfoOSX", i);
5607 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5608 }
5609 }
5610 p = &i->next;
5611 }
5612 return count;
5613 }
5614
5615 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5616 {
5617 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5618 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5619 else
5620 {
5621 dnle->next = mDNSNULL;
5622 dnle->uid = uid;
5623 AssignDomainName(&dnle->name, name);
5624 **List = dnle;
5625 *List = &dnle->next;
5626 }
5627 }
5628
5629 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5630 {
5631 dns_resolver_t *a = *(dns_resolver_t**)aa;
5632 dns_resolver_t *b = *(dns_resolver_t**)bb;
5633
5634 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5635 }
5636
5637 mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5638 {
5639 char *buf = ".";
5640 mDNSu32 scopeid = 0;
5641 char ifid_buf[16];
5642
5643 if (domain)
5644 buf = domain;
5645 //
5646 // Hash the search domain name followed by the InterfaceID.
5647 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5648 // we will detect it. Even if the order of them change, we will detect it.
5649 //
5650 // Note: We have to handle a few of these tricky cases.
5651 //
5652 // 1) Current: com, apple.com Changing to: comapple.com
5653 // 2) Current: a.com,b.com Changing to a.comb.com
5654 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5655 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5656 //
5657 // There are more variants of the above. The key thing is if we include the null in each case
5658 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5659 // NULL as part of the name) to be mistakenly thought of as a old name.
5660
5661 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5662 // mDNS_snprintf always null terminates
5663 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5664 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5665
5666 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5667 MD5_Update(sdc, buf, strlen(buf) + 1);
5668 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5669 }
5670
5671 mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
5672 {
5673 mDNSu8 md5_hash[MD5_LEN];
5674
5675 MD5_Final(md5_hash, sdc);
5676
5677 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5678 {
5679 // If the hash is different, either the search domains have changed or
5680 // the ordering between them has changed. Restart the questions that
5681 // would be affected by this.
5682 LogInfo("FinalizeSearchDomains: The hash is different");
5683 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5684 RetrySearchDomainQuestions(m);
5685 }
5686 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5687 }
5688
5689 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5690 {
5691 switch (scope)
5692 {
5693 case kScopeNone:
5694 return "Unscoped";
5695 case kScopeInterfaceID:
5696 return "InterfaceScoped";
5697 case kScopeServiceID:
5698 return "ServiceScoped";
5699 default:
5700 return "Unknown";
5701 }
5702 }
5703
5704 mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc)
5705 {
5706 const char *scopeString = DNSScopeToString(scope);
5707 int j;
5708
5709 if (scope != kScopeNone)
5710 {
5711 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface);
5712 return;
5713 }
5714 for (j = 0; j < resolver->n_search; j++)
5715 {
5716 LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]);
5717 UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL);
5718 mDNS_AddSearchDomain_CString(resolver->search[j], NULL);
5719 }
5720 }
5721
5722 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
5723 {
5724 NetworkInterfaceInfoOSX *ni;
5725 mDNSInterfaceID interface;
5726
5727 for (ni = m->p->InterfaceList; ni; ni = ni->next)
5728 {
5729 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5730 break;
5731 }
5732 if (ni != NULL)
5733 {
5734 interface = ni->ifinfo.InterfaceID;
5735 }
5736 else
5737 {
5738 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5739 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5740 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5741 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5742 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5743
5744 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5745
5746 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5747 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5748 }
5749 return interface;
5750 }
5751
5752 mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
5753 {
5754 char *opt = r->options;
5755 domainname d;
5756
5757 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5758 {
5759 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5760 {
5761 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5762 return;
5763 }
5764 mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
5765 }
5766 }
5767
5768 mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5769 {
5770 int n;
5771 domainname d;
5772 int serviceID = 0;
5773 mDNSBool cellIntf = mDNSfalse;
5774 mDNSBool scopedDNS = mDNSfalse;
5775 mDNSBool reqA, reqAAAA;
5776
5777 if (!r->domain || !*r->domain)
5778 {
5779 d.c[0] = 0;
5780 }
5781 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5782 {
5783 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5784 return;
5785 }
5786 // Parse the resolver specific attributes that affects all the DNS servers.
5787 if (scope == kScopeInterfaceID)
5788 {
5789 scopedDNS = mDNStrue;
5790 }
5791 else if (scope == kScopeServiceID)
5792 {
5793 serviceID = r->service_identifier;
5794 }
5795
5796 #if TARGET_OS_IPHONE
5797 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5798 #endif
5799 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5800 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5801
5802 for (n = 0; n < r->n_nameserver; n++)
5803 {
5804 mDNSAddr saddr;
5805 DNSServer *s;
5806
5807 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5808 continue;
5809
5810 if (SetupAddr(&saddr, r->nameserver[n]))
5811 {
5812 LogMsg("ConfigDNSServers: Bad address");
5813 continue;
5814 }
5815
5816 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5817 // the timeout value only for the first DNSServer. If we don't have a value in the
5818 // resolver, then use the core's default value
5819 //
5820 // Note: this assumes that when the core picks a list of DNSServers for a question,
5821 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5822 // tries all the DNS servers in a specified timeout
5823 s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5824 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
5825 if (s)
5826 {
5827 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5828 }
5829 }
5830 }
5831
5832 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5833 // Service scope resolvers. This is indicated by the scope argument.
5834 //
5835 // "resolver" has entries that should only be used for unscoped questions.
5836 //
5837 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5838 // interface index (q->InterfaceID)
5839 //
5840 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5841 // a service identifier (q->ServiceID)
5842 //
5843 mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5844 {
5845 int i;
5846 dns_resolver_t **resolver;
5847 int nresolvers;
5848 const char *scopeString = DNSScopeToString(scope);
5849 mDNSInterfaceID interface;
5850
5851 switch (scope)
5852 {
5853 case kScopeNone:
5854 resolver = config->resolver;
5855 nresolvers = config->n_resolver;
5856 break;
5857 case kScopeInterfaceID:
5858 resolver = config->scoped_resolver;
5859 nresolvers = config->n_scoped_resolver;
5860 break;
5861 case kScopeServiceID:
5862 resolver = config->service_specific_resolver;
5863 nresolvers = config->n_service_specific_resolver;
5864 break;
5865 default:
5866 return;
5867 }
5868 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5869
5870 for (i = 0; i < nresolvers; i++)
5871 {
5872 dns_resolver_t *r = resolver[i];
5873
5874 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5875
5876 interface = mDNSInterface_Any;
5877
5878 // Parse the interface index
5879 if (r->if_index != 0)
5880 {
5881 interface = ConfigParseInterfaceID(m, r->if_index);
5882 }
5883
5884 if (setsearch)
5885 {
5886 ConfigSearchDomains(m, resolver[i], interface, scope, sdc);
5887 // Parse other scoped resolvers for search lists
5888 if (!setservers)
5889 continue;
5890 }
5891
5892 if (r->port == 5353 || r->n_nameserver == 0)
5893 {
5894 ConfigNonUnicastResolver(m, r);
5895 }
5896 else
5897 {
5898 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5899 // scoped resolver are not used by other non-scoped or scoped resolvers.
5900 if (scope != kScopeNone)
5901 resGroupID++;
5902
5903 ConfigDNSServers(m, r, interface, scope, resGroupID);
5904 }
5905 }
5906 }
5907
5908 #if APPLE_OSX_mDNSResponder
5909 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5910 {
5911 if (QuerySuppressed(q))
5912 {
5913 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5914 return mDNSfalse;
5915 }
5916 if (mDNSOpaque16IsZero(q->TargetQID))
5917 {
5918 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5919 return mDNSfalse;
5920 }
5921 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5922 // for trigger.
5923 if (q->LOAddressAnswers)
5924 {
5925 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5926 return mDNSfalse;
5927 }
5928 return mDNStrue;
5929 }
5930 #endif
5931
5932 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5933 // We set our state appropriately so that if we start receiving answers, trigger the
5934 // upper layer to retry DNS questions.
5935 #if APPLE_OSX_mDNSResponder
5936 mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
5937 {
5938 if (!QuestionValidForDNSTrigger(q))
5939 return;
5940
5941 // Ignore applications that start and stop queries for no reason before we ever talk
5942 // to any DNS server.
5943 if (!q->triedAllServersOnce)
5944 {
5945 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5946 return;
5947 }
5948 if (q->qtype == kDNSType_A)
5949 m->p->v4answers = 0;
5950 if (q->qtype == kDNSType_AAAA)
5951 m->p->v6answers = 0;
5952 if (!m->p->v4answers || !m->p->v6answers)
5953 {
5954 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5955 DNSTypeName(q->qtype));
5956 }
5957 }
5958 #endif
5959
5960 mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
5961 {
5962 mDNS_CheckLock(m);
5963
5964 // Acking the configuration triggers configd to reissue the reachability queries
5965 m->p->DNSTrigger = NonZeroTime(m->timenow);
5966 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5967 }
5968
5969 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5970 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5971 #if APPLE_OSX_mDNSResponder
5972 mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
5973 {
5974 mDNSBool trigger = mDNSfalse;
5975 mDNSs32 timenow;
5976
5977 // Don't send triggers too often.
5978 // If we have started delivering answers to questions, we should send a trigger
5979 // if the time permits. If we are delivering answers, we should set the state
5980 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5981 // whether the answers that are being delivered currently is for configd or some
5982 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5983 // then we won't deliver the trigger later when it is okay to send one as the
5984 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5985 // v6answers if we are not delivering triggers.
5986 mDNS_Lock(m);
5987 timenow = m->timenow;
5988 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5989 {
5990 if (!m->p->v4answers || !m->p->v6answers)
5991 {
5992 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5993 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5994 }
5995 mDNS_Unlock(m);
5996 return;
5997 }
5998 mDNS_Unlock(m);
5999 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
6000 {
6001 int old = m->p->v4answers;
6002
6003 m->p->v4answers = 1;
6004
6005 // If there are IPv4 answers now and previously we did not have
6006 // any answers, trigger a DNS change so that reachability
6007 // can retry the queries again.
6008 if (!old)
6009 {
6010 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6011 v4q->qname.c, DNSTypeName(v4q->qtype));
6012 trigger = mDNStrue;
6013 }
6014 }
6015 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
6016 {
6017 int old = m->p->v6answers;
6018
6019 m->p->v6answers = 1;
6020 // If there are IPv6 answers now and previously we did not have
6021 // any answers, trigger a DNS change so that reachability
6022 // can retry the queries again.
6023 if (!old)
6024 {
6025 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6026 v6q->qname.c, DNSTypeName(v6q->qtype));
6027 trigger = mDNStrue;
6028 }
6029 }
6030 if (trigger)
6031 {
6032 dns_config_t *config = dns_configuration_copy();
6033 if (config)
6034 {
6035 mDNS_Lock(m);
6036 AckConfigd(m, config);
6037 mDNS_Unlock(m);
6038 dns_configuration_free(config);
6039 }
6040 else
6041 {
6042 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
6043 }
6044 }
6045 }
6046
6047 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
6048 {
6049 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
6050 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
6051 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
6052 config->resolver[0]->nameserver[0])
6053 {
6054 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
6055 }
6056 else
6057 {
6058 ActiveDirectoryPrimaryDomain.c[0] = 0;
6059 }
6060
6061 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
6062 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
6063 if (config->n_resolver && config->resolver[0]->n_nameserver &&
6064 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
6065 {
6066 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
6067 }
6068 else
6069 {
6070 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
6071 ActiveDirectoryPrimaryDomainLabelCount = 0;
6072 ActiveDirectoryPrimaryDomainServer = zeroAddr;
6073 }
6074 }
6075 #endif
6076
6077 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
6078 {
6079 int i;
6080 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6081 domainname d;
6082
6083 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetupDDNSDomains"), NULL, NULL);
6084 if (!store)
6085 {
6086 LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6087 }
6088 else
6089 {
6090 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
6091 if (ddnsdict)
6092 {
6093 if (fqdn)
6094 {
6095 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
6096 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
6097 {
6098 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
6099 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
6100 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
6101 {
6102 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
6103 if (name)
6104 {
6105 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6106 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
6107 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
6108 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
6109 }
6110 }
6111 }
6112 }
6113
6114 if (RegDomains)
6115 {
6116 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
6117 if (regArray && CFArrayGetCount(regArray) > 0)
6118 {
6119 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
6120 if (regDict && DictionaryIsEnabled(regDict))
6121 {
6122 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
6123 if (name)
6124 {
6125 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6126 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6127 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
6128 else
6129 {
6130 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
6131 AppendDNameListElem(&RegDomains, 0, &d);
6132 }
6133 }
6134 }
6135 }
6136 }
6137
6138 if (BrowseDomains)
6139 {
6140 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
6141 if (browseArray)
6142 {
6143 for (i = 0; i < CFArrayGetCount(browseArray); i++)
6144 {
6145 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
6146 if (browseDict && DictionaryIsEnabled(browseDict))
6147 {
6148 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
6149 if (name)
6150 {
6151 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6152 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6153 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
6154 else
6155 {
6156 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
6157 AppendDNameListElem(&BrowseDomains, 0, &d);
6158 }
6159 }
6160 }
6161 }
6162 }
6163 }
6164 CFRelease(ddnsdict);
6165 }
6166
6167 if (RegDomains)
6168 {
6169 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6170 if (btmm)
6171 {
6172 CFIndex size = CFDictionaryGetCount(btmm);
6173 const void *key[size];
6174 const void *val[size];
6175 CFDictionaryGetKeysAndValues(btmm, key, val);
6176 for (i = 0; i < size; i++)
6177 {
6178 LogInfo("BackToMyMac %d", i);
6179 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6180 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
6181 else
6182 {
6183 mDNSu32 uid = atoi(buf);
6184 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6185 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
6186 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
6187 {
6188 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
6189 AppendDNameListElem(&RegDomains, uid, &d);
6190 }
6191 }
6192 }
6193 CFRelease(btmm);
6194 }
6195 }
6196 CFRelease(store);
6197 }
6198 }
6199
6200 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
6201 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
6202 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
6203 {
6204 MD5_CTX sdc; // search domain context
6205 static mDNSu16 resolverGroupID = 0;
6206
6207 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
6208 if (fqdn ) fqdn->c[0] = 0;
6209 if (RegDomains ) *RegDomains = NULL;
6210 if (BrowseDomains) *BrowseDomains = NULL;
6211
6212 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
6213 setservers ? " setservers" : "",
6214 setsearch ? " setsearch" : "",
6215 fqdn ? " fqdn" : "",
6216 RegDomains ? " RegDomains" : "",
6217 BrowseDomains ? " BrowseDomains" : "");
6218
6219 if (setsearch) MD5_Init(&sdc);
6220
6221 // Add the inferred address-based configuration discovery domains
6222 // (should really be in core code I think, not platform-specific)
6223 if (setsearch)
6224 {
6225 struct ifaddrs *ifa = mDNSNULL;
6226 struct sockaddr_in saddr;
6227 mDNSPlatformMemZero(&saddr, sizeof(saddr));
6228 saddr.sin_len = sizeof(saddr);
6229 saddr.sin_family = AF_INET;
6230 saddr.sin_port = 0;
6231 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
6232
6233 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
6234 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
6235
6236 while (ifa)
6237 {
6238 mDNSAddr a, n;
6239 char buf[64];
6240
6241 if (ifa->ifa_addr->sa_family == AF_INET &&
6242 ifa->ifa_netmask &&
6243 !(ifa->ifa_flags & IFF_LOOPBACK) &&
6244 !SetupAddr(&a, ifa->ifa_addr) &&
6245 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
6246 {
6247 // 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
6248 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
6249 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
6250 SetupAddr(&n, ifa->ifa_netmask);
6251 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6252 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
6253 a.ip.v4.b[2] & n.ip.v4.b[2],
6254 a.ip.v4.b[1] & n.ip.v4.b[1],
6255 a.ip.v4.b[0] & n.ip.v4.b[0]);
6256 UpdateSearchDomainHash(m, &sdc, buf, NULL);
6257 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
6258 }
6259 ifa = ifa->ifa_next;
6260 }
6261 }
6262
6263 #ifndef MDNS_NO_DNSINFO
6264 if (setservers || setsearch)
6265 {
6266 dns_config_t *config = dns_configuration_copy();
6267 if (!config)
6268 {
6269 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
6270 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
6271 // Apparently this is expected behaviour -- "not a bug".
6272 // Accordingly, we suppress syslog messages for the first three minutes after boot.
6273 // If we are still getting failures after three minutes, then we log them.
6274 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
6275 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6276 }
6277 else
6278 {
6279 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation);
6280 // SameDomainName check below is to fix <rdar://problem/18059009> Dynamic DNS hostname changes not noticed
6281 if (m->p->LastConfigGeneration == config->generation && (!fqdn || (SameDomainName(fqdn, &m->FQDN))))
6282 {
6283 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
6284 dns_configuration_free(config);
6285 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6286 return mDNSfalse;
6287 }
6288 #if APPLE_OSX_mDNSResponder
6289 SetupActiveDirectoryDomain(config);
6290 #endif
6291
6292 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6293 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6294 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6295 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6296 // same resolverGroupID.
6297 //
6298 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6299 ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6300 resolverGroupID += config->n_resolver;
6301
6302 ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6303 resolverGroupID += config->n_scoped_resolver;
6304
6305 ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6306
6307 // Acking provides a hint that we processed this current configuration and
6308 // we will use that from now on, assuming we don't get another one immediately
6309 // after we return from here.
6310 if (ackConfig)
6311 {
6312 // Note: We have to set the generation number here when we are acking.
6313 // For every DNS configuration change, we do the following:
6314 //
6315 // 1) Copy dns configuration, handle search domains change
6316 // 2) Copy dns configuration, handle dns server change
6317 //
6318 // If we update the generation number at step (1), we won't process the
6319 // DNS servers the second time because generation number would be the same.
6320 // As we ack only when we process dns servers, we set the generation number
6321 // during acking.
6322 m->p->LastConfigGeneration = config->generation;
6323 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6324 AckConfigd(m, config);
6325 }
6326 dns_configuration_free(config);
6327 if (setsearch) FinalizeSearchDomainHash(m, &sdc);
6328 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
6329 setsearch = mDNSfalse;
6330 }
6331 }
6332 #endif // MDNS_NO_DNSINFO
6333 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6334 return mDNStrue;
6335 }
6336
6337
6338 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6339 {
6340 char buf[256];
6341 (void)m; // Unused
6342
6343 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
6344 if (!store)
6345 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6346 else
6347 {
6348 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
6349 if (dict)
6350 {
6351 r->type = mDNSAddrType_IPv4;
6352 r->ip.v4 = zerov4Addr;
6353 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6354 if (string)
6355 {
6356 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6357 LogMsg("Could not convert router to CString");
6358 else
6359 {
6360 struct sockaddr_in saddr;
6361 saddr.sin_len = sizeof(saddr);
6362 saddr.sin_family = AF_INET;
6363 saddr.sin_port = 0;
6364 inet_aton(buf, &saddr.sin_addr);
6365
6366 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6367 }
6368 }
6369
6370 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6371 if (string)
6372 {
6373 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6374 struct ifaddrs *ifa = myGetIfAddrs(1);
6375
6376 *v4 = *v6 = zeroAddr;
6377
6378 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
6379
6380 // find primary interface in list
6381 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6382 {
6383 mDNSAddr tmp6 = zeroAddr;
6384 if (!strcmp(buf, ifa->ifa_name))
6385 {
6386 if (ifa->ifa_addr->sa_family == AF_INET)
6387 {
6388 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
6389 }
6390 else if (ifa->ifa_addr->sa_family == AF_INET6)
6391 {
6392 SetupAddr(&tmp6, ifa->ifa_addr);
6393 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6394 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
6395 }
6396 }
6397 else
6398 {
6399 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6400 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6401 {
6402 SetupAddr(&tmp6, ifa->ifa_addr);
6403 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
6404 }
6405 }
6406 ifa = ifa->ifa_next;
6407 }
6408
6409 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6410 // V4 to communicate w/ our DNS server
6411 }
6412
6413 exit:
6414 CFRelease(dict);
6415 }
6416 CFRelease(store);
6417 }
6418 return mStatus_NoError;
6419 }
6420
6421 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6422 {
6423 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6424 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6425 ConvertDomainNameToCString(dname, uname);
6426
6427 char *p = uname;
6428 while (*p)
6429 {
6430 *p = tolower(*p);
6431 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6432 p++;
6433 }
6434
6435 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6436 // That single entity is a CFDictionary with name "HostNames".
6437 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6438 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6439 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6440 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6441 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6442
6443 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6444 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6445 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6446 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6447 else
6448 {
6449 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6450 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6451 else
6452 {
6453 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6454 if (HostVals[0])
6455 {
6456 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6457 if (StateVals[0])
6458 {
6459 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6460 if (StateDict)
6461 {
6462 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6463 CFRelease(StateDict);
6464 }
6465 CFRelease(StateVals[0]);
6466 }
6467 CFRelease(HostVals[0]);
6468 }
6469 CFRelease(StatusVals[0]);
6470 }
6471 CFRelease(HostKeys[0]);
6472 }
6473 }
6474
6475 #if APPLE_OSX_mDNSResponder
6476 #if !NO_AWACS
6477
6478 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6479 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6480 // help catch it
6481 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6482 {
6483 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6484 if (!store)
6485 {
6486 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6487 return mDNSfalse;
6488 }
6489 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6490 if (btmm)
6491 {
6492 CFIndex size = CFDictionaryGetCount(btmm);
6493 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6494 const void *key[size];
6495 const void *val[size];
6496 domainname dom;
6497 int i;
6498 CFDictionaryGetKeysAndValues(btmm, key, val);
6499 for (i = 0; i < size; i++)
6500 {
6501 LogInfo("BackToMyMac %d", i);
6502 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6503 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6504 else
6505 {
6506 mDNSu32 uid = atoi(buf);
6507 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6508 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6509 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6510 {
6511 if (SameDomainName(&dom, d))
6512 {
6513 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6514 CFRelease(btmm);
6515 CFRelease(store);
6516 return mDNStrue;
6517 }
6518 }
6519 }
6520 }
6521 CFRelease(btmm);
6522 }
6523 CFRelease(store);
6524 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6525 return mDNSfalse;
6526 }
6527
6528 // Appends data to the buffer
6529 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6530 {
6531 int len;
6532
6533 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6534 if (len >= (bufsz - *currlen))
6535 {
6536 // if we have exceeded the space in buf, it has already been NULL terminated
6537 // and we have nothing more to do. Set currlen to the last byte so that the caller
6538 // knows to do the right thing
6539 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6540 *currlen = bufsz - 1;
6541 return -1;
6542 }
6543 else { (*currlen) += len; }
6544
6545 buf[*currlen] = ',';
6546 if (*currlen >= bufsz)
6547 {
6548 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6549 *currlen = bufsz - 1;
6550 buf[*currlen] = 0;
6551 return -1;
6552 }
6553 // if we have filled up the buffer exactly, then there is no more work to do
6554 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6555 (*currlen)++;
6556 return *currlen;
6557 }
6558
6559 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6560 // BTMM domains, then bring down the connection to the relay.
6561 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6562 {
6563 DomainAuthInfo *BTMMDomain = mDNSNULL;
6564 DomainAuthInfo *FoundInList;
6565 static mDNSBool AWACSDConnected = mDNSfalse;
6566 char AllUsers[1024]; // maximum size of mach message
6567 char AllPass[1024]; // maximum size of mach message
6568 char username[MAX_DOMAIN_LABEL + 1];
6569 int currulen = 0;
6570 int currplen = 0;
6571
6572 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6573 // we may not be able to send the dns queries over the relay connection which may be needed
6574 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6575 // need to make sure that we send the disconnect before attempting the next connect as the
6576 // awacs connections are redirected based on usernames.
6577 //
6578 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6579 // connection, we will need to fix this.
6580
6581 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6582 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6583 {
6584 // We need the passwd from the first domain.
6585 BTMMDomain = FoundInList;
6586 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6587 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6588 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6589 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6590 }
6591
6592 if (BTMMDomain)
6593 {
6594 // In the normal case (where we neither exceed the buffer size nor write bytes that
6595 // fit exactly into the buffer), currulen/currplen should be a different size than
6596 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6597
6598 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6599 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6600
6601 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6602 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6603 AWACSDConnected = mDNStrue;
6604 }
6605 else
6606 {
6607 // Disconnect only if we connected previously
6608 if (AWACSDConnected)
6609 {
6610 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6611 AWACS_Disconnect();
6612 AWACSDConnected = mDNSfalse;
6613 }
6614 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6615 }
6616 }
6617 #else
6618 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6619 {
6620 (void) m; // Unused
6621 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6622 }
6623 #endif // ! NO_AWACS
6624
6625 mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
6626
6627 #endif // APPLE_OSX_mDNSResponder
6628
6629 // MUST be called holding the lock
6630 mDNSexport void SetDomainSecrets(mDNS *m)
6631 {
6632 #ifdef NO_SECURITYFRAMEWORK
6633 (void) m;
6634 LogMsg("Note: SetDomainSecrets: no keychain support");
6635 #else
6636 mDNSBool haveAutoTunnels = mDNSfalse;
6637
6638 LogInfo("SetDomainSecrets");
6639
6640 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6641 // In the case where the user simultaneously removes their DDNS host name and the key
6642 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6643 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6644 // address records behind that we no longer have permission to delete.
6645 DomainAuthInfo *ptr;
6646 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6647 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6648
6649 #if APPLE_OSX_mDNSResponder
6650 {
6651 // Mark all TunnelClients for deletion
6652 ClientTunnel *client;
6653 for (client = m->TunnelClients; client; client = client->next)
6654 {
6655 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6656 client->MarkedForDeletion = mDNStrue;
6657 }
6658 }
6659 #endif // APPLE_OSX_mDNSResponder
6660
6661 // String Array used to write list of private domains to Dynamic Store
6662 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6663 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6664 CFIndex i;
6665 CFDataRef data = NULL;
6666 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6667 CFArrayRef secrets = NULL;
6668 int err = mDNSKeychainGetSecrets(&secrets);
6669 if (err || !secrets)
6670 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6671 else
6672 {
6673 CFIndex ArrayCount = CFArrayGetCount(secrets);
6674 // Iterate through the secrets
6675 for (i = 0; i < ArrayCount; ++i)
6676 {
6677 mDNSBool AutoTunnel;
6678 int j, offset;
6679 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6680 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6681 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6682 for (j = 0; j < CFArrayGetCount(entry); ++j)
6683 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6684 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6685
6686 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6687
6688 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6689 // Get DNS domain this key is for (kmDNSKcWhere)
6690 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6691 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6692 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6693 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6694 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6695 stringbuf[CFDataGetLength(data)] = '\0';
6696
6697 AutoTunnel = mDNSfalse;
6698 offset = 0;
6699 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6700 offset = strlen(dnsprefix);
6701 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6702 {
6703 AutoTunnel = mDNStrue;
6704 offset = strlen(btmmprefix);
6705 }
6706 domainname domain;
6707 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6708
6709 // Get key name (kmDNSKcAccount)
6710 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6711 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6712 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6713 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6714 stringbuf[CFDataGetLength(data)] = '\0';
6715
6716 domainname keyname;
6717 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6718
6719 // Get key data (kmDNSKcKey)
6720 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6721 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6722 {
6723 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6724 continue;
6725 }
6726 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6727 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6728
6729 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6730 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6731 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6732 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6733 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6734 {
6735 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6736 continue;
6737 }
6738 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6739 hostbuf[CFDataGetLength(data)] = '\0';
6740
6741 domainname hostname;
6742 mDNSIPPort port;
6743 char *hptr;
6744 hptr = strchr(hostbuf, ':');
6745
6746 port.NotAnInteger = 0;
6747 if (hptr)
6748 {
6749 mDNSu8 *p;
6750 mDNSu16 val = 0;
6751
6752 *hptr++ = '\0';
6753 while(hptr && *hptr != 0)
6754 {
6755 if (*hptr < '0' || *hptr > '9')
6756 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6757 val = val * 10 + *hptr - '0';
6758 hptr++;
6759 }
6760 if (!val) continue;
6761 p = (mDNSu8 *)&val;
6762 port.NotAnInteger = p[0] << 8 | p[1];
6763 }
6764 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6765 hptr = strchr(hostbuf, '@');
6766 if (hptr)
6767 hptr++;
6768 else
6769 hptr = hostbuf;
6770 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6771
6772 DomainAuthInfo *FoundInList;
6773 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6774 if (SameDomainName(&FoundInList->domain, &domain)) break;
6775
6776 #if APPLE_OSX_mDNSResponder
6777 if (FoundInList)
6778 {
6779 // If any client tunnel destination is in this domain, set deletion flag to false
6780 ClientTunnel *client;
6781 for (client = m->TunnelClients; client; client = client->next)
6782 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6783 {
6784 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6785 client->MarkedForDeletion = mDNSfalse;
6786 }
6787 }
6788
6789 #endif // APPLE_OSX_mDNSResponder
6790
6791 // Uncomment the line below to view the keys as they're read out of the system keychain
6792 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6793 //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]));
6794 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6795
6796 // If didn't find desired domain in the list, make a new entry
6797 ptr = FoundInList;
6798 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6799 if (!FoundInList)
6800 {
6801 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6802 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6803 }
6804
6805 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6806
6807 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6808 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6809 {
6810 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6811 continue;
6812 }
6813
6814 ConvertDomainNameToCString(&domain, stringbuf);
6815 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6816 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6817 }
6818 CFRelease(secrets);
6819 }
6820
6821 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6822 {
6823 if (privateDnsArray)
6824 CFRelease(privateDnsArray);
6825
6826 privateDnsArray = sa;
6827 CFRetain(privateDnsArray);
6828 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6829 }
6830 CFRelease(sa);
6831
6832 #if APPLE_OSX_mDNSResponder
6833 {
6834 // clean up ClientTunnels
6835 ClientTunnel **pp = &m->TunnelClients;
6836 while (*pp)
6837 {
6838 if ((*pp)->MarkedForDeletion)
6839 {
6840 ClientTunnel *cur = *pp;
6841 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6842 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6843 AutoTunnelSetKeys(cur, mDNSfalse);
6844 *pp = cur->next;
6845 freeL("ClientTunnel", cur);
6846 }
6847 else
6848 pp = &(*pp)->next;
6849 }
6850
6851 mDNSBool needAutoTunnelNAT = mDNSfalse;
6852 DomainAuthInfo *info;
6853 for (info = m->AuthInfoList; info; info = info->next)
6854 {
6855 if (info->AutoTunnel)
6856 {
6857 UpdateAutoTunnelDeviceInfoRecord(m, info);
6858 UpdateAutoTunnelHostRecord(m, info);
6859 UpdateAutoTunnelServiceRecords(m, info);
6860 UpdateAutoTunnel6Record(m, info);
6861 if (info->deltime)
6862 {
6863 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6864 }
6865 else if (info->AutoTunnelServiceStarted)
6866 needAutoTunnelNAT = true;
6867
6868 UpdateAutoTunnelDomainStatus(m, info);
6869 }
6870 }
6871
6872 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6873 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6874 {
6875 // stop the NAT operation, reset port, cleanup state
6876 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6877 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6878 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6879 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6880 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6881 m->AutoTunnelNAT.Lifetime = 0;
6882 m->AutoTunnelNAT.Result = mStatus_NoError;
6883 m->AutoTunnelNAT.clientContext = mDNSNULL;
6884 }
6885
6886 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6887 ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6888 }
6889 #endif // APPLE_OSX_mDNSResponder
6890
6891 CheckSuppressUnusableQuestions(m);
6892
6893 #endif /* NO_SECURITYFRAMEWORK */
6894 }
6895
6896 mDNSlocal void SetLocalDomains(void)
6897 {
6898 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6899 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6900
6901 CFArrayAppendValue(sa, CFSTR("local"));
6902 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6903 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6904 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6905 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6906 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6907
6908 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6909 CFRelease(sa);
6910 }
6911
6912 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6913 {
6914 #if USE_IOPMCOPYACTIVEPMPREFERENCES
6915 CFTypeRef blob = NULL;
6916 CFStringRef str = NULL;
6917 CFDictionaryRef odict = NULL;
6918 CFDictionaryRef idict = NULL;
6919 CFNumberRef number = NULL;
6920
6921 blob = IOPSCopyPowerSourcesInfo();
6922 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
6923
6924 odict = IOPMCopyActivePMPreferences();
6925 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
6926
6927 str = IOPSGetProvidingPowerSourceType(blob);
6928 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
6929
6930 idict = CFDictionaryGetValue(odict, str);
6931 if (!idict)
6932 {
6933 char buf[256];
6934 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6935 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
6936 goto end;
6937 }
6938
6939 number = CFDictionaryGetValue(idict, name);
6940 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6941 *val = 0;
6942 end:
6943 if (blob) CFRelease(blob);
6944 if (odict) CFRelease(odict);
6945
6946 #else
6947
6948 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
6949 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6950 else
6951 {
6952 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6953 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6954 else
6955 {
6956 CFNumberRef number = CFDictionaryGetValue(dict, name);
6957 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6958 *val = 0;
6959 CFRelease(dict);
6960 }
6961 CFRelease(store);
6962 }
6963
6964 #endif
6965 }
6966
6967 #if APPLE_OSX_mDNSResponder
6968
6969 static CFMutableDictionaryRef spsStatusDict = NULL;
6970 static const CFStringRef kMetricRef = CFSTR("Metric");
6971
6972 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6973 {
6974 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6975 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6976 if (!num)
6977 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6978 else
6979 {
6980 CFDictionarySetValue(dict, key, num);
6981 CFRelease(num);
6982 }
6983 }
6984
6985 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6986 {
6987 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6988 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6989
6990 char buffer[1024];
6991 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6992 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6993 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6994 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6995 CFRelease(spsname);
6996
6997 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6998 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6999 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
7000 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
7001
7002 mDNSu32 tmp = SPSMetric(ptr);
7003 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
7004 if (!num)
7005 LogMsg("SPSCreateDict: Could not create CFNumber");
7006 else
7007 {
7008 CFDictionarySetValue(dict, kMetricRef, num);
7009 CFRelease(num);
7010 }
7011
7012 if (ptr[0] >= 12)
7013 {
7014 memcpy(buffer, ptr + 13, ptr[0] - 12);
7015 buffer[ptr[0] - 12] = 0;
7016 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7017 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
7018 else
7019 {
7020 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
7021 CFRelease(spsname);
7022 }
7023 }
7024
7025 return dict;
7026 }
7027
7028 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
7029 {
7030 (void)context;
7031 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
7032 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
7033 NULL);
7034 }
7035
7036 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7037 {
7038 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
7039 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
7040
7041 mDNS_Lock(m);
7042 mDNS_UpdateAllowSleep(m);
7043 mDNS_Unlock(m);
7044
7045 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
7046
7047 if (!spsStatusDict)
7048 {
7049 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7050 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
7051 }
7052
7053 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
7054 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
7055
7056 CFMutableArrayRef array = NULL;
7057
7058 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
7059 {
7060 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7061 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
7062 CFDictionarySetValue(spsStatusDict, ifname, array);
7063 CFRelease(array); // let go of our reference, now that the dict has one
7064 }
7065 else
7066 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
7067
7068 if (!answer) // special call that means the question has been stopped (because the interface is going away)
7069 CFArrayRemoveAllValues(array);
7070 else
7071 {
7072 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
7073 if (!dict) { CFRelease(ifname); return; }
7074
7075 if (AddRecord)
7076 {
7077 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
7078 {
7079 int i=0;
7080 for (i=0; i<CFArrayGetCount(array); i++)
7081 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
7082 break;
7083 CFArrayInsertValueAtIndex(array, i, dict);
7084 }
7085 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
7086 }
7087 else
7088 {
7089 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
7090 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
7091 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
7092 }
7093
7094 CFRelease(dict);
7095 }
7096
7097 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
7098
7099 CFRelease(ifname);
7100 }
7101
7102 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
7103 {
7104 mDNSs32 val = -1;
7105 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
7106 if (!store)
7107 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7108 else
7109 {
7110 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
7111 if (dict)
7112 {
7113 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
7114 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
7115 CFRelease(dict);
7116 }
7117 CFRelease(store);
7118 }
7119 return val;
7120 }
7121
7122 mDNSlocal void SetSPS(mDNS *const m)
7123 {
7124
7125 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
7126 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
7127
7128 // For devices that are not running NAT, but are set to never sleep, we may choose to act
7129 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
7130 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
7131
7132 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
7133
7134 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
7135 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
7136 // We rate such a device as metric 70 ("Incidentally Available Hardware")
7137 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
7138
7139 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
7140 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
7141 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
7142
7143 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
7144 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
7145 if (IsAppleTV())
7146 {
7147 NetworkInterfaceInfo *intf = mDNSNULL;
7148 mDNSEthAddr bssid = zeroEthAddr;
7149 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
7150 {
7151 bssid = GetBSSID(intf->ifname);
7152 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
7153 {
7154 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
7155 sps = 0;
7156 break;
7157 }
7158 }
7159 }
7160 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
7161
7162 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
7163 }
7164
7165 // The definitions below should eventually come from some externally-supplied header file.
7166 // However, since these definitions can't really be changed without breaking binary compatibility,
7167 // they should never change, so in practice it should not be a big problem to have them defined here.
7168
7169 enum
7170 { // commands from the daemon to the driver
7171 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
7172 };
7173
7174 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
7175
7176 typedef struct
7177 { // cmd_mDNSOffloadRR structure
7178 uint32_t command; // set to OffloadRR
7179 uint32_t rrBufferSize; // number of bytes of RR records
7180 uint32_t numUDPPorts; // number of SRV UDP ports
7181 uint32_t numTCPPorts; // number of SRV TCP ports
7182 uint32_t numRRRecords; // number of RR records
7183 uint32_t compression; // rrRecords - compression is base for compressed strings
7184 FatPtr rrRecords; // address of array of pointers to the rr records
7185 FatPtr udpPorts; // address of udp port list (SRV)
7186 FatPtr tcpPorts; // address of tcp port list (SRV)
7187 } mDNSOffloadCmd;
7188
7189 #include <IOKit/IOKitLib.h>
7190 #include <dns_util.h>
7191
7192 mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
7193 {
7194 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
7195 int count = 0;
7196 AuthRecord *rr;
7197 for (rr = m->ResourceRecords; rr; rr=rr->next)
7198 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
7199 {
7200 if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
7201 count++;
7202 }
7203
7204 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
7205 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
7206 {
7207 LogSPS("GetPortArray Back to My Mac at %d", count);
7208 if (portarray) portarray[count] = IPSECPort;
7209 count++;
7210 }
7211 return(count);
7212 }
7213
7214 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7215 mDNSlocal mDNSBool SupportsTCPKeepAlive()
7216 {
7217 IOReturn ret = kIOReturnSuccess;
7218 CFTypeRef obj = NULL;
7219 mDNSBool supports = mDNSfalse;
7220
7221 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
7222 if ((kIOReturnSuccess == ret) && (obj != NULL))
7223 {
7224 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
7225 CFRelease(obj);
7226 }
7227 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
7228 return supports;
7229 }
7230
7231 mDNSlocal mDNSBool OnBattery(void)
7232 {
7233 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
7234 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
7235 mDNSBool result = mDNSfalse;
7236
7237 if (powerInfo != NULL)
7238 {
7239 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
7240 CFRelease(powerInfo);
7241 }
7242 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
7243 return result;
7244 }
7245
7246 #endif // !TARGET_OS_EMBEDDED
7247
7248 #define TfrRecordToNIC(RR) \
7249 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
7250
7251 mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7252 {
7253 *numbytes = 0;
7254 int count = 0;
7255
7256 AuthRecord *rr;
7257
7258 for (rr = m->ResourceRecords; rr; rr=rr->next)
7259 {
7260 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7261 {
7262 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7263 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7264 // Skip over all other records if we are registering TCP KeepAlive records only
7265 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
7266 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7267 continue;
7268
7269 // Update the record before calculating the number of bytes required
7270 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7271 // attempt to update the record again.
7272 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
7273 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7274 #else
7275 (void) TCPKAOnly; // unused
7276 (void) supportsTCPKA; // unused
7277 (void) intf; // unused
7278 #endif // APPLE_OSX_mDNSResponder
7279 if (TfrRecordToNIC(rr))
7280 {
7281 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
7282 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
7283 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
7284 count++;
7285 }
7286 }
7287 }
7288 return(count);
7289 }
7290
7291 mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7292 {
7293 mDNSu8 *p = msg->data;
7294 const mDNSu8 *const limit = p + *numbytes;
7295 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7296
7297 int count = 0;
7298 AuthRecord *rr;
7299
7300 for (rr = m->ResourceRecords; rr; rr=rr->next)
7301 {
7302 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7303 {
7304 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7305 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7306
7307 // Skip over all other records if we are registering TCP KeepAlive records only
7308 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7309 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7310 continue;
7311 #else
7312 (void) TCPKAOnly; // unused
7313 (void) supportsTCPKA; // unused
7314 #endif // APPLE_OSX_mDNSResponder
7315
7316 if (TfrRecordToNIC(rr))
7317 {
7318 records[count].sixtyfourbits = zeroOpaque64;
7319 records[count].ptr = p;
7320 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7321 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7322 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7323 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7324 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7325 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7326 count++;
7327 }
7328 }
7329 }
7330 *numbytes = p - msg->data;
7331 }
7332
7333 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
7334 // then we declare a dummy version here so that the code at least compiles
7335 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
7336 static kern_return_t
7337 IOConnectCallStructMethod(
7338 mach_port_t connection, // In
7339 uint32_t selector, // In
7340 const void *inputStruct, // In
7341 size_t inputStructCnt, // In
7342 void *outputStruct, // Out
7343 size_t *outputStructCnt) // In/Out
7344 {
7345 (void)connection;
7346 (void)selector;
7347 (void)inputStruct;
7348 (void)inputStructCnt;
7349 (void)outputStruct;
7350 (void)outputStructCnt;
7351 LogMsg("Compiled without IOConnectCallStructMethod");
7352 return(KERN_FAILURE);
7353 }
7354 #endif
7355
7356 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7357 {
7358 if(!UseInternalSleepProxy)
7359 {
7360 LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7361 return mDNSfalse;
7362 }
7363 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7364 }
7365
7366 mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held
7367 {
7368 mStatus result = mStatus_UnknownErr;
7369 mDNSBool TCPKAOnly = mDNSfalse;
7370 mDNSBool supportsTCPKA = mDNSfalse;
7371 mDNSBool onbattery = mDNSfalse;
7372 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7373
7374 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7375 onbattery = OnBattery();
7376 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7377 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
7378
7379 // Only TCP Keepalive records are to be offloaded if
7380 // - The system is on battery
7381 // - OR wake for network access is not set but powernap is enabled
7382 TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
7383 #else
7384 (void) onbattery; // unused;
7385 #endif
7386 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7387
7388 io_name_t n1, n2;
7389 IOObjectGetClass(service, n1);
7390 io_object_t parent;
7391 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7392 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7393 else
7394 {
7395 IOObjectGetClass(parent, n2);
7396 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7397 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7398 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7399 else
7400 {
7401 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7402 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7403 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7404 else if (!UseInternalSleepProxy)
7405 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7406 else
7407 {
7408 io_connect_t conObj;
7409 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7410 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7411 else
7412 {
7413 mDNSOffloadCmd cmd;
7414 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7415 cmd.command = cmd_mDNSOffloadRR;
7416 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
7417 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
7418 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
7419 cmd.compression = sizeof(DNSMessageHeader);
7420
7421 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7422 cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
7423 cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
7424 cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
7425
7426 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7427 msg, cmd.rrBufferSize,
7428 cmd.rrRecords.ptr, cmd.numRRRecords,
7429 cmd.udpPorts.ptr, cmd.numUDPPorts,
7430 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7431
7432 if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
7433 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7434 msg, cmd.rrBufferSize,
7435 cmd.rrRecords.ptr, cmd.numRRRecords,
7436 cmd.udpPorts.ptr, cmd.numUDPPorts,
7437 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7438 else
7439 {
7440 GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
7441 GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
7442 GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
7443 char outputData[2];
7444 size_t outputDataSize = sizeof(outputData);
7445 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7446 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7447 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7448 }
7449
7450 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7451 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7452 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7453 if (msg) freeL("mDNSOffloadCmd msg", msg);
7454 IOServiceClose(conObj);
7455 }
7456 }
7457 CFRelease(ref);
7458 }
7459 IOObjectRelease(parent);
7460 }
7461 IOObjectRelease(service);
7462 return result;
7463 }
7464
7465 #endif // APPLE_OSX_mDNSResponder
7466
7467 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7468 {
7469 mDNSs32 val = 0;
7470 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7471
7472 if (DisableSleepProxyClient)
7473 {
7474 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7475 return mDNSfalse;
7476 }
7477
7478 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7479
7480 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7481
7482 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7483 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7484 // Further policy decisions on whether to offload the records is handled during sleep processing.
7485 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7486 ret = (mDNSu8)mDNS_WakeOnBattery;
7487 #endif // APPLE_OSX_mDNSResponder
7488
7489 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7490 return ret;
7491 }
7492
7493 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7494 {
7495 mDNSs32 val = 0;
7496 GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7497 return val != 0 ? mDNStrue : mDNSfalse;
7498 }
7499
7500 #if APPLE_OSX_mDNSResponder
7501 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7502 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7503 // the RR relay.
7504 //
7505 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7506 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7507 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7508 // depend on their associated SRV record and therefore will be deregistered together in a
7509 // single update with the SRV record.
7510 //
7511 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7512 // its presence shouldn't delay sleep.
7513 //
7514 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7515 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7516 //
7517 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7518 mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
7519 {
7520 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7521
7522 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7523 {
7524 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7525 return mDNSfalse;
7526 }
7527
7528 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7529 {
7530 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7531 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7532 {
7533 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7534 if (info && info->AutoTunnel)
7535 {
7536 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7537 return mDNSfalse;
7538 }
7539 }
7540 }
7541
7542 return mDNStrue;
7543 }
7544
7545 // Caller must hold the lock
7546 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7547 {
7548 DomainAuthInfo *info;
7549 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7550 // deregister the record, and the MemFree callback won't re-register.
7551 m->AutoTunnelRelayAddr = zerov6Addr;
7552 for (info = m->AuthInfoList; info; info = info->next)
7553 if (info->AutoTunnel)
7554 UpdateAutoTunnel6Record(m, info);
7555 }
7556
7557 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7558 {
7559 struct ifaddrs *ifa;
7560 struct ifaddrs *ifaddrs;
7561 mDNSAddr addr;
7562
7563 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7564
7565 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7566
7567 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7568 {
7569 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7570 continue;
7571 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7572 continue;
7573 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7574 {
7575 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7576 continue;
7577 }
7578 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7579 {
7580 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7581 break;
7582 }
7583 }
7584 freeifaddrs(ifaddrs);
7585 return ifa != NULL;
7586 }
7587
7588 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7589 {
7590 mDNSv6Addr retVal;
7591 struct addrinfo hints;
7592 struct addrinfo *res0;
7593
7594 memset(&hints, 0, sizeof(hints));
7595 hints.ai_family = AF_INET6;
7596 hints.ai_flags = AI_NUMERICHOST;
7597
7598 int err = getaddrinfo(buf, NULL, &hints, &res0);
7599 if (err)
7600 return zerov6Addr;
7601
7602 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7603
7604 freeaddrinfo(res0);
7605
7606 return retVal;
7607 }
7608
7609 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7610 {
7611 SCDynamicStoreRef store = NULL;
7612 CFDictionaryRef connd = NULL;
7613 CFDictionaryRef BTMMDict = NULL;
7614
7615 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL);
7616 if (!store)
7617 {
7618 LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7619 goto end;
7620 }
7621
7622 connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
7623 if (!connd)
7624 {
7625 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7626 goto end;
7627 }
7628
7629 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7630 if (!BTMMDict)
7631 {
7632 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7633 goto end;
7634 }
7635
7636 // Non-dictionary is treated as non-existent dictionary
7637 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7638 {
7639 BTMMDict = NULL;
7640 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7641 goto end;
7642 }
7643
7644 CFRetain(BTMMDict);
7645
7646 end:
7647 if (connd) CFRelease(connd);
7648 if (store) CFRelease(store);
7649
7650 return BTMMDict;
7651 }
7652
7653 #define MAX_IPV6_TEXTUAL 40
7654
7655 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7656 {
7657 mDNSv6Addr retVal = zerov6Addr;
7658 CFTypeRef string = NULL;
7659 char ifname[IFNAMSIZ];
7660 char address[MAX_IPV6_TEXTUAL];
7661
7662 if (!BTMMDict)
7663 return zerov6Addr;
7664
7665 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7666 {
7667 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7668 return zerov6Addr;
7669 }
7670
7671 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7672 {
7673 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7674 return zerov6Addr;
7675 }
7676
7677 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7678 {
7679 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7680 return zerov6Addr;
7681 }
7682
7683 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7684 {
7685 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7686 return zerov6Addr;
7687 }
7688
7689 retVal = IPv6AddressFromString(address);
7690 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7691
7692 if (mDNSIPv6AddressIsZero(retVal))
7693 return zerov6Addr;
7694
7695 if (!IPv6AddressIsOnInterface(retVal, ifname))
7696 {
7697 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7698 return zerov6Addr;
7699 }
7700
7701 return retVal;
7702 }
7703
7704 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7705 {
7706 CFTypeRef zones = NULL;
7707
7708 if (!BTMMDict)
7709 return NULL;
7710
7711 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7712 {
7713 LogInfo("CopyBTMMZones: Zones key does not exist");
7714 return NULL;
7715 }
7716
7717 return zones;
7718 }
7719
7720 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7721 {
7722 mDNSv6Addr addr = zerov6Addr;
7723 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7724 CFStringRef domain = NULL;
7725 CFTypeRef theZone = NULL;
7726
7727 if (!zones)
7728 return addr;
7729
7730 ConvertDomainNameToCString(&info->domain, buffer);
7731 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7732 if (!domain)
7733 return addr;
7734
7735 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7736 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7737
7738 CFRelease(domain);
7739
7740 return addr;
7741 }
7742
7743 mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
7744 {
7745 DomainAuthInfo* info;
7746 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7747 mDNSv6Addr newAddr;
7748
7749 for (info = m->AuthInfoList; info; info = info->next)
7750 {
7751 if (!info->AutoTunnel)
7752 continue;
7753
7754 newAddr = ParseBackToMyMacZone(zones, info);
7755
7756 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7757 continue;
7758
7759 info->AutoTunnelInnerAddress = newAddr;
7760 DeregisterAutoTunnelHostRecord(m, info);
7761 UpdateAutoTunnelHostRecord(m, info);
7762 UpdateAutoTunnelDomainStatus(m, info);
7763 }
7764 }
7765
7766 // MUST be called holding the lock
7767 mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
7768 {
7769 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7770 if (!dict)
7771 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7772 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7773
7774 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7775
7776 SetupBackToMyMacInnerAddresses(m, dict);
7777
7778 if (dict) CFRelease(dict);
7779
7780 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7781 {
7782 m->AutoTunnelRelayAddr = relayAddr;
7783
7784 DomainAuthInfo* info;
7785 for (info = m->AuthInfoList; info; info = info->next)
7786 if (info->AutoTunnel)
7787 {
7788 DeregisterAutoTunnel6Record(m, info);
7789 UpdateAutoTunnel6Record(m, info);
7790 UpdateAutoTunnelDomainStatus(m, info);
7791 }
7792
7793 // Determine whether we need racoon to accept incoming connections
7794 UpdateAnonymousRacoonConfig(m);
7795 }
7796
7797 // If awacsd crashes or exits for some reason, restart it
7798 UpdateBTMMRelayConnection(m);
7799 }
7800 #endif /* APPLE_OSX_mDNSResponder */
7801
7802 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7803 {
7804 DNSServer *s;
7805 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7806 for (s = m->DNSServers; s; s = s->next)
7807 {
7808 if (s->addr.ip.v4.b[0] == 17)
7809 {
7810 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7811 return mDNStrue;
7812 }
7813 }
7814 return mDNSfalse;
7815 }
7816
7817 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
7818 {
7819 LogInfo("*** Network Configuration Change *** (%d)%s",
7820 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
7821 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
7822 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7823 mDNSs32 utc = mDNSPlatformUTC();
7824 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7825 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7826 MarkAllInterfacesInactive(m, utc);
7827 UpdateInterfaceList(m, utc);
7828 ClearInactiveInterfaces(m, utc);
7829 SetupActiveInterfaces(m, utc);
7830
7831 #if APPLE_OSX_mDNSResponder
7832
7833 mDNS_Lock(m);
7834 ProcessConndConfigChanges(m);
7835 mDNS_Unlock(m);
7836
7837 // Scan to find client tunnels whose questions have completed,
7838 // but whose local inner/outer addresses have changed since the tunnel was set up
7839 ClientTunnel *p;
7840 for (p = m->TunnelClients; p; p = p->next)
7841 if (p->q.ThisQInterval < 0)
7842 {
7843 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7844 if (!info)
7845 {
7846 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7847 AutoTunnelSetKeys(p, mDNSfalse);
7848 }
7849 else
7850 {
7851 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7852
7853 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7854 {
7855 mDNSAddr tmpSrc = zeroAddr;
7856 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7857 tmpDst.ip.v4 = p->rmt_outer;
7858 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7859 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7860 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7861 {
7862 AutoTunnelSetKeys(p, mDNSfalse);
7863 p->loc_inner = inner;
7864 p->loc_outer = tmpSrc.ip.v4;
7865 AutoTunnelSetKeys(p, mDNStrue);
7866 }
7867 }
7868 else
7869 {
7870 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7871 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7872 {
7873 AutoTunnelSetKeys(p, mDNSfalse);
7874 p->loc_inner = inner;
7875 p->loc_outer6 = m->AutoTunnelRelayAddr;
7876 AutoTunnelSetKeys(p, mDNStrue);
7877 }
7878 }
7879 }
7880 }
7881
7882 SetSPS(m);
7883
7884 NetworkInterfaceInfoOSX *i;
7885 for (i = m->p->InterfaceList; i; i = i->next)
7886 {
7887 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7888 {
7889 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
7890 }
7891 else // else, we're Sleep Proxy Server; open BPF fds
7892 {
7893 if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
7894 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
7895 }
7896 }
7897
7898 #endif // APPLE_OSX_mDNSResponder
7899
7900 uDNS_SetupDNSConfig(m);
7901 mDNS_ConfigChanged(m);
7902
7903 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7904 {
7905 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7906 LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7907 UpdateDebugState();
7908 }
7909
7910 }
7911
7912 // Called with KQueueLock & mDNS lock
7913 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
7914 {
7915 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
7916 {
7917 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
7918 LogInfo("SetNetworkChanged: scheduling in %d msec", delay);
7919 }
7920 }
7921
7922 // Called with KQueueLock & mDNS lock
7923 mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
7924 {
7925 // If it's not set or it needs to happen sooner than when it's currently set
7926 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7927 {
7928 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7929 LogInfo("SetKeyChainTimer: %d", delay);
7930 }
7931 }
7932
7933 // Copy the fourth slash-delimited element from either:
7934 // State:/Network/Interface/<bsdname>/IPv4
7935 // or
7936 // Setup:/Network/Service/<servicename>/Interface
7937 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7938 {
7939 CFArrayRef a;
7940 CFStringRef name = NULL;
7941
7942 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7943 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7944 if (a != NULL) CFRelease(a);
7945
7946 return name;
7947 }
7948
7949 // Whether a key from a network change notification corresponds to
7950 // an IP service that is explicitly configured for IPv4 Link Local
7951 mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7952 {
7953 SCDynamicStoreRef store = NULL;
7954 CFDictionaryRef dict = NULL;
7955 CFMutableArrayRef a;
7956 const void **keys = NULL, **vals = NULL;
7957 CFStringRef pattern = NULL;
7958 int i, ic, j, jc;
7959 mDNSBool found = mDNSfalse;
7960
7961 jc = CFArrayGetCount(inkeys);
7962 if (!jc) goto done;
7963
7964 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
7965 if (store == NULL) goto done;
7966
7967 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7968 if (a == NULL) goto done;
7969
7970 // Setup:/Network/Service/[^/]+/Interface
7971 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7972 if (pattern == NULL) goto done;
7973 CFArrayAppendValue(a, pattern);
7974 CFRelease(pattern);
7975
7976 // Setup:/Network/Service/[^/]+/IPv4
7977 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7978 if (pattern == NULL) goto done;
7979 CFArrayAppendValue(a, pattern);
7980 CFRelease(pattern);
7981
7982 dict = SCDynamicStoreCopyMultiple(store, NULL, a);
7983 CFRelease(a);
7984
7985 if (!dict)
7986 {
7987 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7988 goto done;
7989 }
7990
7991 ic = CFDictionaryGetCount(dict);
7992 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7993 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7994 CFDictionaryGetKeysAndValues(dict, keys, vals);
7995
7996 for (j = 0; j < jc && !found; j++)
7997 {
7998 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7999 CFStringRef ifname = NULL;
8000
8001 char buf[256];
8002
8003 // It would be nice to use a regex here
8004 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
8005
8006 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
8007 if (mDNS_LoggingEnabled)
8008 {
8009 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8010 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
8011 }
8012
8013 for (i = 0; i < ic; i++)
8014 {
8015 CFDictionaryRef ipv4dict;
8016 CFStringRef name;
8017 CFStringRef serviceid;
8018 CFStringRef configmethod;
8019
8020 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
8021
8022 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
8023
8024 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
8025
8026 if (!CFEqual(ifname, name)) continue;
8027
8028 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
8029 if (mDNS_LoggingEnabled)
8030 {
8031 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8032 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
8033 }
8034
8035 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
8036 CFRelease(serviceid);
8037 if (pattern == NULL) continue;
8038
8039 ipv4dict = CFDictionaryGetValue(dict, pattern);
8040 CFRelease(pattern);
8041 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
8042
8043 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
8044 if (!configmethod) continue;
8045
8046 if (mDNS_LoggingEnabled)
8047 {
8048 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8049 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
8050 }
8051
8052 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
8053 }
8054
8055 CFRelease(ifname);
8056 }
8057
8058 done:
8059 if (vals != NULL) mDNSPlatformMemFree(vals);
8060 if (keys != NULL) mDNSPlatformMemFree(keys);
8061 if (dict != NULL) CFRelease(dict);
8062 if (store != NULL) CFRelease(store);
8063
8064 return found;
8065 }
8066
8067 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
8068 {
8069 (void)store; // Parameter not used
8070 mDNSBool changeNow = mDNSfalse;
8071 mDNS *const m = (mDNS *const)context;
8072 KQueueLock(m);
8073 mDNS_Lock(m);
8074
8075 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
8076
8077 int c = CFArrayGetCount(changedKeys); // Count changes
8078 CFRange range = { 0, c };
8079 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
8080 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
8081 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
8082 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
8083 if (c && c - c1 - c2 - c3 - c4 == 0)
8084 delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
8085
8086 // Do immediate network changed processing for "p2p*" interfaces and
8087 // for interfaces with the IFEF_DIRECTLINK flag set.
8088 {
8089 CFArrayRef labels;
8090 CFIndex n;
8091 for (int i = 0; i < c; i++)
8092 {
8093 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
8094
8095 // Only look at keys with prefix "State:/Network/Interface/"
8096 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
8097 continue;
8098
8099 // And suffix "IPv6" or "IPv4".
8100 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
8101 continue;
8102
8103 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
8104 if (labels == NULL)
8105 break;
8106 n = CFArrayGetCount(labels);
8107
8108 // Interface changes will have keys of the form:
8109 // State:/Network/Interface/<interfaceName>/IPv6
8110 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
8111 if (n == 5)
8112 {
8113 char buf[256];
8114
8115 // The 4th label (index = 3) should be the interface name.
8116 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
8117 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK)))
8118 {
8119 LogInfo("NetworkChanged: interface %s, not delaying network change", buf);
8120 changeNow = mDNStrue;
8121 CFRelease(labels);
8122 break;
8123 }
8124 }
8125 CFRelease(labels);
8126 }
8127 }
8128
8129 mDNSBool btmmChanged = CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac);
8130 if (btmmChanged) delay = 0;
8131
8132 if (mDNS_LoggingEnabled)
8133 {
8134 int i;
8135 for (i=0; i<c; i++)
8136 {
8137 char buf[256];
8138 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8139 LogInfo("*** NetworkChanged SC key: %s", buf);
8140 }
8141 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
8142 c, c>1 ? "s" : "",
8143 c1 ? "(Local Hostname) " : "",
8144 c2 ? "(Computer Name) " : "",
8145 c3 ? "(DynamicDNS) " : "",
8146 c4 ? "(DNS) " : "",
8147 changeNow ? 0 : delay);
8148 }
8149
8150 if (!changeNow)
8151 SetNetworkChanged(m, delay);
8152
8153 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
8154 // so in order for secure updates to be made to the server, make sure to read the keychain and
8155 // setup the DomainAuthInfo before handing the network change.
8156 // If we don't, then we will first try to register services in the clear, then later setup the
8157 // DomainAuthInfo, which is incorrect.
8158 if (c3 || btmmChanged)
8159 SetKeyChainTimer(m, delay);
8160
8161 mDNS_Unlock(m);
8162
8163 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
8164 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
8165 if (c4 || ChangedKeysHaveIPv4LL(changedKeys) || changeNow) mDNSMacOSXNetworkChanged(m);
8166
8167 KQueueUnlock(m, "NetworkChanged");
8168 }
8169
8170 #if APPLE_OSX_mDNSResponder
8171 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
8172 {
8173 (void)context;
8174 char buf[IFNAMSIZ];
8175
8176 CFStringRef ifnameStr = (CFStringRef)key;
8177 CFArrayRef array = (CFArrayRef)value;
8178 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
8179 buf[0] = 0;
8180
8181 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
8182 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
8183 }
8184 #endif
8185
8186 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
8187 {
8188 mDNS *const m = (mDNS *const)info;
8189 (void)store;
8190
8191 LogInfo("DynamicStoreReconnected: Reconnected");
8192
8193 // State:/Network/MulticastDNS
8194 SetLocalDomains();
8195
8196 // State:/Network/DynamicDNS
8197 if (m->FQDN.c[0])
8198 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
8199
8200 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
8201 // as we receive network change notifications and thus not necessary. But we leave it here
8202 // so that if things are done differently in the future, this code still works.
8203
8204 // State:/Network/PrivateDNS
8205 if (privateDnsArray)
8206 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
8207
8208 #if APPLE_OSX_mDNSResponder
8209 mDNS_Lock(m);
8210 // State:/Network/BackToMyMac
8211 UpdateAutoTunnelDomainStatuses(m);
8212 mDNS_Unlock(m);
8213
8214 // State:/Network/Interface/en0/SleepProxyServers
8215 if (spsStatusDict)
8216 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
8217 #endif
8218 }
8219
8220 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8221 {
8222 mStatus err = -1;
8223 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8224 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8225 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8226 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8227 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8228 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8229
8230 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8231 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8232
8233 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8234 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8235 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8236 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8237 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8238 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8239 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8240 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
8241 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8242 CFArrayAppendValue(patterns, pattern1);
8243 CFArrayAppendValue(patterns, pattern2);
8244 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8245 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8246 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8247
8248 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8249 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8250 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8251 #else
8252 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8253 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8254 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8255 #endif
8256 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8257 m->p->Store = store;
8258 err = 0;
8259 goto exit;
8260
8261 error:
8262 if (store) CFRelease(store);
8263
8264 exit:
8265 if (patterns) CFRelease(patterns);
8266 if (pattern2) CFRelease(pattern2);
8267 if (pattern1) CFRelease(pattern1);
8268 if (keys) CFRelease(keys);
8269
8270 return(err);
8271 }
8272
8273 #if 0 // <rdar://problem/6751656>
8274 mDNSlocal void PMChanged(void *context)
8275 {
8276 mDNS *const m = (mDNS *const)context;
8277
8278 KQueueLock(m);
8279 mDNS_Lock(m);
8280
8281 LogSPS("PMChanged");
8282
8283 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8284
8285 mDNS_Unlock(m);
8286 KQueueUnlock(m, "PMChanged");
8287 }
8288
8289 mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
8290 {
8291 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
8292 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
8293
8294 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
8295
8296 return mStatus_NoError;
8297 }
8298 #endif
8299
8300 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8301
8302 mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
8303 {
8304 AuthRecord *rr;
8305 pfArray_t portArray;
8306 pfArray_t protocolArray;
8307 uint32_t count = 0;
8308
8309 for (rr = m->ResourceRecords; rr; rr=rr->next)
8310 {
8311 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8312 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8313 {
8314 const mDNSu8 *p;
8315
8316 if (count >= PFPortArraySize)
8317 {
8318 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8319 continue;
8320 }
8321
8322 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8323 {
8324 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8325 continue;
8326 }
8327
8328 LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8329
8330 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8331
8332 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8333 p = rr->resrec.name->c;
8334
8335 // Skip to App Protocol
8336 if (p[0]) p += 1 + p[0];
8337
8338 // Skip to Transport Protocol
8339 if (p[0]) p += 1 + p[0];
8340
8341 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP;
8342 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP;
8343 else
8344 {
8345 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8346 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8347 return;
8348 }
8349 count++;
8350 }
8351 }
8352 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8353 }
8354
8355 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8356 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8357 {
8358 mDNS *const m = &mDNSStorage;
8359
8360 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8361 while (intf)
8362 {
8363 if (strncmp(intf->ifname, "p2p", 3) == 0)
8364 {
8365 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8366 mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
8367 break;
8368 }
8369 intf = GetFirstActiveInterface(intf->next);
8370 }
8371 }
8372
8373 #else // !TARGET_OS_EMBEDDED
8374
8375 // Currently no packet filter setup required on embedded platforms.
8376 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8377 {
8378 (void) excludeRecord; // unused
8379 }
8380
8381 #endif // !TARGET_OS_EMBEDDED
8382
8383 // Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
8384 // marked to include the AWDL interface.
8385 mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
8386 {
8387 char ifname[IFNAMSIZ];
8388 mDNSu32 interfaceIndex;
8389 DNSQuestion *q;
8390 AuthRecord *rr;
8391 NetworkInterfaceInfoOSX *infoOSX;
8392 mDNSInterfaceID InterfaceID;
8393
8394 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8395 interfaceIndex = if_nametoindex(ifname);
8396
8397 if (!interfaceIndex)
8398 {
8399 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8400 return;
8401 }
8402
8403 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8404 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
8405
8406 // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing
8407 // when it is first brought up.
8408 if (!infoOSX)
8409 {
8410 LogInfo("newMasterElected: interface not yet active");
8411 return;
8412 }
8413 InterfaceID = infoOSX->ifinfo.InterfaceID;
8414
8415 for (q = m->Questions; q; q=q->next)
8416 {
8417 if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
8418 || q->InterfaceID == InterfaceID)
8419 {
8420 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
8421 mDNSCoreRestartQuestion(m, q);
8422 }
8423 }
8424
8425 for (rr = m->ResourceRecords; rr; rr=rr->next)
8426 {
8427 if ((!rr->resrec.InterfaceID
8428 && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
8429 || rr->resrec.InterfaceID == InterfaceID)
8430 {
8431 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
8432 mDNSCoreRestartRegistration(m, rr, -1);
8433 }
8434 }
8435 }
8436
8437 // An ssth array of all zeroes indicates the peer has no services registered.
8438 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8439 {
8440 int i;
8441 int *intp = (int *) op->ssth;
8442
8443 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8444 // it's not, print an error message and return false so that
8445 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8446 // is received.
8447 if (MAX_SSTH_SIZE % sizeof(int))
8448 {
8449 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8450 return mDNSfalse;
8451 }
8452
8453 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8454 {
8455 if (*intp)
8456 return mDNSfalse;
8457 }
8458 return mDNStrue;
8459 }
8460
8461 // mDNS_Reconfirm_internal() adds 33% to this interval, so the records should
8462 // be removed in 4 seconds.
8463 #define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3)
8464
8465 // Mark records from this peer for deletion from the cache.
8466 mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap)
8467 {
8468 mDNSu32 slot;
8469 CacheGroup *cg;
8470 CacheRecord *cr;
8471 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex);
8472
8473 if (!InterfaceID)
8474 {
8475 LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex);
8476 return;
8477 }
8478
8479 FORALL_CACHERECORDS(slot, cg, cr)
8480 {
8481 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8482 {
8483 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8484 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8485 mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime);
8486 }
8487 }
8488 }
8489
8490 // Handle KEV_DL_NODE_PRESENCE event.
8491 mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
8492 {
8493 char buf[INET6_ADDRSTRLEN];
8494 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8495
8496 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8497 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
8498 else
8499 LogInfo("nodePresence: inet_ntop() error");
8500
8501 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8502 // all zeroes when a node is present and has no services registered.
8503 if (allZeroSSTH(op))
8504 {
8505 mDNSAddr peerAddr;
8506
8507 peerAddr.type = mDNSAddrType_IPv6;
8508 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8509
8510 LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer");
8511 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8512 }
8513 }
8514
8515 // Handle KEV_DL_NODE_ABSENCE event.
8516 mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
8517 {
8518 mDNSAddr peerAddr;
8519 char buf[INET6_ADDRSTRLEN];
8520
8521 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8522 LogInfo("nodeAbsence: IPv6 address: %s", buf);
8523 else
8524 LogInfo("nodeAbsence: inet_ntop() error");
8525
8526 peerAddr.type = mDNSAddrType_IPv6;
8527 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8528
8529 LogInfo("nodeAbsence: delete cached records from this peer");
8530 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8531 }
8532
8533 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
8534 {
8535 mDNS *const m = (mDNS *const)context;
8536
8537 mDNS_Lock(m);
8538
8539 struct { struct kern_event_msg k; char extra[256]; } msg;
8540 int bytes = recv(s1, &msg, sizeof(msg), 0);
8541 if (bytes < 0)
8542 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8543 else
8544 {
8545 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8546 bytes, msg.k.total_size,
8547 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8548 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8549 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8550 msg.k.id, msg.k.event_code,
8551 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8552 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8553 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8554 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8555 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8556 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8557 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8558 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8559 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8560 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8561 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8562 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8563 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8564 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8565 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8566 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8567 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8568 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8569 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8570 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8571 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8572 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8573 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8574 "?");
8575
8576 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8577 nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
8578
8579 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8580 nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
8581
8582 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8583 newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
8584
8585 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8586 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8587 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8588 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8589 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8590
8591 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8592 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8593
8594 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8595
8596 // For p2p interfaces, need to open the advertised service port in the firewall.
8597 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8598 {
8599 struct net_event_data * p;
8600 p = (struct net_event_data *) &msg.k.event_data;
8601
8602 if (strncmp(p->if_name, "p2p", 3) == 0)
8603 {
8604 char ifname[IFNAMSIZ];
8605 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8606
8607 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8608
8609 mDNSSetPacketFilterRules(m, ifname, NULL);
8610 }
8611 }
8612
8613 // For p2p interfaces, need to clear the firewall rules on interface detach
8614 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8615 {
8616 struct net_event_data * p;
8617 p = (struct net_event_data *) &msg.k.event_data;
8618
8619 if (strncmp(p->if_name, "p2p", 3) == 0)
8620 {
8621 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8622 char ifname[IFNAMSIZ];
8623 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8624
8625 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8626
8627 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8628 }
8629 }
8630 #endif // !TARGET_OS_EMBEDDED
8631
8632 }
8633
8634 mDNS_Unlock(m);
8635 }
8636
8637 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8638 {
8639 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8640 if (m->p->SysEventNotifier < 0)
8641 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8642
8643 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8644 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8645 if (err < 0)
8646 {
8647 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8648 close(m->p->SysEventNotifier);
8649 m->p->SysEventNotifier = -1;
8650 return(mStatus_UnknownErr);
8651 }
8652
8653 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8654 m->p->SysEventKQueue.KQcontext = m;
8655 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8656 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8657
8658 return(mStatus_NoError);
8659 }
8660
8661 #ifndef NO_SECURITYFRAMEWORK
8662 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8663 {
8664 LogInfo("*** Keychain Changed ***");
8665 mDNS *const m = (mDNS *const)context;
8666 SecKeychainRef skc;
8667 OSStatus err = SecKeychainCopyDefault(&skc);
8668 if (!err)
8669 {
8670 if (info->keychain == skc)
8671 {
8672 // 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
8673 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8674 if (!relevant)
8675 {
8676 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8677 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8678 SecKeychainAttributeList *a = NULL;
8679 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8680 if (!err)
8681 {
8682 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8683 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
8684 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
8685 SecKeychainItemFreeAttributesAndData(a, NULL);
8686 }
8687 }
8688 if (relevant)
8689 {
8690 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8691 keychainEvent,
8692 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8693 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8694 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8695 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8696 KQueueLock(m);
8697 mDNS_Lock(m);
8698
8699 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8700 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8701 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8702 //
8703 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8704 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8705 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8706 // condition between the RegistrationDomain and the DomainAuthInfo.
8707 //
8708 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8709 // the timer here, as it will not get set by NetworkChanged().
8710 SetKeyChainTimer(m, mDNSPlatformOneSecond);
8711
8712 mDNS_Unlock(m);
8713 KQueueUnlock(m, "KeychainChanged");
8714 }
8715 }
8716 CFRelease(skc);
8717 }
8718
8719 return 0;
8720 }
8721 #endif
8722
8723 mDNSlocal void PowerOn(mDNS *const m)
8724 {
8725 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8726 if (m->p->WakeAtUTC)
8727 {
8728 long utc = mDNSPlatformUTC();
8729 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8730 if (m->p->WakeAtUTC - utc > 30)
8731 {
8732 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8733 }
8734 else if (utc - m->p->WakeAtUTC > 30)
8735 {
8736 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8737 }
8738 else if (IsAppleTV())
8739 {
8740 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8741 }
8742 else
8743 {
8744 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8745 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8746 }
8747 }
8748 }
8749
8750 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8751 {
8752 mDNS *const m = (mDNS *const)refcon;
8753 KQueueLock(m);
8754 (void)service; // Parameter not used
8755 debugf("PowerChanged %X %lX", messageType, messageArgument);
8756
8757 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8758 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8759
8760 switch(messageType)
8761 {
8762 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8763 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8764 mDNSCoreMachineSleep(m, true);
8765 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8766 break;
8767 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8768 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
8769 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8770 mDNSCoreMachineSleep(m, true);
8771 break;
8772 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8773 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8774 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8775 if (m->SleepState)
8776 {
8777 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8778 PowerOn(m);
8779 }
8780 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8781 // the System Configuration Framework "network changed" event that we expect
8782 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8783 mDNS_Lock(m);
8784 if (!m->p->NetworkChanged ||
8785 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
8786 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
8787 mDNS_Unlock(m);
8788
8789 break;
8790 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8791 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8792
8793 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8794 if (m->SleepState != SleepState_Sleeping)
8795 {
8796 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8797 m->SleepState = SleepState_Sleeping;
8798 mDNSMacOSXNetworkChanged(m);
8799 }
8800 PowerOn(m);
8801 break;
8802 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8803 }
8804
8805 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
8806 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8807
8808 KQueueUnlock(m, "PowerChanged Sleep/Wake");
8809 }
8810
8811 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8812 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8813 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8814 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8815 {
8816 mDNS *const m = (mDNS *const)refcon;
8817 KQueueLock(m);
8818 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8819 connection, token, eventDescriptor,
8820 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8821 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8822 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8823 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8824 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8825
8826 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8827 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8828
8829 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8830 {
8831 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8832 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8833 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8834 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8835 if (m->SleepLimit)
8836 {
8837 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8838 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8839 m->SleepLimit = 0;
8840 }
8841 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8842 // If the network notifications have already come before we got the wakeup, we ignored them and
8843 // in case we get no more, we need to trigger one.
8844 mDNS_Lock(m);
8845 SetNetworkChanged(m, 2 * mDNSPlatformOneSecond);
8846 mDNS_Unlock(m);
8847 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8848 if (m->SleepState != SleepState_Awake) PowerOn(m);
8849 IOPMConnectionAcknowledgeEvent(connection, token);
8850 }
8851 else
8852 {
8853 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8854 // we should hear nothing more until we're told that the CPU has started executing again.
8855 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8856 //sleep(5);
8857 //mDNSMacOSXNetworkChanged(m);
8858 mDNSCoreMachineSleep(m, true);
8859 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8860 m->p->SleepCookie = token;
8861 }
8862
8863 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
8864 }
8865 #endif
8866
8867 #if COMPILER_LIKES_PRAGMA_MARK
8868 #pragma mark -
8869 #pragma mark - /etc/hosts support
8870 #endif
8871
8872 // Implementation Notes
8873 //
8874 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8875 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8876 // them into a hash table. The implementation need to be able to do the following things efficiently
8877 //
8878 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8879 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8880 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8881 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8882 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8883 // not a duplicate
8884 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8885 //
8886 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8887 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8888 // of the core layer which does all of the above very efficiently
8889
8890 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8891
8892 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8893 {
8894 (void)m; // unused
8895 (void)rr;
8896 (void)result;
8897 if (result == mStatus_MemFree)
8898 {
8899 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8900 freeL("etchosts", rr);
8901 }
8902 }
8903
8904 // Returns true on success and false on failure
8905 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8906 {
8907 AuthRecord *rr;
8908 mDNSu32 slot;
8909 mDNSu32 namehash;
8910 AuthGroup *ag;
8911 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8912 mDNSu16 rrtype;
8913
8914 if (!domain)
8915 {
8916 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8917 return mDNSfalse;
8918 }
8919 if (!sa && !cname)
8920 {
8921 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8922 return mDNSfalse;
8923 }
8924
8925 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8926 {
8927 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8928 return mDNSfalse;
8929 }
8930
8931
8932 if (ifname)
8933 {
8934 mDNSu32 ifindex = if_nametoindex(ifname);
8935 if (!ifindex)
8936 {
8937 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8938 return mDNSfalse;
8939 }
8940 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8941 }
8942
8943 if (sa)
8944 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8945 else
8946 rrtype = kDNSType_CNAME;
8947
8948 // Check for duplicates. See whether we parsed an entry before like this ?
8949 slot = AuthHashSlot(domain);
8950 namehash = DomainNameHashValue(domain);
8951 ag = AuthGroupForName(auth, slot, namehash, domain);
8952 if (ag)
8953 {
8954 rr = ag->members;
8955 while (rr)
8956 {
8957 if (rr->resrec.rrtype == rrtype)
8958 {
8959 if (rrtype == kDNSType_A)
8960 {
8961 mDNSv4Addr ip;
8962 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8963 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8964 {
8965 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8966 return mDNSfalse;
8967 }
8968 }
8969 else if (rrtype == kDNSType_AAAA)
8970 {
8971 mDNSv6Addr ip6;
8972 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8973 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8974 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8975 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8976 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8977 {
8978 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8979 return mDNSfalse;
8980 }
8981 }
8982 else if (rrtype == kDNSType_CNAME)
8983 {
8984 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8985 {
8986 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8987 return mDNSfalse;
8988 }
8989 }
8990 }
8991 rr = rr->next;
8992 }
8993 }
8994 rr= mallocL("etchosts", sizeof(*rr));
8995 if (rr == NULL) return mDNSfalse;
8996 mDNSPlatformMemZero(rr, sizeof(*rr));
8997 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8998 AssignDomainName(&rr->namestorage, domain);
8999
9000 if (sa)
9001 {
9002 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
9003 if (sa->sa_family == AF_INET)
9004 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
9005 else
9006 {
9007 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
9008 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
9009 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
9010 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
9011 }
9012 }
9013 else
9014 {
9015 rr->resrec.rdlength = DomainNameLength(cname);
9016 rr->resrec.rdata->u.name.c[0] = 0;
9017 AssignDomainName(&rr->resrec.rdata->u.name, cname);
9018 }
9019 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9020 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9021 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
9022 InsertAuthRecord(m, auth, rr);
9023 return mDNStrue;
9024 }
9025
9026 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
9027 {
9028 int i;
9029
9030 *name = NULL;
9031 for (i = start; i < length; i++)
9032 {
9033 if (buffer[i] == '#')
9034 return -1;
9035 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
9036 {
9037 *name = &buffer[i];
9038
9039 // Found the start of a name, find the end and null terminate
9040 for (i++; i < length; i++)
9041 {
9042 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9043 {
9044 buffer[i] = 0;
9045 break;
9046 }
9047 }
9048 return i;
9049 }
9050 }
9051 return -1;
9052 }
9053
9054 mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
9055 {
9056 int i;
9057 int ifStart = 0;
9058 char *ifname = NULL;
9059 domainname name1d;
9060 domainname name2d;
9061 char *name1;
9062 char *name2;
9063 int aliasIndex;
9064
9065 //Ignore leading whitespaces and tabs
9066 while (*buffer == ' ' || *buffer == '\t')
9067 {
9068 buffer++;
9069 length--;
9070 }
9071
9072 // Find the end of the address string
9073 for (i = 0; i < length; i++)
9074 {
9075 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
9076 {
9077 if (buffer[i] == '%')
9078 ifStart = i + 1;
9079 buffer[i] = 0;
9080 break;
9081 }
9082 }
9083
9084 // Convert the address string to an address
9085 struct addrinfo hints;
9086 bzero(&hints, sizeof(hints));
9087 hints.ai_flags = AI_NUMERICHOST;
9088 struct addrinfo *gairesults = NULL;
9089 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
9090 {
9091 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
9092 return;
9093 }
9094
9095 if (ifStart)
9096 {
9097 // Parse the interface
9098 ifname = &buffer[ifStart];
9099 for (i = ifStart + 1; i < length; i++)
9100 {
9101 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9102 {
9103 buffer[i] = 0;
9104 break;
9105 }
9106 }
9107 }
9108
9109 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
9110 if (i == length)
9111 {
9112 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
9113 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
9114 {
9115 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9116 freeaddrinfo(gairesults);
9117 return;
9118 }
9119 mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
9120 }
9121 else if (i != -1)
9122 {
9123 domainname first;
9124 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
9125 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
9126 // doing the right thing.
9127 if (!MakeDomainNameFromDNSNameString(&first, name1))
9128 {
9129 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9130 freeaddrinfo(gairesults);
9131 return;
9132 }
9133 // If the /etc/hosts has an entry like this
9134 //
9135 // 1.2.3.4 sun star bright
9136 //
9137 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
9138 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
9139 //
9140 // To achieve this, we need to add the entry like this:
9141 //
9142 // star CNAME bright
9143 // bright CNAME sun
9144 // sun A 1.2.3.4
9145 //
9146 // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
9147 // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
9148 // entry and the first entry. Finally, we add the Address (A/AAAA) record.
9149 aliasIndex = 0;
9150 while (i <= length)
9151 {
9152 // Parse a name. If there are no names, we need to know whether we
9153 // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
9154 // add a CNAME with the last name and the first name. Otherwise, this
9155 // is same as the common case above where the line has just one name
9156 // but with trailing white spaces.
9157 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
9158 if (name2)
9159 {
9160 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
9161 {
9162 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
9163 freeaddrinfo(gairesults);
9164 return;
9165 }
9166 aliasIndex++;
9167 }
9168 else if (!aliasIndex)
9169 {
9170 // We have never parsed any aliases. This case happens if there
9171 // is just one name and some extra white spaces at the end.
9172 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
9173 break;
9174 }
9175 else
9176 {
9177 // We have parsed at least one alias before and we reached the end of the line.
9178 // Setup a CNAME for the last name with "first" name as its RDATA
9179 name2d.c[0] = 0;
9180 AssignDomainName(&name2d, &first);
9181 }
9182
9183 // Don't add a CNAME for the first alias we parse (see the example above).
9184 // As we parse more, we might discover that there are no more aliases, in
9185 // which case we would have set "name2d" to "first" above. We need to add
9186 // the CNAME in that case.
9187
9188 if (aliasIndex > 1 || SameDomainName(&name2d, &first))
9189 {
9190 // Ignore if it points to itself
9191 if (!SameDomainName(&name1d, &name2d))
9192 {
9193 if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth))
9194 {
9195 freeaddrinfo(gairesults);
9196 return;
9197 }
9198 }
9199 else
9200 LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c);
9201 }
9202
9203 // If we have already wrapped around, we just need to add the A/AAAA record alone
9204 // which is done below
9205 if (SameDomainName(&name2d, &first)) break;
9206
9207 // Remember the current name so that we can set the CNAME record if we parse one
9208 // more name
9209 name1d.c[0] = 0;
9210 AssignDomainName(&name1d, &name2d);
9211 }
9212 // Added all the CNAMEs if any, add the "A/AAAA" record
9213 mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
9214 }
9215 freeaddrinfo(gairesults);
9216 }
9217
9218 mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
9219 {
9220 mDNSBool good;
9221 char buf[ETCHOSTS_BUFSIZE];
9222 ssize_t len;
9223 FILE *fp;
9224
9225 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
9226
9227 fp = fopen("/etc/hosts", "r");
9228 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
9229
9230 while (1)
9231 {
9232 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
9233 if (!good) break;
9234
9235 // skip comment and empty lines
9236 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
9237 continue;
9238
9239 len = strlen(buf);
9240 if (!len) break; // sanity check
9241 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
9242 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9243 {
9244 buf[len - 1] = '\0';
9245 len = len - 1;
9246 }
9247 // fgets always null terminates and hence even if we have no
9248 // newline at the end, it is null terminated. The callee
9249 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
9250 // buf[length] is zero and hence we decrement len to reflect that.
9251 if (len)
9252 {
9253 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
9254 //here we need to check for just \r but taking extra caution.
9255 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9256 {
9257 buf[len - 1] = '\0';
9258 len = len - 1;
9259 }
9260 }
9261 if (!len) //Sanity Check: len should never be zero
9262 {
9263 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
9264 continue;
9265 }
9266 mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
9267 }
9268 fclose(fp);
9269 }
9270
9271 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
9272
9273 mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
9274 {
9275 #ifdef __DISPATCH_GROUP__
9276 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9277 static dispatch_queue_t etcq = 0;
9278 static dispatch_source_t etcsrc = 0;
9279 static dispatch_source_t hostssrc = 0;
9280
9281 // First time through? just schedule ourselves on the main queue and we'll do the work later
9282 if (!etcq)
9283 {
9284 etcq = dispatch_get_main_queue();
9285 if (etcq)
9286 {
9287 // Do this work on the queue, not here - solves potential synchronization issues
9288 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9289 }
9290 return -1;
9291 }
9292
9293 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9294 #endif
9295
9296 int fd = open("/etc/hosts", O_RDONLY);
9297
9298 #ifdef __DISPATCH_GROUP__
9299 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9300 if (fd == -1)
9301 {
9302 // If the open failed and we're already watching /etc, we're done
9303 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9304
9305 // we aren't watching /etc, we should be
9306 fd = open("/etc", O_RDONLY);
9307 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9308 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9309 if (etcsrc == NULL)
9310 {
9311 close(fd);
9312 return -1;
9313 }
9314 dispatch_source_set_event_handler(etcsrc,
9315 ^{
9316 u_int32_t flags = dispatch_source_get_data(etcsrc);
9317 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9318 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9319 {
9320 dispatch_source_cancel(etcsrc);
9321 dispatch_release(etcsrc);
9322 etcsrc = NULL;
9323 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9324 return;
9325 }
9326 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9327 {
9328 mDNSMacOSXUpdateEtcHosts(m);
9329 }
9330 });
9331 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9332 dispatch_resume(etcsrc);
9333
9334 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9335 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9336 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9337 }
9338
9339 // create a dispatch source to watch for changes to hosts file
9340 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9341 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9342 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9343 if (hostssrc == NULL)
9344 {
9345 close(fd);
9346 return -1;
9347 }
9348 dispatch_source_set_event_handler(hostssrc,
9349 ^{
9350 u_int32_t flags = dispatch_source_get_data(hostssrc);
9351 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9352 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9353 {
9354 dispatch_source_cancel(hostssrc);
9355 dispatch_release(hostssrc);
9356 hostssrc = NULL;
9357 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9358 // the block immediately, we try to open the file and the file may not exist and may
9359 // fail to get a notification in the future. When the file does not exist and
9360 // we start to monitor the directory, on "dispatch_resume" of that source, there
9361 // is no guarantee that the file creation will be notified always because when
9362 // the dispatch_resume returns, the kevent manager may not have registered the
9363 // kevent yet but the file may have been created
9364 usleep(1000000);
9365 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9366 return;
9367 }
9368 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9369 {
9370 mDNSMacOSXUpdateEtcHosts(m);
9371 }
9372 });
9373 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9374 dispatch_resume(hostssrc);
9375
9376 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9377 if (etcsrc)
9378 {
9379 dispatch_source_cancel(etcsrc);
9380 dispatch_release(etcsrc);
9381 etcsrc = NULL;
9382 }
9383
9384 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9385 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9386 #else
9387 (void)m;
9388 return fd;
9389 #endif
9390 }
9391
9392 // When /etc/hosts is modified, flush all the cache records as there may be local
9393 // authoritative answers now
9394 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9395 {
9396 CacheRecord *cr;
9397 mDNSu32 slot;
9398 CacheGroup *cg;
9399
9400 FORALL_CACHERECORDS(slot, cg, cr)
9401 {
9402 // Skip multicast.
9403 if (cr->resrec.InterfaceID) continue;
9404
9405 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9406 // never used to deliver an ADD or RMV
9407 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9408 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9409 {
9410 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9411 mDNS_PurgeCacheResourceRecord(m, cr);
9412 }
9413 }
9414 }
9415
9416 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9417 mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9418 {
9419 AuthGroup *ag;
9420 mDNSu32 slot;
9421 AuthRecord *rr, *primary, *rrnext;
9422 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9423 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9424 {
9425 primary = NULL;
9426 for (rr = ag->members; rr; rr = rrnext)
9427 {
9428 rrnext = rr->next;
9429 AuthGroup *ag1;
9430 AuthRecord *rr1;
9431 mDNSBool found = mDNSfalse;
9432 ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
9433 if (ag1 && ag1->members)
9434 {
9435 if (!primary) primary = ag1->members;
9436 rr1 = ag1->members;
9437 while (rr1)
9438 {
9439 // We are not using InterfaceID in checking for duplicates. This means,
9440 // if there are two addresses for a given name e.g., fe80::1%en0 and
9441 // fe80::1%en1, we only add the first one. It is not clear whether
9442 // this is a common case. To fix this, we also need to modify
9443 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9444 // common case, we will fix it then.
9445 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9446 {
9447 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9448 found = mDNStrue;
9449 break;
9450 }
9451 rr1 = rr1->next;
9452 }
9453 }
9454 if (!found)
9455 {
9456 if (justCheck)
9457 {
9458 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9459 return mDNStrue;
9460 }
9461 RemoveAuthRecord(m, newhosts, rr);
9462 // if there is no primary, point to self
9463 rr->RRSet = (primary ? primary : rr);
9464 rr->next = NULL;
9465 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9466 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9467 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9468 }
9469 }
9470 }
9471 return mDNSfalse;
9472 }
9473
9474 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9475 // does not delete, just returns true
9476 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9477 {
9478 AuthGroup *ag;
9479 mDNSu32 slot;
9480 AuthRecord *rr, *primary, *rrnext;
9481 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9482 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9483 for (rr = ag->members; rr; rr = rrnext)
9484 {
9485 mDNSBool found = mDNSfalse;
9486 AuthGroup *ag1;
9487 AuthRecord *rr1;
9488 rrnext = rr->next;
9489 if (rr->RecordCallback != FreeEtcHosts) continue;
9490 ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
9491 if (ag1)
9492 {
9493 primary = rr1 = ag1->members;
9494 while (rr1)
9495 {
9496 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9497 {
9498 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9499 found = mDNStrue;
9500 break;
9501 }
9502 rr1 = rr1->next;
9503 }
9504 }
9505 // there is no corresponding record in newhosts for the same name. This means
9506 // we should delete this from the core.
9507 if (!found)
9508 {
9509 if (justCheck)
9510 {
9511 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9512 return mDNStrue;
9513 }
9514 // if primary is going away, make sure that the rest of the records
9515 // point to the new primary
9516 if (rr == ag->members)
9517 {
9518 AuthRecord *new_primary = rr->next;
9519 AuthRecord *r = new_primary;
9520 while (r)
9521 {
9522 if (r->RRSet == rr)
9523 {
9524 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9525 r->RRSet = new_primary;
9526 }
9527 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9528 r = r->next;
9529 }
9530 }
9531 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9532 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9533 }
9534 }
9535 return mDNSfalse;
9536 }
9537
9538 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9539 {
9540 AuthHash *newhosts = (AuthHash *)context;
9541
9542 mDNS_CheckLock(m);
9543
9544 //Delete old entries from the core if they are not present in the newhosts
9545 EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
9546 // Add the new entries to the core if not already present in the core
9547 EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
9548 }
9549
9550 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9551 {
9552 mDNSu32 slot;
9553 AuthGroup *ag, *agnext;
9554 AuthRecord *rr, *rrnext;
9555
9556 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9557 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9558 {
9559 agnext = ag->next;
9560 for (rr = ag->members; rr; rr = rrnext)
9561 {
9562 rrnext = rr->next;
9563 freeL("etchosts", rr);
9564 }
9565 freeL("AuthGroups", ag);
9566 }
9567 }
9568
9569 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9570 {
9571 AuthHash newhosts;
9572
9573 // As we will be modifying the core, we can only have one thread running at
9574 // any point in time.
9575 KQueueLock(m);
9576
9577 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9578
9579 // Get the file desecriptor (will trigger us to start watching for changes)
9580 int fd = mDNSMacOSXGetEtcHostsFD(m);
9581 if (fd != -1)
9582 {
9583 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9584 mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
9585 }
9586 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9587
9588 // Optimization: Detect whether /etc/hosts changed or not.
9589 //
9590 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9591 // newhosts is already registered with core. If we find at least one entry that is not
9592 // registered with core, then it means we have work to do.
9593 //
9594 // 2. Next, we check to see if any of the entries that are registered with core is not present
9595 // in newhosts. If we find at least one entry that is not present, it means we have work to
9596 // do.
9597 //
9598 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9599 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9600 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9601 // in the future and this code does not have to change.
9602 mDNS_Lock(m);
9603 // Add the new entries to the core if not already present in the core
9604 if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
9605 {
9606 // No new entries to add, check to see if we need to delete any old entries from the
9607 // core if they are not present in the newhosts
9608 if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
9609 {
9610 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9611 mDNS_Unlock(m);
9612 KQueueUnlock(m, "/etc/hosts changed");
9613 FreeNewHosts(&newhosts);
9614 return;
9615 }
9616 }
9617
9618 // This will flush the cache, stop and start the query so that the queries
9619 // can look at the /etc/hosts again
9620 //
9621 // Notes:
9622 //
9623 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9624 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9625 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9626 // delivers these events in the right order and then calls us back to delete them.
9627 //
9628 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9629 // is a common function that looks at all local auth records and delivers a RMV including
9630 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9631 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9632 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9633 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9634 // looks normal.
9635 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9636 mDNS_Unlock(m);
9637
9638 KQueueUnlock(m, "/etc/hosts changed");
9639 FreeNewHosts(&newhosts);
9640 }
9641
9642 #if COMPILER_LIKES_PRAGMA_MARK
9643 #pragma mark -
9644 #pragma mark - Initialization & Teardown
9645 #endif
9646
9647 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9648 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9649 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9650 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9651
9652 // Major version 13 is 10.9.x
9653 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9654 {
9655 int major = 0, minor = 0;
9656 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9657 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9658 if (vers)
9659 {
9660 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9661 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9662 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9663 if (cfprodname)
9664 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9665 if (cfprodvers)
9666 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9667 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9668 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9669 CFRelease(vers);
9670 }
9671 if (!major)
9672 {
9673 major = 13;
9674 LogMsg("Note: No Major Build Version number found; assuming 13");
9675 }
9676 if (HINFO_SWstring)
9677 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9678 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9679
9680 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9681 if ((prodname[0] & 0xDF) == 'M')
9682 OSXVers = major;
9683 else
9684 iOSVers = major;
9685 }
9686
9687 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9688 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9689 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9690 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9691 {
9692 int err = -1;
9693 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9694 if (s < 3)
9695 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9696 else
9697 {
9698 struct sockaddr_in s5353;
9699 s5353.sin_family = AF_INET;
9700 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9701 s5353.sin_addr.s_addr = 0;
9702 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9703 close(s);
9704 }
9705
9706 if (err) LogMsg("No unicast UDP responses");
9707 else debugf("Unicast UDP responses okay");
9708 return(err == 0);
9709 }
9710
9711 mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
9712 {
9713 AuthRecord *rr;
9714 const domainname *pname = (domainname *)"\x9" "localhost";
9715
9716 rr= mallocL("localhosts", sizeof(*rr));
9717 if (rr == NULL) return;
9718 mDNSPlatformMemZero(rr, sizeof(*rr));
9719
9720 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9721 AssignDomainName(&rr->namestorage, domain);
9722
9723 rr->resrec.rdlength = DomainNameLength(pname);
9724 rr->resrec.rdata->u.name.c[0] = 0;
9725 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9726
9727 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9728 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9729 mDNS_Register(m, rr);
9730 }
9731
9732 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9733 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9734 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9735 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9736 //
9737 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9738 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9739 mDNSlocal void SetupLocalHostRecords(mDNS *const m)
9740 {
9741 char buffer[MAX_REVERSE_MAPPING_NAME];
9742 domainname name;
9743 int i;
9744 struct in6_addr addr;
9745 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
9746
9747 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
9748 {
9749 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
9750 ptr[3], ptr[2], ptr[1], ptr[0]);
9751 MakeDomainNameFromDNSNameString(&name, buffer);
9752 CreatePTRRecord(m, &name);
9753 }
9754 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
9755
9756 if (inet_pton(AF_INET6, "::1", &addr) == 1)
9757 {
9758 for (i = 0; i < 16; i++)
9759 {
9760 static const char hexValues[] = "0123456789ABCDEF";
9761 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
9762 buffer[i * 4 + 1] = '.';
9763 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
9764 buffer[i * 4 + 3] = '.';
9765 }
9766 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
9767 MakeDomainNameFromDNSNameString(&name, buffer);
9768 CreatePTRRecord(m, &name);
9769 }
9770 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
9771 }
9772
9773 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9774 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9775 // (.local manually generated via explicit callback)
9776 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9777 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9778 // 4) result above should generate a callback from question in (1). result added to global list
9779 // 5) global list delivered to client via GetSearchDomainList()
9780 // 6) client calls to enumerate domains now go over LocalOnly interface
9781 // (!!!KRS may add outgoing interface in addition)
9782
9783 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9784 {
9785 mStatus err;
9786 m->p->CFRunLoop = CFRunLoopGetCurrent();
9787
9788 char HINFO_SWstring[256] = "";
9789 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9790
9791 err = mDNSHelperInit();
9792 if (err)
9793 return err;
9794
9795 DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL);
9796 if (DynamicStoreQueue == NULL)
9797 {
9798 LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!");
9799 return mStatus_NoMemoryErr;
9800 }
9801
9802 // Store mDNSResponder Platform
9803 if (OSXVers)
9804 {
9805 m->mDNS_plat = platform_OSX;
9806 }
9807 else if (iOSVers)
9808 {
9809 if (IsAppleTV())
9810 m->mDNS_plat = platform_Atv;
9811 else
9812 m->mDNS_plat = platform_iOS;
9813 }
9814 else
9815 {
9816 m->mDNS_plat = platform_NonApple;
9817 }
9818
9819 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9820 // 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.
9821 int i;
9822 for (i=0; i<100; i++)
9823 {
9824 domainlabel testlabel;
9825 testlabel.c[0] = 0;
9826 GetUserSpecifiedLocalHostName(&testlabel);
9827 if (testlabel.c[0]) break;
9828 usleep(50000);
9829 }
9830
9831 m->hostlabel.c[0] = 0;
9832
9833 int get_model[2] = { CTL_HW, HW_MODEL };
9834 size_t len_model = sizeof(HINFO_HWstring_buffer);
9835
9836 // Normal Apple model names are of the form "iPhone2,1", and
9837 // internal code names are strings containing no commas, e.g. "N88AP".
9838 // We used to ignore internal code names, but Apple now uses these internal code names
9839 // even in released shipping products, so we no longer ignore strings containing no commas.
9840 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9841 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9842 HINFO_HWstring = HINFO_HWstring_buffer;
9843
9844 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9845 // For names of the form "N88AP" containg no comma, we use the entire string.
9846 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9847
9848 if (mDNSPlatformInit_CanReceiveUnicast())
9849 m->CanReceiveUnicastOn5353 = mDNStrue;
9850
9851 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9852 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9853 if (hlen + slen < 254)
9854 {
9855 m->HIHardware.c[0] = hlen;
9856 m->HISoftware.c[0] = slen;
9857 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9858 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9859 }
9860
9861 m->p->permanentsockets.port = MulticastDNSPort;
9862 m->p->permanentsockets.m = m;
9863 m->p->permanentsockets.sktv4 = -1;
9864 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9865 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9866 m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
9867 m->p->permanentsockets.sktv6 = -1;
9868 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9869 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9870 m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
9871
9872 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9873 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9874
9875 struct sockaddr_in s4;
9876 socklen_t n4 = sizeof(s4);
9877 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9878 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9879 else
9880 m->UnicastPort4.NotAnInteger = s4.sin_port;
9881
9882 if (m->p->permanentsockets.sktv6 >= 0)
9883 {
9884 struct sockaddr_in6 s6;
9885 socklen_t n6 = sizeof(s6);
9886 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9887 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9888 }
9889
9890 m->p->InterfaceList = mDNSNULL;
9891 m->p->userhostlabel.c[0] = 0;
9892 m->p->usernicelabel.c[0] = 0;
9893 m->p->prevoldnicelabel.c[0] = 0;
9894 m->p->prevnewnicelabel.c[0] = 0;
9895 m->p->prevoldhostlabel.c[0] = 0;
9896 m->p->prevnewhostlabel.c[0] = 0;
9897 m->p->NotifyUser = 0;
9898 m->p->KeyChainTimer = 0;
9899 m->p->WakeAtUTC = 0;
9900 m->p->RequestReSleep = 0;
9901 // Assume that everything is good to begin with. If something is not working,
9902 // we will detect that when we start sending questions.
9903 m->p->v4answers = 1;
9904 m->p->v6answers = 1;
9905 m->p->DNSTrigger = 0;
9906 m->p->LastConfigGeneration = 0;
9907
9908 #if APPLE_OSX_mDNSResponder
9909 uuid_generate(m->asl_uuid);
9910 #endif
9911
9912 m->AutoTunnelRelayAddr = zerov6Addr;
9913
9914 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9915 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9916 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9917 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9918 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9919 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9920 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9921 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9922
9923 err = WatchForNetworkChanges(m);
9924 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9925
9926 #if 0 // <rdar://problem/6751656>
9927 err = WatchForPMChanges(m);
9928 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
9929 #endif
9930
9931 err = WatchForSysEvents(m);
9932 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9933
9934 mDNSs32 utc = mDNSPlatformUTC();
9935 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9936 UpdateInterfaceList(m, utc);
9937 SetupActiveInterfaces(m, utc);
9938
9939 // Explicitly ensure that our Keychain operations utilize the system domain.
9940 #ifndef NO_SECURITYFRAMEWORK
9941 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9942 #endif
9943
9944 mDNS_Lock(m);
9945 SetDomainSecrets(m);
9946 SetLocalDomains();
9947 mDNS_Unlock(m);
9948
9949 #ifndef NO_SECURITYFRAMEWORK
9950 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9951 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9952 #endif
9953
9954 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9955 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9956 #else
9957 IOPMConnection c;
9958 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9959 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9960 else
9961 {
9962 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9963 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9964 else
9965 {
9966 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9967 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9968 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9969 #else
9970 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
9971 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9972 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9973 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9974 }
9975 }
9976 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9977 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9978 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9979 {
9980 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9981 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9982 else
9983 {
9984 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9985 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9986 #else
9987 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9988 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9989 }
9990 }
9991
9992 #if APPLE_OSX_mDNSResponder
9993 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9994 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9995 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9996 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9997 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9998 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9999 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10000 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
10001 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
10002 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
10003 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
10004 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
10005 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
10006 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10007 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10008 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
10009 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
10010 #endif // APPLE_OSX_mDNSResponder
10011
10012 // Currently this is not defined. SSL code will eventually fix this. If it becomes
10013 // critical, we will define this to workaround the bug in SSL.
10014 #ifdef __SSL_NEEDS_SERIALIZATION__
10015 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
10016 #else
10017 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
10018 #endif
10019 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
10020
10021 mDNSMacOSXUpdateEtcHosts(m);
10022 SetupLocalHostRecords(m);
10023 CUPInit(m);
10024
10025 return(mStatus_NoError);
10026 }
10027
10028 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
10029 {
10030 #if MDNS_NO_DNSINFO
10031 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
10032 #endif
10033
10034 // Adding interfaces will use this flag, so set it now.
10035 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
10036
10037 #if APPLE_OSX_mDNSResponder
10038 m->SPSBrowseCallback = UpdateSPSStatus;
10039 #endif // APPLE_OSX_mDNSResponder
10040
10041 mStatus result = mDNSPlatformInit_setup(m);
10042
10043 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
10044 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
10045 if (result == mStatus_NoError)
10046 {
10047 mDNSCoreInitComplete(m, mStatus_NoError);
10048
10049 #if !NO_D2D
10050 // We only initialize if mDNSCore successfully initialized.
10051 if (D2DInitialize)
10052 {
10053 D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
10054 if (ds != kD2DSuccess)
10055 LogMsg("D2DInitialiize failed: %d", ds);
10056 else
10057 LogMsg("D2DInitialize succeeded");
10058 }
10059 #endif // ! NO_D2D
10060
10061 }
10062 result = DNSSECCryptoInit(m);
10063 return(result);
10064 }
10065
10066 mDNSexport void mDNSPlatformClose(mDNS *const m)
10067 {
10068 if (m->p->PowerConnection)
10069 {
10070 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10071 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
10072 #else
10073 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10074 #endif
10075 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
10076 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
10077 IODeregisterForSystemPower(&m->p->PowerNotifier);
10078 IOServiceClose ( m->p->PowerConnection);
10079 IONotificationPortDestroy ( m->p->PowerPortRef);
10080 m->p->PowerConnection = 0;
10081 }
10082
10083 if (m->p->Store)
10084 {
10085 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10086 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
10087 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
10088 #else
10089 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
10090 CFRunLoopSourceInvalidate(m->p->StoreRLS);
10091 CFRelease(m->p->StoreRLS);
10092 m->p->StoreRLS = NULL;
10093 #endif
10094 CFRelease(m->p->Store);
10095 m->p->Store = NULL;
10096 }
10097
10098 if (m->p->PMRLS)
10099 {
10100 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
10101 CFRunLoopSourceInvalidate(m->p->PMRLS);
10102 CFRelease(m->p->PMRLS);
10103 m->p->PMRLS = NULL;
10104 }
10105
10106 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
10107
10108 #if !NO_D2D
10109 if (D2DTerminate)
10110 {
10111 D2DStatus ds = D2DTerminate();
10112 if (ds != kD2DSuccess)
10113 LogMsg("D2DTerminate failed: %d", ds);
10114 else
10115 LogMsg("D2DTerminate succeeded");
10116 }
10117 #endif // ! NO_D2D
10118
10119 mDNSs32 utc = mDNSPlatformUTC();
10120 MarkAllInterfacesInactive(m, utc);
10121 ClearInactiveInterfaces(m, utc);
10122 CloseSocketSet(&m->p->permanentsockets);
10123
10124 #if APPLE_OSX_mDNSResponder
10125 // clean up tunnels
10126 while (m->TunnelClients)
10127 {
10128 ClientTunnel *cur = m->TunnelClients;
10129 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
10130 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
10131 AutoTunnelSetKeys(cur, mDNSfalse);
10132 m->TunnelClients = cur->next;
10133 freeL("ClientTunnel", cur);
10134 }
10135
10136 if (AnonymousRacoonConfig)
10137 {
10138 AnonymousRacoonConfig = mDNSNULL;
10139 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
10140 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL);
10141 }
10142 #endif // APPLE_OSX_mDNSResponder
10143 }
10144
10145 #if COMPILER_LIKES_PRAGMA_MARK
10146 #pragma mark -
10147 #pragma mark - General Platform Support Layer functions
10148 #endif
10149
10150 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
10151 {
10152 return(arc4random());
10153 }
10154
10155 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
10156 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
10157
10158 mDNSexport mStatus mDNSPlatformTimeInit(void)
10159 {
10160 // Notes: Typical values for mach_timebase_info:
10161 // tbi.numer = 1000 million
10162 // tbi.denom = 33 million
10163 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
10164 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
10165 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
10166 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
10167 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
10168 //
10169 // Arithmetic notes:
10170 // tbi.denom is at least 1, and not more than 2^32-1.
10171 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
10172 // tbi.denom is at least 1, and not more than 2^32-1.
10173 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
10174 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
10175 // which is unlikely on any current or future Macintosh.
10176 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
10177 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
10178 struct mach_timebase_info tbi;
10179 kern_return_t result = mach_timebase_info(&tbi);
10180 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
10181 return(result);
10182 }
10183
10184 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
10185 {
10186 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
10187
10188 static uint64_t last_mach_absolute_time = 0;
10189 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
10190 uint64_t this_mach_absolute_time = mach_absolute_time();
10191 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
10192 {
10193 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
10194 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
10195 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10196 last_mach_absolute_time = this_mach_absolute_time;
10197 // Note: This bug happens all the time on 10.3
10198 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10199 "This error occurs from time to time, often on newly released hardware, "
10200 "and usually the exact cause is different in each instance.\r\r"
10201 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10202 "and assign it to Radar Component “Kernel” Version “X”.");
10203 }
10204 last_mach_absolute_time = this_mach_absolute_time;
10205
10206 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
10207 }
10208
10209 mDNSexport mDNSs32 mDNSPlatformUTC(void)
10210 {
10211 return time(NULL);
10212 }
10213
10214 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10215 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
10216 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
10217 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
10218 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
10219 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
10220 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
10221 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
10222 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
10223 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
10224 {
10225 return (qsort(base, nel, width, compar));
10226 }
10227 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10228 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
10229 #endif
10230 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
10231
10232 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
10233 {
10234 if (allowSleep && m->p->IOPMAssertion)
10235 {
10236 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
10237 IOPMAssertionRelease(m->p->IOPMAssertion);
10238 m->p->IOPMAssertion = 0;
10239 }
10240 else if (!allowSleep)
10241 {
10242 #ifdef kIOPMAssertionTypeNoIdleSleep
10243 if (m->p->IOPMAssertion)
10244 {
10245 IOPMAssertionRelease(m->p->IOPMAssertion);
10246 m->p->IOPMAssertion = 0;
10247 }
10248
10249 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10250 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10251 if (assertionName) CFRelease(assertionName);
10252 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10253 #endif
10254 }
10255 }
10256
10257 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10258 {
10259 mDNSu32 ifindex;
10260
10261 // Sanity check
10262 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
10263 if (ifindex <= 0)
10264 {
10265 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10266 return;
10267 }
10268 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10269 }
10270
10271 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10272 {
10273 NetworkInterfaceInfoOSX *info;
10274
10275 if (InterfaceID == mDNSInterface_P2P)
10276 return mDNStrue;
10277
10278 if ( (InterfaceID == mDNSInterface_Any)
10279 || (InterfaceID == mDNSInterfaceMark)
10280 || (InterfaceID == mDNSInterface_LocalOnly)
10281 || (InterfaceID == mDNSInterface_Unicast))
10282 return mDNSfalse;
10283
10284 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
10285 if (info == NULL)
10286 {
10287 // this log message can print when operations are stopped on an interface that has gone away
10288 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10289 return mDNSfalse;
10290 }
10291
10292 return (mDNSBool) info->D2DInterface;
10293 }
10294
10295 // Filter records send over P2P (D2D) type interfaces
10296 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10297 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
10298 {
10299 // For an explicit match to a valid interface ID, return true.
10300 if (rr->resrec.InterfaceID == intf->InterfaceID)
10301 return mDNStrue;
10302
10303 // Only filtering records for D2D type interfaces, return true for all other interface types.
10304 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10305 return mDNStrue;
10306
10307 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10308 if (intf->InterfaceID == AWDLInterfaceID)
10309 {
10310 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10311 return mDNStrue;
10312 else
10313 return mDNSfalse;
10314 }
10315
10316 // Send record if it is explicitly marked to include all other P2P type interfaces.
10317 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10318 return mDNStrue;
10319
10320 // Don't send the record over this interface.
10321 return mDNSfalse;
10322 }
10323
10324 // Filter questions send over P2P (D2D) type interfaces.
10325 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10326 {
10327 // For an explicit match to a valid interface ID, return true.
10328 if (q->InterfaceID == intf->InterfaceID)
10329 return mDNStrue;
10330
10331 // Only filtering questions for D2D type interfaces
10332 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10333 return mDNStrue;
10334
10335 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10336 if (intf->InterfaceID == AWDLInterfaceID)
10337 {
10338 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10339 return mDNStrue;
10340 else
10341 return mDNSfalse;
10342 }
10343
10344 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10345 if (q->flags & kDNSServiceFlagsIncludeP2P)
10346 return mDNStrue;
10347
10348 // Don't send the question over this interface.
10349 return mDNSfalse;
10350 }
10351
10352 // Returns true unless record was received over the AWDL interface and
10353 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10354 // with the kDNSServiceFlagsIncludeAWDL flag set.
10355 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10356 {
10357 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10358 return mDNStrue;
10359
10360 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10361 {
10362 LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query",
10363 DNSTypeName(q->qtype), q->qname.c);
10364 return mDNSfalse;
10365 }
10366
10367 return mDNStrue;
10368 }
10369
10370 // formating time to RFC 4034 format
10371 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10372 {
10373 struct tm tmTime;
10374 time_t t = (time_t)te;
10375 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10376 // gmtime_r first and then use strftime
10377 gmtime_r(&t, &tmTime);
10378 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10379 }
10380
10381 mDNSexport mDNSs32 mDNSPlatformGetPID()
10382 {
10383 return getpid();
10384 }
10385
10386 // Schedule a function asynchronously on the main queue
10387 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10388 {
10389 // KQueueLock/Unlock is used for two purposes
10390 //
10391 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10392 // serializes the access to the "core"
10393 //
10394 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10395 // up and calls udsserver_idle which schedules the messages across the uds socket.
10396 // If "func" delivers something to the uds socket from the dispatch thread, it will
10397 // not be delivered immediately if not for the Unlock.
10398 dispatch_async(dispatch_get_main_queue(), ^{
10399 KQueueLock(m);
10400 func(m, context);
10401 KQueueUnlock(m, "mDNSPlatformDispatchAsync");
10402 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10403 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10404 // to handle any message that "func" might deliver.
10405 TriggerEventCompletion();
10406 #endif
10407 });
10408 }
10409
10410 // definitions for device-info record construction
10411 #define DEVINFO_MODEL "model="
10412 #define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL)
10413
10414 #define OSX_VER "osxvers="
10415 #define OSX_VER_LEN strlen(OSX_VER)
10416 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10417
10418 // Bytes available in TXT record for model name after subtracting space for other
10419 // fixed size strings and their length bytes.
10420 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1))
10421
10422 // Initialize device-info TXT record contents and return total length of record data.
10423 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10424 {
10425 mDNSu8 *bufferStart = ptr;
10426 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10427
10428 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10429 ptr++;
10430 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10431 ptr += DEVINFO_MODEL_LEN;
10432 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10433 ptr += len;
10434
10435 // only include this string for OSX
10436 if (OSXVers)
10437 {
10438 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10439 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10440 ptr++;
10441 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10442 ptr += OSX_VER_LEN;
10443 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10444 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10445 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10446 ptr += VER_NUM_LEN;
10447 }
10448
10449 return (ptr - bufferStart);
10450 }