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