]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
c57edddadabcbaf48ef84a27e4ccc0d0f19118a3
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2016 Apple 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 "dns_sd_private.h"
33 #include "PlatformCommon.h"
34 #include "uds_daemon.h"
35 #include "CryptoSupport.h"
36
37 #include <stdio.h>
38 #include <stdarg.h> // For va_list support
39 #include <stdlib.h> // For arc4random
40 #include <net/if.h>
41 #include <net/if_types.h> // For IFT_ETHER
42 #include <net/if_dl.h>
43 #include <net/bpf.h> // For BIOCSETIF etc.
44 #include <sys/uio.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/event.h>
49 #include <fcntl.h>
50 #include <sys/ioctl.h>
51 #include <time.h> // platform support for UTC time
52 #include <arpa/inet.h> // for inet_aton
53 #include <pthread.h>
54 #include <netdb.h> // for getaddrinfo
55 #include <sys/sockio.h> // for SIOCGIFEFLAGS
56 #include <notify.h>
57 #include <netinet/in.h> // For IP_RECVTTL
58 #ifndef IP_RECVTTL
59 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
60 #endif
61
62 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
63 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
64 #include <netinet6/in6_var.h> // For IN6_IFF_TENTATIVE 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 #if TARGET_OS_IPHONE
90 // For WiFiManagerClientRef etc, declarations.
91 #include <MobileGestalt.h>
92 #include <MobileWiFi/WiFiManagerClient.h>
93 #include <dlfcn.h>
94 #endif // TARGET_OS_IPHONE
95
96 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
97 #include <Kernel/IOKit/apple80211/apple80211_var.h>
98
99 #if APPLE_OSX_mDNSResponder
100 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
101 #include <AWACS.h>
102 #include <ne_session.h> // for ne_session_set_socket_attributes()
103 #if !NO_D2D
104 #include "BLE.h"
105
106 D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
107 D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
108 D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
109 D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
110 D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
111 D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
112 D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
113 void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
114 void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
115 D2DStatus D2DTerminate() __attribute__((weak_import));
116
117 void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
118 void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
119
120 #endif // ! NO_D2D
121
122 #else
123 #define NO_D2D 1
124 #define NO_AWACS 1
125 #endif // APPLE_OSX_mDNSResponder
126
127 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
128 #include <IOKit/platform/IOPlatformSupportPrivate.h>
129 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
130
131 #define kInterfaceSpecificOption "interface="
132
133 #define mDNS_IOREG_KEY "mDNS_KEY"
134 #define mDNS_IOREG_VALUE "2009-07-30"
135 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
136 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
137
138 #define DARK_WAKE_TIME 16 // Time we hold an idle sleep assertion for maintenance after a wake notification
139
140 // cache the InterfaceID of the AWDL interface
141 mDNSInterfaceID AWDLInterfaceID;
142
143 // ***************************************************************************
144 // Globals
145
146 #if COMPILER_LIKES_PRAGMA_MARK
147 #pragma mark - Globals
148 #endif
149
150 // By default we don't offer sleep proxy service
151 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
152 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
153 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
154 mDNSexport int OfferSleepProxyService = 0;
155 mDNSexport int DisableSleepProxyClient = 0;
156 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
157
158 mDNSexport int OSXVers, iOSVers;
159 mDNSexport int KQueueFD;
160
161 #ifndef NO_SECURITYFRAMEWORK
162 static CFArrayRef ServerCerts;
163 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
164 #endif /* NO_SECURITYFRAMEWORK */
165
166 static CFStringRef NetworkChangedKey_IPv4;
167 static CFStringRef NetworkChangedKey_IPv6;
168 static CFStringRef NetworkChangedKey_Hostnames;
169 static CFStringRef NetworkChangedKey_Computername;
170 static CFStringRef NetworkChangedKey_DNS;
171 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
172 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
173 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
174 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
175 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
176
177 static char HINFO_HWstring_buffer[32];
178 static char *HINFO_HWstring = "Device";
179 static int HINFO_HWstring_prefixlen = 6;
180
181 mDNSexport int WatchDogReportingThreshold = 250;
182
183 dispatch_queue_t SSLqueue;
184
185 #if TARGET_OS_EMBEDDED
186 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
187 #endif
188
189 #if APPLE_OSX_mDNSResponder
190 static mDNSu8 SPMetricPortability = 99;
191 static mDNSu8 SPMetricMarginalPower = 99;
192 static mDNSu8 SPMetricTotalPower = 99;
193 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
194 mDNSexport domainname ActiveDirectoryPrimaryDomain;
195 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
196 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
197 #endif // APPLE_OSX_mDNSResponder
198
199 // Don't send triggers too often. We arbitrarily limit it to three minutes.
200 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
201
202 // Used by AutoTunnel
203 const char btmmprefix[] = "btmmdns:";
204 const char dnsprefix[] = "dns:";
205
206 // String Array used to write list of private domains to Dynamic Store
207 static CFArrayRef privateDnsArray = NULL;
208
209 // ***************************************************************************
210 #if COMPILER_LIKES_PRAGMA_MARK
211 #pragma mark -
212 #pragma mark - D2D Support
213 #endif
214
215 #if !NO_D2D
216
217 mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
218 {
219 // AWDL wants the address and reverse address PTR record communicated
220 // via the D2D interface layer.
221 if (interface->InterfaceID == AWDLInterfaceID)
222 {
223 // only log if we have a valid record to start advertising
224 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
225 LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
226
227 if (interface->RR_A.resrec.RecordType)
228 external_start_advertising_service(&interface->RR_A.resrec, 0);
229 if (interface->RR_PTR.resrec.RecordType)
230 external_start_advertising_service(&interface->RR_PTR.resrec, 0);
231 }
232 }
233
234 mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
235 {
236 if (interface->InterfaceID == AWDLInterfaceID)
237 {
238 // only log if we have a valid record to stop advertising
239 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
240 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
241
242 if (interface->RR_A.resrec.RecordType)
243 external_stop_advertising_service(&interface->RR_A.resrec, 0);
244 if (interface->RR_PTR.resrec.RecordType)
245 external_stop_advertising_service(&interface->RR_PTR.resrec, 0);
246 }
247 }
248
249 // If record would have been advertised to the D2D plugin layer, stop that advertisement.
250 mDNSexport void D2D_stop_advertising_record(AuthRecord *ar)
251 {
252 DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
253 if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
254 {
255 external_stop_advertising_service(&ar->resrec, flags);
256 }
257 }
258
259 // If record should be advertised to the D2D plugin layer, start that advertisement.
260 mDNSexport void D2D_start_advertising_record(AuthRecord *ar)
261 {
262 DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
263 if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
264 {
265 external_start_advertising_service(&ar->resrec, flags);
266 }
267 }
268
269 // Name compression items for fake packet version number 1
270 static const mDNSu8 compression_packet_v1 = 0x01;
271
272 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" };
273 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
274 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
275
276 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
277 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
278
279 typedef struct D2DRecordListElem
280 {
281 struct D2DRecordListElem *next;
282 D2DServiceInstance instanceHandle;
283 D2DTransportType transportType;
284 AuthRecord ar; // must be last in the structure to accomodate extra space
285 // allocated for large records.
286 } D2DRecordListElem;
287
288 static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
289
290 typedef struct D2DBrowseListElem
291 {
292 struct D2DBrowseListElem *next;
293 domainname name;
294 mDNSu16 type;
295 unsigned int refCount;
296 } D2DBrowseListElem;
297
298 D2DBrowseListElem* D2DBrowseList = NULL;
299
300 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
301 {
302 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
303 ptr[1] = (mDNSu8)((val ) & 0xFF);
304 return ptr + sizeof(mDNSu16);
305 }
306
307 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
308 {
309 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
310 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
311 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
312 ptr[3] = (mDNSu8)((val ) & 0xFF);
313 return ptr + sizeof(mDNSu32);
314 }
315
316 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
317 {
318 const mDNSu8 * const start = (const mDNSu8 * const)in;
319 mDNSu8 *ptr = (mDNSu8*)start;
320 while(*ptr)
321 {
322 mDNSu8 c = *ptr;
323 out->c[ptr-start] = *ptr;
324 ptr++;
325 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
326 }
327 out->c[ptr-start] = *ptr;
328 }
329
330 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
331 {
332 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
333 if (!ptr) return ptr;
334 *ptr = (qtype >> 8) & 0xff;
335 ptr += 1;
336 *ptr = qtype & 0xff;
337 ptr += 1;
338 *ptr = compression_packet_v1;
339 return ptr + 1;
340 }
341
342 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
343 {
344 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
345 }
346
347 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
348
349 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
350 {
351 mDNSu8 *end;
352 char buffer[49] = {0};
353 char *bufend = buffer + sizeof(buffer);
354
355 if (len > PRINT_DEBUG_BYTES_LIMIT)
356 {
357 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
358 len = PRINT_DEBUG_BYTES_LIMIT;
359 }
360 end = data + len;
361
362 while(data < end)
363 {
364 char *ptr = buffer;
365 for(; data < end && ptr < bufend-1; ptr+=3,data++)
366 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
367 LogInfo(" %s", buffer);
368 }
369 }
370
371 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
372 {
373 if (!mDNS_LoggingEnabled) return;
374
375 LogInfo("%s:", tag);
376 LogInfo(" LHS: (%d bytes)", lhs_len);
377 PrintHex(lhs, lhs_len);
378
379 if (!rhs) return;
380
381 LogInfo(" RHS: (%d bytes)", rhs_len);
382 PrintHex(rhs, rhs_len);
383 }
384
385 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
386 {
387 (void)m; // unused
388 if (result == mStatus_MemFree)
389 {
390 D2DRecordListElem **ptr = &D2DRecords;
391 D2DRecordListElem *tmp;
392 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
393 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
394 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
395 tmp = *ptr;
396 *ptr = (*ptr)->next;
397 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
398 mDNSPlatformMemFree(tmp);
399 }
400 }
401
402 mDNSexport void external_connection_release(const domainname *instance)
403 {
404 (void) instance;
405 D2DRecordListElem *ptr = D2DRecords;
406
407 for ( ; ptr ; ptr = ptr->next)
408 {
409 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
410 SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
411 {
412 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
413 ptr->instanceHandle, ptr->transportType);
414 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
415 }
416 }
417 }
418
419 mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
420 {
421 D2DRecordListElem *ptr = D2DRecords;
422 for ( ; ptr ; ptr = ptr->next)
423 {
424 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
425 {
426 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
427 mDNS_Deregister(&mDNSStorage, &ptr->ar);
428 }
429 }
430 }
431
432 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
433 {
434 D2DBrowseListElem **ptr = &D2DBrowseList;
435
436 for ( ; *ptr; ptr = &(*ptr)->next)
437 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
438 break;
439
440 return ptr;
441 }
442
443 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
444 {
445 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
446 return *ptr ? (*ptr)->refCount : 0;
447 }
448
449 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
450 {
451 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
452
453 if (!*ptr)
454 {
455 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
456 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
457 (*ptr)->type = type;
458 AssignDomainName(&(*ptr)->name, name);
459 }
460 (*ptr)->refCount += 1;
461
462 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
463 }
464
465 // Returns true if found in list, false otherwise
466 mDNSlocal bool D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
467 {
468 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
469
470 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return false; }
471
472 (*ptr)->refCount -= 1;
473
474 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
475
476 if (!(*ptr)->refCount)
477 {
478 D2DBrowseListElem *tmp = *ptr;
479 *ptr = (*ptr)->next;
480 mDNSPlatformMemFree(tmp);
481 }
482 return true;
483 }
484
485 mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp)
486 {
487 // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
488 // plugin protocol version number.
489 // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
490 // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
491 // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
492 // to the byte after the first name compression pointer it encounters.
493 const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len);
494
495 // There should be 3 bytes remaining in a valid key,
496 // two for the DNS record type, and one for the D2D protocol version number.
497 if (keyp == NULL || (keyp + 3 != (lhs + lhs_len)))
498 {
499 LogInfo("xD2DParse: Could not parse DNS name in key");
500 return mStatus_Incompatible;
501 }
502 keyp += 2; // point to D2D compression packet format version byte
503 if (*keyp != compression_packet_v1)
504 {
505 LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp);
506 return mStatus_Incompatible;
507 }
508
509 if (mDNS_LoggingEnabled)
510 {
511 LogInfo("%s", __func__);
512 LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
513 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
514 }
515
516 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
517
518 // Check to make sure we're not going to go past the end of the DNSMessage data
519 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
520 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
521
522 // Copy the LHS onto our fake wire packet
523 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
524 ptr += lhs_len - 1;
525
526 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
527 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
528
529 // two bytes of CLASS
530 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
531
532 // four bytes of TTL
533 ptr = putVal32(ptr, 120);
534
535 // Copy the RHS length into the RDLENGTH of our fake wire packet
536 ptr = putVal16(ptr, rhs_len);
537
538 // Copy the RHS onto our fake wire packet
539 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
540 ptr += rhs_len;
541
542 if (mDNS_LoggingEnabled)
543 {
544 LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
545 PrintHex(compression_lhs, ptr - compression_lhs);
546 }
547
548 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
549 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
550 {
551 LogMsg("xD2DParse: failed to get large RR");
552 m->rec.r.resrec.RecordType = 0;
553 return mStatus_UnknownErr;
554 }
555 else
556 {
557 LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
558 }
559
560 *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
561 if (!*D2DListp) return mStatus_NoMemoryErr;
562
563 AuthRecord *rr = &(*D2DListp)->ar;
564 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
565 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
566 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
567 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
568 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
569 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
570 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
571
572 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
573
574 return mStatus_NoError;
575 }
576
577 mDNSexport void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
578 {
579 if (result == kD2DSuccess)
580 {
581 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
582
583 mStatus err;
584 D2DRecordListElem *ptr = NULL;
585
586 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr);
587 if (err)
588 {
589 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
590 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
591 if (ptr)
592 mDNSPlatformMemFree(ptr);
593 return;
594 }
595
596 // If the record was created based on a BLE beacon, update the interface index to indicate
597 // this and thus match BLE specific queries.
598 if (transportType == D2DBLETransport)
599 ptr->ar.resrec.InterfaceID = mDNSInterface_BLE;
600
601 err = mDNS_Register(m, &ptr->ar);
602 if (err)
603 {
604 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
605 mDNSPlatformMemFree(ptr);
606 return;
607 }
608
609 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
610 ptr->instanceHandle = instanceHandle;
611 ptr->transportType = transportType;
612 ptr->next = D2DRecords;
613 D2DRecords = ptr;
614 }
615 else
616 LogMsg("xD2DAddToCache: Unexpected result %d", result);
617 }
618
619 mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
620 {
621 D2DRecordListElem *ptr = D2DRecords;
622 D2DRecordListElem *arptr = NULL;
623
624 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
625
626 mStatus err = xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr);
627 if (err)
628 {
629 LogMsg("xD2DFindInList: xD2DParse returned error: %d", err);
630 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
631 if (arptr)
632 mDNSPlatformMemFree(arptr);
633 return NULL;
634 }
635
636 while (ptr)
637 {
638 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
639 ptr = ptr->next;
640 }
641
642 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
643 mDNSPlatformMemFree(arptr);
644 return ptr;
645 }
646
647 mDNSexport void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
648 {
649 (void)transportType; // We don't care about this, yet.
650 (void)instanceHandle; // We don't care about this, yet.
651
652 if (result == kD2DSuccess)
653 {
654 D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
655 if (ptr)
656 {
657 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
658 mDNS_Deregister(m, &ptr->ar);
659 }
660 }
661 else
662 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
663 }
664
665 mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
666 {
667 (void)m;
668 (void)key;
669 (void)keySize;
670 (void)value;
671 (void)valueSize;
672
673 if (result == kD2DSuccess)
674 {
675 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
676 if (D2DRetain) D2DRetain(instanceHandle, transportType);
677 }
678 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
679 }
680
681 mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
682 {
683 (void)m;
684 (void)instanceHandle;
685 (void)transportType;
686 (void)key;
687 (void)keySize;
688 (void)value;
689 (void)valueSize;
690
691 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
692 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
693 }
694
695 mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
696 {
697 (void)m;
698 (void)instanceHandle;
699 (void)transportType;
700 (void)key;
701 (void)keySize;
702 (void)value;
703 (void)valueSize;
704
705 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
706 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
707 }
708
709 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)
710 {
711 mDNS *m = (mDNS *) userData;
712 const char *eventString = "unknown";
713
714 KQueueLock(m);
715
716 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
717 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
718
719 switch (event)
720 {
721 case D2DServiceFound:
722 eventString = "D2DServiceFound";
723 break;
724 case D2DServiceLost:
725 eventString = "D2DServiceLost";
726 break;
727 case D2DServiceResolved:
728 eventString = "D2DServiceResolved";
729 break;
730 case D2DServiceRetained:
731 eventString = "D2DServiceRetained";
732 break;
733 case D2DServiceReleased:
734 eventString = "D2DServiceReleased";
735 break;
736 default:
737 break;
738 }
739
740 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);
741 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
742
743 switch (event)
744 {
745 case D2DServiceFound:
746 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
747 break;
748 case D2DServiceLost:
749 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
750 break;
751 case D2DServiceResolved:
752 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
753 break;
754 case D2DServiceRetained:
755 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
756 break;
757 case D2DServiceReleased:
758 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
759 break;
760 default:
761 break;
762 }
763
764 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
765 KQueueUnlock(m, "xD2DServiceCallback");
766 }
767
768 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
769 // should be called.
770 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
771 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
772 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
773
774 mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
775 {
776 NetworkInterfaceInfoOSX *info;
777
778 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
779 *excludedTransportType = D2DAWDLTransport;
780
781 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
782 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
783 {
784 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
785 *excludedTransportType = D2DTransportMax;
786 return D2DTransportMax;
787 }
788 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
789 else if (flags & kDNSServiceFlagsIncludeP2P)
790 {
791 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
792 return D2DTransportMax;
793 }
794 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
795 else if (flags & kDNSServiceFlagsIncludeAWDL)
796 {
797 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
798 return D2DAWDLTransport;
799 }
800
801 if (InterfaceID == mDNSInterface_P2P)
802 {
803 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
804 return D2DTransportMax;
805 }
806
807 // Compare to cached AWDL interface ID.
808 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
809 {
810 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
811 return D2DAWDLTransport;
812 }
813
814 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
815 if (info == NULL)
816 {
817 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
818 return D2DTransportMax;
819 }
820
821 // Recognize AirDrop specific p2p* interface based on interface name.
822 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
823 {
824 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
825 return D2DWifiPeerToPeerTransport;
826 }
827
828 // Currently there is no way to identify Bluetooth interface by name,
829 // since they use "en*" based name strings.
830
831 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
832 return D2DTransportMax;
833 }
834
835 // Similar to callExternalHelpers(), but without the checks for the BLE specific interface or flags.
836 // It's assumed that the domain was already verified to be .local once we are at this level.
837 mDNSlocal mDNSBool callInternalHelpers(mDNSInterfaceID InterfaceID, DNSServiceFlags flags)
838 {
839 if ( ((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL)))
840 || mDNSPlatformInterfaceIsD2D(InterfaceID))
841 return mDNStrue;
842 else
843 return mDNSfalse;
844 }
845
846 mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q)
847 {
848 // BLE support currently not handled by a D2D plugin
849 if (applyToBLE(InterfaceID, flags))
850 {
851 domainname lower;
852
853 DomainnameToLower(typeDomain, &lower);
854 // pass in the key and keySize
855 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
856 start_BLE_browse(q, &lower, qtype, flags, compression_lhs, end - compression_lhs);
857 }
858
859 if (callInternalHelpers(InterfaceID, flags))
860 internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
861 }
862
863 mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
864 {
865 domainname lower;
866
867 DomainnameToLower(typeDomain, &lower);
868
869 if (!D2DBrowseListRefCount(&lower, qtype))
870 {
871 D2DTransportType transportType, excludedTransport;
872
873 LogInfo("%s: Starting browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype));
874 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
875 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
876
877 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
878 if (transportType == D2DTransportMax)
879 {
880 D2DTransportType i;
881 for (i = 0; i < D2DTransportMax; i++)
882 {
883 if (i == excludedTransport) continue;
884 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
885 }
886 }
887 else
888 {
889 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
890 }
891 }
892 D2DBrowseListRetain(&lower, qtype);
893 }
894
895 mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
896 {
897 // BLE support currently not handled by a D2D plugin
898 if (applyToBLE(InterfaceID, flags))
899 {
900 domainname lower;
901
902 // If this is the last instance of this browse, clear any cached records recieved for it.
903 // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
904 DomainnameToLower(typeDomain, &lower);
905 if (stop_BLE_browse(&lower, qtype, flags))
906 xD2DClearCache(&lower, qtype);
907 }
908
909 if (callInternalHelpers(InterfaceID, flags))
910 internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
911 }
912
913 mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
914 {
915 domainname lower;
916
917 DomainnameToLower(typeDomain, &lower);
918
919 // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
920 if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype))
921 {
922 D2DTransportType transportType, excludedTransport;
923
924 LogInfo("%s: Stopping browse for: %##s %s", __func__, lower.c, DNSTypeName(qtype));
925 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
926 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
927
928 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
929 if (transportType == D2DTransportMax)
930 {
931 D2DTransportType i;
932 for (i = 0; i < D2DTransportMax; i++)
933 {
934 if (i == excludedTransport) continue;
935 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
936 }
937 }
938 else
939 {
940 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
941 }
942
943 // The D2D driver may not generate the D2DServiceLost event for this key after
944 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
945 // record cache now.
946 xD2DClearCache(&lower, qtype);
947 }
948 }
949
950 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
951 {
952 // Note, start_BLE_advertise() is currently called directly from external_start_advertising_helper() since
953 // it needs to pass the ServiceRecordSet so that we can promote the record advertisements to AWDL
954 // when we see the corresponding browse indication over BLE.
955
956 if (callInternalHelpers(resourceRecord->InterfaceID, flags))
957 internal_start_advertising_service(resourceRecord, flags);
958 }
959
960 mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
961 {
962 domainname lower;
963 mDNSu8 *rhs = NULL;
964 mDNSu8 *end = NULL;
965 D2DTransportType transportType, excludedTransport;
966 DomainnameToLower(resourceRecord->name, &lower);
967
968 LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
969
970 // For SRV records, update packet filter if p2p interface already exists, otherwise,
971 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
972 if (resourceRecord->rrtype == kDNSType_SRV)
973 mDNSUpdatePacketFilter(NULL);
974
975 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
976 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
977 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
978
979 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
980 if (transportType == D2DTransportMax)
981 {
982 D2DTransportType i;
983 for (i = 0; i < D2DTransportMax; i++)
984 {
985 if (i == excludedTransport) continue;
986 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
987 }
988 }
989 else
990 {
991 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
992 }
993 }
994
995 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
996 {
997 // BLE support currently not handled by a D2D plugin
998 if (applyToBLE(resourceRecord->InterfaceID, flags))
999 {
1000 domainname lower;
1001
1002 DomainnameToLower(resourceRecord->name, &lower);
1003 stop_BLE_advertise(&lower, resourceRecord->rrtype, flags);
1004 }
1005
1006 if (callInternalHelpers(resourceRecord->InterfaceID, flags))
1007 internal_stop_advertising_service(resourceRecord, flags);
1008 }
1009
1010 mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
1011 {
1012 domainname lower;
1013 mDNSu8 *rhs = NULL;
1014 mDNSu8 *end = NULL;
1015 D2DTransportType transportType, excludedTransport;
1016 DomainnameToLower(resourceRecord->name, &lower);
1017
1018 LogInfo("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
1019
1020 // For SRV records, update packet filter if p2p interface already exists, otherwise,
1021 // For SRV records, update packet filter to to remove this port from list
1022 if (resourceRecord->rrtype == kDNSType_SRV)
1023 mDNSUpdatePacketFilter(resourceRecord);
1024
1025 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
1026 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
1027 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
1028
1029 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
1030 if (transportType == D2DTransportMax)
1031 {
1032 D2DTransportType i;
1033 for (i = 0; i < D2DTransportMax; i++)
1034 {
1035 if (i == excludedTransport) continue;
1036 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
1037 }
1038 }
1039 else
1040 {
1041 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
1042 }
1043 }
1044
1045 mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
1046 {
1047 domainname lower;
1048 mDNSu8 *rhs = NULL;
1049 mDNSu8 *end = NULL;
1050 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
1051 D2DTransportType transportType, excludedTransport;
1052 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
1053
1054 LogInfo("external_start_resolving_service: %##s", fqdn->c);
1055 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
1056 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
1057 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
1058
1059 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
1060 if (transportType == D2DTransportMax)
1061 {
1062 // Resolving over all the transports, except for excludedTransport if set.
1063 D2DTransportType i;
1064 for (i = 0; i < D2DTransportMax; i++)
1065 {
1066 if (i == excludedTransport) continue;
1067 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
1068
1069 if (i == D2DAWDLTransport)
1070 AWDL_used = true;
1071 }
1072 }
1073 else
1074 {
1075 // Resolving over one specific transport.
1076 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
1077
1078 if (transportType == D2DAWDLTransport)
1079 AWDL_used = true;
1080 }
1081
1082 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1083 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1084 // interface and don't set any other flags.
1085 if (AWDL_used && AWDLInterfaceID)
1086 {
1087 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
1088 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0, 0);
1089 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, 0);
1090 }
1091 }
1092
1093 mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
1094 {
1095 domainname lower;
1096 mDNSu8 *rhs = NULL;
1097 mDNSu8 *end = NULL;
1098 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
1099 D2DTransportType transportType, excludedTransport;
1100 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
1101
1102 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
1103 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
1104 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
1105 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
1106
1107 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
1108 if (transportType == D2DTransportMax)
1109 {
1110 D2DTransportType i;
1111 for (i = 0; i < D2DTransportMax; i++)
1112 {
1113 if (i == excludedTransport) continue;
1114 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
1115
1116 if (i == D2DAWDLTransport)
1117 AWDL_used = true;
1118 }
1119 }
1120 else
1121 {
1122 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
1123
1124 if (transportType == D2DAWDLTransport)
1125 AWDL_used = true;
1126 }
1127
1128 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1129 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1130 // interface and don't set any other flags.
1131 if (AWDL_used && AWDLInterfaceID)
1132 {
1133 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1134 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, 0);
1135 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0);
1136 }
1137 }
1138
1139 #elif APPLE_OSX_mDNSResponder
1140
1141 mDNSexport void internal_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags }
1142 mDNSexport void internal_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
1143 mDNSexport void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1144 mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1145
1146 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; (void)q }
1147 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;}
1148 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1149 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1150 mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1151 mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1152
1153 #endif // ! NO_D2D
1154
1155 // ***************************************************************************
1156 // Functions
1157
1158 #if COMPILER_LIKES_PRAGMA_MARK
1159 #pragma mark -
1160 #pragma mark - Utility Functions
1161 #endif
1162
1163 // We only attempt to send and receive multicast packets on interfaces that are
1164 // (a) flagged as multicast-capable
1165 // (b) *not* flagged as point-to-point (e.g. modem)
1166 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1167 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1168 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1169
1170 #if BONJOUR_ON_DEMAND
1171 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1172 #else
1173 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1174 #endif
1175 #define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
1176
1177 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
1178 {
1179 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1180 #if !ForceAlerts
1181 {
1182 // Determine if we're at Apple (17.*.*.*)
1183 NetworkInterfaceInfoOSX *i;
1184 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1185 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1186 break;
1187 if (!i)
1188 return; // If not at Apple, don't show the alert
1189 }
1190 #endif
1191
1192 LogMsg("NotifyOfElusiveBug: %s", title);
1193 LogMsg("NotifyOfElusiveBug: %s", msg);
1194
1195 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1196 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1197 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180))
1198 {
1199 LogMsg("Suppressing notification early in boot: %d", mDNSPlatformRawTime());
1200 return;
1201 }
1202
1203 #ifndef NO_CFUSERNOTIFICATION
1204 static int notifyCount = 0; // To guard against excessive display of warning notifications
1205 if (notifyCount < 5)
1206 {
1207 notifyCount++;
1208 mDNSNotify(title, msg);
1209 }
1210 #endif /* NO_CFUSERNOTIFICATION */
1211
1212 }
1213
1214 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
1215 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
1216 mDNSexport void LogMemCorruption(const char *format, ...)
1217 {
1218 char buffer[512];
1219 va_list ptr;
1220 va_start(ptr,format);
1221 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
1222 va_end(ptr);
1223 LogMsg("!!!! %s !!!!", buffer);
1224 NotifyOfElusiveBug("Memory Corruption", buffer);
1225 #if ForceAlerts
1226 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
1227 #endif
1228 }
1229 #endif
1230
1231 // Like LogMemCorruption above, but only display the alert if ForceAlerts is set and we're going to generate a stack trace
1232 #if APPLE_OSX_mDNSResponder
1233 mDNSexport void LogFatalError(const char *format, ...)
1234 {
1235 char buffer[512];
1236 va_list ptr;
1237 va_start(ptr,format);
1238 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
1239 va_end(ptr);
1240 LogMsg("!!!! %s !!!!", buffer);
1241 #if ForceAlerts
1242 NotifyOfElusiveBug("Fatal Error. See /Library/Logs/DiagnosticReports", buffer);
1243 *(volatile long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
1244 #endif
1245 }
1246 #endif
1247
1248 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
1249 mDNSlocal mDNSBool IsAppleTV(void)
1250 {
1251 #if TARGET_OS_EMBEDDED
1252 static mDNSBool sInitialized = mDNSfalse;
1253 static mDNSBool sIsAppleTV = mDNSfalse;
1254 CFStringRef deviceClass = NULL;
1255
1256 if(!sInitialized)
1257 {
1258 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
1259 if(deviceClass)
1260 {
1261 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
1262 sIsAppleTV = mDNStrue;
1263 CFRelease(deviceClass);
1264 }
1265 sInitialized = mDNStrue;
1266 }
1267 return(sIsAppleTV);
1268 #else
1269 return mDNSfalse;
1270 #endif // TARGET_OS_EMBEDDED
1271 }
1272
1273 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
1274 {
1275 static struct ifaddrs *ifa = NULL;
1276
1277 if (refresh && ifa)
1278 {
1279 freeifaddrs(ifa);
1280 ifa = NULL;
1281 }
1282
1283 if (ifa == NULL)
1284 getifaddrs(&ifa);
1285 return ifa;
1286 }
1287
1288 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
1289 {
1290 CFStringRef sckey = NULL;
1291 Boolean release_sckey = FALSE;
1292 CFDataRef bytes = NULL;
1293 CFPropertyListRef plist = NULL;
1294
1295 switch ((enum mDNSDynamicStoreSetConfigKey)key)
1296 {
1297 case kmDNSMulticastConfig:
1298 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
1299 break;
1300 case kmDNSDynamicConfig:
1301 sckey = CFSTR("State:/Network/DynamicDNS");
1302 break;
1303 case kmDNSPrivateConfig:
1304 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
1305 break;
1306 case kmDNSBackToMyMacConfig:
1307 sckey = CFSTR("State:/Network/BackToMyMac");
1308 break;
1309 case kmDNSSleepProxyServersState:
1310 {
1311 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
1312 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
1313 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
1314 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
1315 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
1316 release_sckey = TRUE;
1317 CFRelease(tmp);
1318 break;
1319 }
1320 case kmDNSDebugState:
1321 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
1322 break;
1323 default:
1324 LogMsg("unrecognized key %d", key);
1325 goto fin;
1326 }
1327 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
1328 valueCnt, kCFAllocatorNull)))
1329 {
1330 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
1331 goto fin;
1332 }
1333 if (NULL == (plist = CFPropertyListCreateWithData(NULL, bytes, kCFPropertyListImmutable, NULL, NULL)))
1334 {
1335 LogMsg("CFPropertyListCreateWithData of bytes failed");
1336 goto fin;
1337 }
1338 CFRelease(bytes);
1339 bytes = NULL;
1340 SCDynamicStoreSetValue(NULL, sckey, plist);
1341
1342 fin:
1343 if (NULL != bytes)
1344 CFRelease(bytes);
1345 if (NULL != plist)
1346 CFRelease(plist);
1347 if (release_sckey && sckey)
1348 CFRelease(sckey);
1349 }
1350
1351 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
1352 {
1353 CFPropertyListRef valueCopy;
1354 char *subkeyCopy = NULL;
1355 if (!value)
1356 return;
1357
1358 // We need to copy the key and value before we dispatch off the block below as the
1359 // caller will free the memory once we return from this function.
1360 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
1361 if (!valueCopy)
1362 {
1363 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
1364 return;
1365 }
1366 if (subkey)
1367 {
1368 int len = strlen(subkey);
1369 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
1370 if (!subkeyCopy)
1371 {
1372 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
1373 CFRelease(valueCopy);
1374 return;
1375 }
1376 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
1377 subkeyCopy[len] = 0;
1378 }
1379
1380 dispatch_async(dispatch_get_main_queue(), ^{
1381 CFWriteStreamRef stream = NULL;
1382 CFDataRef bytes = NULL;
1383 CFIndex ret;
1384 KQueueLock(&mDNSStorage);
1385
1386 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
1387 {
1388 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
1389 goto END;
1390 }
1391 CFWriteStreamOpen(stream);
1392 ret = CFPropertyListWrite(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1393 if (ret == 0)
1394 {
1395 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
1396 goto END;
1397 }
1398 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
1399 {
1400 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
1401 goto END;
1402 }
1403 CFWriteStreamClose(stream);
1404 CFRelease(stream);
1405 stream = NULL;
1406 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
1407
1408 END:
1409 CFRelease(valueCopy);
1410 if (NULL != stream)
1411 {
1412 CFWriteStreamClose(stream);
1413 CFRelease(stream);
1414 }
1415 if (NULL != bytes)
1416 CFRelease(bytes);
1417 if (subkeyCopy)
1418 mDNSPlatformMemFree(subkeyCopy);
1419
1420 KQueueUnlock(&mDNSStorage, "mDNSDynamicStoreSetConfig");
1421 });
1422 }
1423
1424 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1425 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1426 {
1427 NetworkInterfaceInfoOSX *i;
1428 for (i = m->p->InterfaceList; i; i = i->next)
1429 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
1430 ((type == AF_UNSPEC ) ||
1431 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1432 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
1433 return(NULL);
1434 }
1435
1436 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
1437 {
1438 struct ifaddrs *ifa;
1439 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1440 if (ifa->ifa_addr->sa_family == AF_LINK)
1441 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
1442 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1443 return -1;
1444 }
1445
1446 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
1447 {
1448 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
1449 NetworkInterfaceInfoOSX *i;
1450
1451 // Don't get tricked by inactive interfaces
1452 for (i = m->p->InterfaceList; i; i = i->next)
1453 if (i->Registered && i->scope_id == scope_id) return(i);
1454
1455 return mDNSNULL;
1456 }
1457
1458 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
1459 {
1460 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1461 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
1462 if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE);
1463 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
1464
1465 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1466 if (!ifi)
1467 {
1468 // Not found. Make sure our interface list is up to date, then try again.
1469 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
1470 mDNSMacOSXNetworkChanged(m);
1471 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1472 }
1473
1474 if (!ifi) return(mDNSNULL);
1475
1476 return(ifi->ifinfo.InterfaceID);
1477 }
1478
1479
1480 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
1481 {
1482 NetworkInterfaceInfoOSX *i;
1483 if (id == mDNSInterface_Any ) return(0);
1484 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1485 if (id == mDNSInterface_Unicast ) return(0);
1486 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
1487 if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE);
1488
1489 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
1490
1491 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
1492 for (i = m->p->InterfaceList; i; i = i->next)
1493 if (i->scope_id == scope_id) return(i->scope_id);
1494
1495 // If we are supposed to suppress network change, return "id" back
1496 if (suppressNetworkChange) return scope_id;
1497
1498 // Not found. Make sure our interface list is up to date, then try again.
1499 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
1500 mDNSMacOSXNetworkChanged(m);
1501 for (i = m->p->InterfaceList; i; i = i->next)
1502 if (i->scope_id == scope_id) return(i->scope_id);
1503
1504 return(0);
1505 }
1506
1507 #if APPLE_OSX_mDNSResponder
1508 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
1509 {
1510 if (iOSVers)
1511 return; // No ASL on iOS
1512
1513 static char buffer[512];
1514 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
1515
1516 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1517 if (uuid)
1518 {
1519 char uuidStr[37];
1520 uuid_unparse(*uuid, uuidStr);
1521 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
1522 }
1523
1524 static char domainBase[] = "com.apple.mDNSResponder.%s";
1525 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
1526 asl_set (asl_msg, "com.apple.message.domain", buffer);
1527
1528 if (result) asl_set(asl_msg, "com.apple.message.result", result);
1529 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
1530
1531 va_list ptr;
1532 va_start(ptr,fmt);
1533 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
1534 va_end(ptr);
1535
1536 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1537 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
1538 asl_set_filter(NULL, old_filter);
1539 asl_free(asl_msg);
1540 }
1541
1542
1543 mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
1544 {
1545 char buffer[16];
1546
1547 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1548
1549 // If we failed to allocate an aslmsg structure, keep accumulating
1550 // the statistics and try again at the next log interval.
1551 if (!aslmsg)
1552 {
1553 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
1554 return;
1555 }
1556
1557 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
1558
1559 if (m->rrcache_totalused_unicast)
1560 {
1561 mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
1562 }
1563 else
1564 {
1565 LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
1566 buffer[0] = 0;
1567 }
1568 asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
1569
1570 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
1571 asl_set(aslmsg,"com.apple.message.Latency0", buffer);
1572 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
1573 asl_set(aslmsg,"com.apple.message.Latency10", buffer);
1574 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
1575 asl_set(aslmsg,"com.apple.message.Latency20", buffer);
1576 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
1577 asl_set(aslmsg,"com.apple.message.Latency50", buffer);
1578 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
1579 asl_set(aslmsg,"com.apple.message.Latency100", buffer);
1580
1581 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
1582 asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
1583 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
1584 asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
1585 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
1586 asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
1587 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
1588 asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
1589
1590 // Ignore IndeterminateStatus as we don't log them
1591 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
1592 asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
1593 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
1594 asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
1595 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
1596 asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
1597 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
1598 asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
1599
1600 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
1601 asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
1602 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
1603 asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
1604 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
1605 asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
1606 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
1607 asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
1608
1609 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1610 asl_free(aslmsg);
1611 }
1612
1613 // Calculate packets per hour given total packet count and interval in seconds.
1614 // Cast one term of multiplication to (long) to use 64-bit arithmetic
1615 // and avoid a potential 32-bit overflow prior to the division.
1616 #define ONE_HOUR 3600
1617 #define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
1618
1619 // Put packet rate data in discrete buckets.
1620 mDNSlocal int mDNSBucketData(int inputData, int interval)
1621 {
1622 if (!interval)
1623 {
1624 LogMsg("mDNSBucketData: interval is zero!");
1625 return 0;
1626 }
1627
1628 int ratePerHour = PACKET_RATE(inputData, interval);
1629 int bucket;
1630
1631 if (ratePerHour == 0)
1632 bucket = 0;
1633 else if (ratePerHour <= 10)
1634 bucket = 10;
1635 else if (ratePerHour <= 100)
1636 bucket = 100;
1637 else if (ratePerHour <= 1000)
1638 bucket = 1000;
1639 else if (ratePerHour <= 5000)
1640 bucket = 5000;
1641 else if (ratePerHour <= 10000)
1642 bucket = 10000;
1643 else if (ratePerHour <= 50000)
1644 bucket = 50000;
1645 else if (ratePerHour <= 100000)
1646 bucket = 100000;
1647 else if (ratePerHour <= 250000)
1648 bucket = 250000;
1649 else if (ratePerHour <= 500000)
1650 bucket = 500000;
1651 else
1652 bucket = 1000000;
1653
1654 return bucket;
1655 }
1656
1657 mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
1658 {
1659 static mDNSs32 last_PktNum, last_MPktNum;
1660 static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
1661 static mDNSs32 last_RemoteSubnet;
1662
1663 mDNSs32 interval;
1664 char buffer[16];
1665 mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
1666 mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
1667 mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
1668 mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
1669 mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
1670
1671
1672 // save starting values for new interval
1673 last_PktNum = m->PktNum;
1674 last_MPktNum = m->MPktNum;
1675 last_UnicastPacketsSent = m->UnicastPacketsSent;
1676 last_MulticastPacketsSent = m->MulticastPacketsSent;
1677 last_RemoteSubnet = m->RemoteSubnet;
1678
1679 // Need a non-zero active time interval.
1680 if (!m->ActiveStatTime)
1681 return;
1682
1683 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
1684 interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
1685
1686 // Use a minimum of 30 minutes of awake time to calculate average packet rates.
1687 // The rounded awake interval should not be greater than the rounded reporting
1688 // interval.
1689 if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
1690 return;
1691
1692 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1693
1694 if (!aslmsg)
1695 {
1696 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
1697 return;
1698 }
1699 // log in MessageTracer format
1700 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
1701
1702 snprintf(buffer, sizeof(buffer), "%d", interval);
1703 asl_set(aslmsg,"com.apple.message.interval", buffer);
1704
1705 // log the packet rates as packets per hour
1706 snprintf(buffer, sizeof(buffer), "%d",
1707 mDNSBucketData(inUnicast, m->ActiveStatTime));
1708 asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
1709
1710 snprintf(buffer, sizeof(buffer), "%d",
1711 mDNSBucketData(inMulticast, m->ActiveStatTime));
1712 asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
1713
1714 snprintf(buffer, sizeof(buffer), "%d",
1715 mDNSBucketData(outUnicast, m->ActiveStatTime));
1716 asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
1717
1718 snprintf(buffer, sizeof(buffer), "%d",
1719 mDNSBucketData(outMulticast, m->ActiveStatTime));
1720 asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
1721
1722 snprintf(buffer, sizeof(buffer), "%d",
1723 mDNSBucketData(remoteSubnet, m->ActiveStatTime));
1724 asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
1725
1726 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1727
1728 asl_free(aslmsg);
1729 }
1730
1731 // Log multicast and unicast traffic statistics to MessageTracer on OSX
1732 mDNSexport void mDNSLogStatistics(mDNS *const m)
1733 {
1734 // MessageTracer only available on OSX
1735 if (iOSVers)
1736 return;
1737
1738 mDNSs32 currentUTC = mDNSPlatformUTC();
1739
1740 // log runtime statistics
1741 if ((currentUTC - m->NextStatLogTime) >= 0)
1742 {
1743 m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
1744 // If StatStartTime is zero, it hasn't been reinitialized yet
1745 // in the wakeup code path.
1746 if (m->StatStartTime)
1747 {
1748 m->ActiveStatTime += currentUTC - m->StatStartTime;
1749 }
1750
1751 // Only log statistics if we have recorded some active time during
1752 // this statistics interval.
1753 if (m->ActiveStatTime)
1754 {
1755 mDNSLogBonjourStatistics(m);
1756 mDNSLogDNSSECStatistics(m);
1757 }
1758
1759 // Start a new statistics gathering interval.
1760 m->StatStartTime = currentUTC;
1761 m->ActiveStatTime = 0;
1762 }
1763 }
1764
1765 #endif // APPLE_OSX_mDNSResponder
1766
1767 #if COMPILER_LIKES_PRAGMA_MARK
1768 #pragma mark -
1769 #pragma mark - UDP & TCP send & receive
1770 #endif
1771
1772 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1773 {
1774 mDNSBool result = mDNSfalse;
1775 SCNetworkConnectionFlags flags;
1776 CFDataRef remote_addr;
1777 CFMutableDictionaryRef options;
1778 SCNetworkReachabilityRef ReachRef = NULL;
1779
1780 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1781 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
1782 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
1783 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
1784 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
1785 CFRelease(options);
1786 CFRelease(remote_addr);
1787
1788 if (!ReachRef)
1789 {
1790 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
1791 goto end;
1792 }
1793 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
1794 {
1795 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
1796 goto end;
1797 }
1798 result = flags & kSCNetworkFlagsConnectionRequired;
1799
1800 end:
1801 if (ReachRef)
1802 CFRelease(ReachRef);
1803 return result;
1804 }
1805
1806 // Set traffic class for socket
1807 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
1808 {
1809 int traffic_class;
1810
1811 if (useBackgroundTrafficClass)
1812 traffic_class = SO_TC_BK_SYS;
1813 else
1814 traffic_class = SO_TC_CTL;
1815
1816 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
1817 }
1818
1819 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
1820 {
1821 if (transType == mDNSTransport_UDP)
1822 {
1823 UDPSocket* sock = (UDPSocket*) sockCxt;
1824 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
1825 }
1826 else if (transType == mDNSTransport_TCP)
1827 {
1828 TCPSocket* sock = (TCPSocket*) sockCxt;
1829 return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
1830 }
1831 else
1832 {
1833 LogInfo("mDNSPlatformGetSocktFd: invalid transport %d", transType);
1834 return kInvalidSocketRef;
1835 }
1836 }
1837
1838 mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType, DNSQuestion *q)
1839 {
1840 int sockfd;
1841 char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
1842
1843 // verify passed-in arguments exist and that sockfd is valid
1844 if (q == mDNSNULL || sockCxt == mDNSNULL || (sockfd = mDNSPlatformGetSocktFd(sockCxt, transType, addrType)) < 0)
1845 return;
1846
1847 if (q->pid)
1848 {
1849 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
1850 LogMsg("mDNSPlatformSetSocktOpt: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
1851 }
1852 else
1853 {
1854 if (setsockopt(sockfd, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
1855 LogMsg("mDNSPlatformSetSocktOpt: Delegate UUID failed %s", strerror(errno));
1856 }
1857
1858 // set the domain on the socket
1859 ConvertDomainNameToCString(&q->qname, unenc_name);
1860 if (!(ne_session_set_socket_attributes(sockfd, unenc_name, NULL)))
1861 LogInfo("mDNSPlatformSetSocktOpt: ne_session_set_socket_attributes()-> setting domain failed for %s", unenc_name);
1862
1863 int nowake = 1;
1864 if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
1865 LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
1866
1867 if ((q->flags & kDNSServiceFlagsDenyCellular) || (q->flags & kDNSServiceFlagsDenyExpensive))
1868 {
1869 #if defined(SO_RESTRICT_DENY_CELLULAR)
1870 if (q->flags & kDNSServiceFlagsDenyCellular)
1871 {
1872 int restrictions = 0;
1873 restrictions = SO_RESTRICT_DENY_CELLULAR;
1874 if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
1875 LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno));
1876 }
1877 #endif
1878 #if defined(SO_RESTRICT_DENY_EXPENSIVE)
1879 if (q->flags & kDNSServiceFlagsDenyExpensive)
1880 {
1881 int restrictions = 0;
1882 restrictions = SO_RESTRICT_DENY_EXPENSIVE;
1883 if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
1884 LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno));
1885 }
1886 #endif
1887 }
1888 }
1889
1890 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1891 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1892 // OR send via our primary v4 unicast socket
1893 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1894 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1895 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
1896 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1897 {
1898 NetworkInterfaceInfoOSX *info = mDNSNULL;
1899 struct sockaddr_storage to;
1900 int s = -1, err;
1901 mStatus result = mStatus_NoError;
1902
1903 if (InterfaceID)
1904 {
1905 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
1906 if (info == NULL)
1907 {
1908 // We may not have registered interfaces with the "core" as we may not have
1909 // seen any interface notifications yet. This typically happens during wakeup
1910 // where we might try to send DNS requests (non-SuppressUnusable questions internal
1911 // to mDNSResponder) before we receive network notifications.
1912 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
1913 return mStatus_BadParamErr;
1914 }
1915 }
1916
1917 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
1918
1919 if (dst->type == mDNSAddrType_IPv4)
1920 {
1921 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1922 sin_to->sin_len = sizeof(*sin_to);
1923 sin_to->sin_family = AF_INET;
1924 sin_to->sin_port = dstPort.NotAnInteger;
1925 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1926 s = (src ? src->ss : m->p->permanentsockets).sktv4;
1927
1928 if (info) // Specify outgoing interface
1929 {
1930 if (!mDNSAddrIsDNSMulticast(dst))
1931 {
1932 #ifdef IP_BOUND_IF
1933 if (info->scope_id == 0)
1934 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1935 else
1936 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1937 #else
1938 {
1939 static int displayed = 0;
1940 if (displayed < 1000)
1941 {
1942 displayed++;
1943 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1944 }
1945 }
1946 #endif
1947 }
1948 else
1949 #ifdef IP_MULTICAST_IFINDEX
1950 {
1951 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
1952 // We get an error when we compile on a machine that supports this option and run the binary on
1953 // a different machine that does not support it
1954 if (err < 0)
1955 {
1956 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
1957 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1958 if (err < 0 && !m->NetworkChanged)
1959 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1960 }
1961 }
1962 #else
1963 {
1964 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1965 if (err < 0 && !m->NetworkChanged)
1966 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1967
1968 }
1969 #endif
1970 }
1971 }
1972
1973 else if (dst->type == mDNSAddrType_IPv6)
1974 {
1975 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1976 sin6_to->sin6_len = sizeof(*sin6_to);
1977 sin6_to->sin6_family = AF_INET6;
1978 sin6_to->sin6_port = dstPort.NotAnInteger;
1979 sin6_to->sin6_flowinfo = 0;
1980 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1981 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1982 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1983 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1984 {
1985 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1986 if (err < 0)
1987 {
1988 char name[IFNAMSIZ];
1989 if (if_indextoname(info->scope_id, name) != NULL)
1990 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1991 else
1992 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
1993 }
1994 }
1995 #ifdef IPV6_BOUND_IF
1996 if (info) // Specify outgoing interface for non-multicast destination
1997 {
1998 if (!mDNSAddrIsDNSMulticast(dst))
1999 {
2000 if (info->scope_id == 0)
2001 LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
2002 else
2003 setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2004 }
2005 }
2006 #endif
2007 }
2008
2009 else
2010 {
2011 LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
2012 return mStatus_BadParamErr;
2013 }
2014
2015 if (s >= 0)
2016 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
2017 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
2018 else
2019 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
2020 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
2021
2022 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
2023 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
2024 if (s < 0) return(mStatus_Invalid);
2025
2026 // switch to background traffic class for this message if requested
2027 if (useBackgroundTrafficClass)
2028 setTrafficClass(s, useBackgroundTrafficClass);
2029
2030 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
2031
2032 // set traffic class back to default value
2033 if (useBackgroundTrafficClass)
2034 setTrafficClass(s, mDNSfalse);
2035
2036 if (err < 0)
2037 {
2038 static int MessageCount = 0;
2039 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
2040 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
2041 if (!mDNSAddressIsAllDNSLinkGroup(dst))
2042 {
2043 if (errno == EHOSTUNREACH) return(mStatus_HostUnreachErr);
2044 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == ENETUNREACH) return(mStatus_TransientErr);
2045 }
2046 // Don't report EHOSTUNREACH in the first three minutes after boot
2047 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
2048 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
2049 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
2050 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
2051 if (errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
2052 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2053 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
2054 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
2055 else
2056 {
2057 MessageCount++;
2058 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
2059 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",
2060 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
2061 else // If logging is enabled, remove the cap and log aggressively
2062 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",
2063 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
2064 }
2065
2066 result = mStatus_UnknownErr;
2067 }
2068
2069 return(result);
2070 }
2071
2072 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
2073 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
2074 {
2075 static unsigned int numLogMessages = 0;
2076 struct iovec databuffers = { (char *)buffer, max };
2077 struct msghdr msg;
2078 ssize_t n;
2079 struct cmsghdr *cmPtr;
2080 char ancillary[1024];
2081
2082 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
2083
2084 // Set up the message
2085 msg.msg_name = (caddr_t)from;
2086 msg.msg_namelen = *fromlen;
2087 msg.msg_iov = &databuffers;
2088 msg.msg_iovlen = 1;
2089 msg.msg_control = (caddr_t)&ancillary;
2090 msg.msg_controllen = sizeof(ancillary);
2091 msg.msg_flags = 0;
2092
2093 // Receive the data
2094 n = recvmsg(s, &msg, 0);
2095 if (n<0)
2096 {
2097 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
2098 return(-1);
2099 }
2100 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
2101 {
2102 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
2103 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
2104 return(-1);
2105 }
2106 if (msg.msg_flags & MSG_CTRUNC)
2107 {
2108 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
2109 return(-1);
2110 }
2111
2112 *fromlen = msg.msg_namelen;
2113
2114 // Parse each option out of the ancillary data.
2115 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
2116 {
2117 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
2118 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
2119 {
2120 dstaddr->type = mDNSAddrType_IPv4;
2121 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
2122 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
2123 }
2124 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
2125 {
2126 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
2127 if (sdl->sdl_nlen < IF_NAMESIZE)
2128 {
2129 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
2130 ifname[sdl->sdl_nlen] = 0;
2131 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
2132 }
2133 }
2134 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
2135 *ttl = *(u_char*)CMSG_DATA(cmPtr);
2136 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
2137 {
2138 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
2139 dstaddr->type = mDNSAddrType_IPv6;
2140 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
2141 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
2142 }
2143 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
2144 *ttl = *(int*)CMSG_DATA(cmPtr);
2145 }
2146
2147 return(n);
2148 }
2149
2150 // What is this for, and why does it use xor instead of a simple quality check? -- SC
2151 mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
2152 {
2153 NetworkInterfaceInfo *intf;
2154
2155 if (addr->type == mDNSAddrType_IPv4)
2156 {
2157 for (intf = m->HostInterfaces; intf; intf = intf->next)
2158 {
2159 if (intf->ip.type == addr->type && intf->McastTxRx)
2160 {
2161 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
2162 {
2163 return(intf->InterfaceID);
2164 }
2165 }
2166 }
2167 }
2168
2169 if (addr->type == mDNSAddrType_IPv6)
2170 {
2171 for (intf = m->HostInterfaces; intf; intf = intf->next)
2172 {
2173 if (intf->ip.type == addr->type && intf->McastTxRx)
2174 {
2175 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
2176 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
2177 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
2178 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
2179 {
2180 return(intf->InterfaceID);
2181 }
2182 }
2183 }
2184 }
2185 return(mDNSInterface_Any);
2186 }
2187
2188 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
2189 {
2190 KQSocketSet *const ss = (KQSocketSet *)context;
2191 mDNS *const m = ss->m;
2192 int err = 0, count = 0, closed = 0;
2193
2194 if (filter != EVFILT_READ)
2195 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
2196
2197 if (s1 != ss->sktv4 && s1 != ss->sktv6)
2198 {
2199 LogMsg("myKQSocketCallBack: native socket %d", s1);
2200 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
2201 }
2202
2203 while (!closed)
2204 {
2205 mDNSAddr senderAddr, destAddr = zeroAddr;
2206 mDNSIPPort senderPort;
2207 struct sockaddr_storage from;
2208 size_t fromlen = sizeof(from);
2209 char packetifname[IF_NAMESIZE] = "";
2210 mDNSu8 ttl;
2211 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
2212 if (err < 0) break;
2213
2214 if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
2215 (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
2216
2217 count++;
2218 if (from.ss_family == AF_INET)
2219 {
2220 struct sockaddr_in *s = (struct sockaddr_in*)&from;
2221 senderAddr.type = mDNSAddrType_IPv4;
2222 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
2223 senderPort.NotAnInteger = s->sin_port;
2224 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2225 }
2226 else if (from.ss_family == AF_INET6)
2227 {
2228 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
2229 senderAddr.type = mDNSAddrType_IPv6;
2230 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
2231 senderPort.NotAnInteger = sin6->sin6_port;
2232 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2233 }
2234 else
2235 {
2236 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
2237 return;
2238 }
2239
2240 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
2241 mDNSInterfaceID InterfaceID = mDNSNULL;
2242 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
2243 while (intf)
2244 {
2245 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
2246 break;
2247 intf = intf->next;
2248 }
2249
2250 // When going to sleep we deregister all our interfaces, but if the machine
2251 // takes a few seconds to sleep we may continue to receive multicasts
2252 // during that time, which would confuse mDNSCoreReceive, because as far
2253 // as it's concerned, we should have no active interfaces any more.
2254 // Hence we ignore multicasts for which we can find no matching InterfaceID.
2255 if (intf)
2256 InterfaceID = intf->ifinfo.InterfaceID;
2257 else if (mDNSAddrIsDNSMulticast(&destAddr))
2258 continue;
2259
2260 if (!InterfaceID)
2261 {
2262 InterfaceID = FindMyInterface(m, &destAddr);
2263 }
2264
2265 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
2266 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
2267
2268 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
2269 // loop when that happens, or we may try to read from an invalid FD. We do this by
2270 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
2271 // if it closes the socketset.
2272 ss->closeFlag = &closed;
2273
2274 if (ss->proxy)
2275 {
2276 m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
2277 senderPort, &destAddr, ss->port, InterfaceID, NULL);
2278 }
2279 else
2280 {
2281 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
2282 }
2283
2284 // if we didn't close, we can safely dereference the socketset, and should to
2285 // reset the closeFlag, since it points to something on the stack
2286 if (!closed) ss->closeFlag = mDNSNULL;
2287 }
2288
2289 // If a client application is put in the background, it's socket to us can go defunct and
2290 // we'll get an ENOTCONN error on that connection. Just close the socket in that case.
2291 if (err < 0 && errno == ENOTCONN)
2292 {
2293 LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
2294 close(s1);
2295 return;
2296 }
2297
2298 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
2299 {
2300 // Something is busted here.
2301 // kqueue says there is a packet, but myrecvfrom says there is not.
2302 // Try calling select() to get another opinion.
2303 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
2304 // All of this is racy, as data may have arrived after the call to select()
2305 static unsigned int numLogMessages = 0;
2306 int save_errno = errno;
2307 int so_error = -1;
2308 int so_nread = -1;
2309 int fionread = -1;
2310 socklen_t solen = sizeof(int);
2311 fd_set readfds;
2312 struct timeval timeout;
2313 int selectresult;
2314 FD_ZERO(&readfds);
2315 FD_SET(s1, &readfds);
2316 timeout.tv_sec = 0;
2317 timeout.tv_usec = 0;
2318 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
2319 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
2320 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
2321 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
2322 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
2323 if (ioctl(s1, FIONREAD, &fionread) == -1)
2324 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
2325 if (numLogMessages++ < 100)
2326 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
2327 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
2328 if (numLogMessages > 5)
2329 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
2330 "Congratulations, you've reproduced an elusive bug.\r"
2331 "Please contact the current assignee of <rdar://problem/3375328>.\r"
2332 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2333 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2334
2335 sleep(1); // After logging this error, rate limit so we don't flood syslog
2336 }
2337 }
2338
2339 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
2340 {
2341 mDNSBool c = !sock->connected;
2342 sock->connected = mDNStrue;
2343 sock->callback(sock, sock->context, c, sock->err);
2344 // Note: the callback may call CloseConnection here, which frees the context structure!
2345 }
2346
2347 #ifndef NO_SECURITYFRAMEWORK
2348
2349 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
2350 {
2351 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2352 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2353 if (ret >= 0) { *dataLength = ret; return(noErr); }
2354 *dataLength = 0;
2355 if (errno == EAGAIN ) return(errSSLWouldBlock);
2356 if (errno == ENOENT ) return(errSSLClosedGraceful);
2357 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
2358 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
2359 return(errSSLClosedAbort);
2360 }
2361
2362 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
2363 {
2364 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2365 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2366 if (ret > 0) { *dataLength = ret; return(noErr); }
2367 *dataLength = 0;
2368 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
2369 if ( errno == EAGAIN ) return(errSSLWouldBlock);
2370 if ( errno == ECONNRESET) return(errSSLClosedAbort);
2371 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
2372 return(errSSLClosedAbort);
2373 }
2374
2375 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
2376 {
2377 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
2378
2379 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
2380 if (!sock->tlsContext)
2381 {
2382 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
2383 return(mStatus_UnknownErr);
2384 }
2385
2386 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
2387 if (err)
2388 {
2389 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
2390 goto fail;
2391 }
2392
2393 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
2394 if (err)
2395 {
2396 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
2397 goto fail;
2398 }
2399
2400 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
2401 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
2402 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
2403 if (err)
2404 {
2405 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
2406 goto fail;
2407 }
2408
2409 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
2410 // (error not in OSStatus space) is okay.
2411 if (!sock->hostname.c[0])
2412 {
2413 LogMsg("ERROR: tlsSetupSock: hostname NULL");
2414 err = -1;
2415 goto fail;
2416 }
2417
2418 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
2419 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
2420 if (err)
2421 {
2422 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
2423 goto fail;
2424 }
2425
2426 return(err);
2427
2428 fail:
2429 if (sock->tlsContext)
2430 CFRelease(sock->tlsContext);
2431 return(err);
2432 }
2433
2434 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2435 mDNSlocal void doSSLHandshake(TCPSocket *sock)
2436 {
2437 mStatus err = SSLHandshake(sock->tlsContext);
2438
2439 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
2440 //defined, KQueueLock is a noop. Hence we need to serialize here
2441 //
2442 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
2443 //We need the rest of the logic also. Otherwise, we can enable the READ
2444 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
2445 //ConnFailed which means we are going to free the tcpInfo. While it
2446 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
2447 //and potentially call doTCPCallback with error which can close the fd and free the
2448 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
2449 //is already freed.
2450
2451 dispatch_async(dispatch_get_main_queue(), ^{
2452
2453 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2454
2455 if (sock->handshake == handshake_to_be_closed)
2456 {
2457 LogInfo("SSLHandshake completed after close");
2458 mDNSPlatformTCPCloseConnection(sock);
2459 }
2460 else
2461 {
2462 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2463 else LogMsg("doSSLHandshake: sock->fd is -1");
2464
2465 if (err == errSSLWouldBlock)
2466 sock->handshake = handshake_required;
2467 else
2468 {
2469 if (err)
2470 {
2471 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2472 CFRelease(sock->tlsContext);
2473 sock->tlsContext = NULL;
2474 }
2475
2476 sock->err = err ? mStatus_ConnFailed : 0;
2477 sock->handshake = handshake_completed;
2478
2479 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2480 doTcpSocketCallback(sock);
2481 }
2482 }
2483
2484 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2485 return;
2486 });
2487 }
2488 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2489 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
2490 {
2491 // Warning: Touching sock without the kqueue lock!
2492 // We're protected because sock->handshake == handshake_in_progress
2493 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
2494 mStatus err = SSLHandshake(sock->tlsContext);
2495
2496 KQueueLock(m);
2497 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2498
2499 if (sock->handshake == handshake_to_be_closed)
2500 {
2501 LogInfo("SSLHandshake completed after close");
2502 mDNSPlatformTCPCloseConnection(sock);
2503 }
2504 else
2505 {
2506 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2507 else LogMsg("doSSLHandshake: sock->fd is -1");
2508
2509 if (err == errSSLWouldBlock)
2510 sock->handshake = handshake_required;
2511 else
2512 {
2513 if (err)
2514 {
2515 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2516 CFRelease(sock->tlsContext);
2517 sock->tlsContext = NULL;
2518 }
2519
2520 sock->err = err ? mStatus_ConnFailed : 0;
2521 sock->handshake = handshake_completed;
2522
2523 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2524 doTcpSocketCallback(sock);
2525 }
2526 }
2527
2528 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2529 KQueueUnlock(m, "doSSLHandshake");
2530 return NULL;
2531 }
2532 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2533
2534 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
2535 {
2536 debugf("spawnSSLHandshake %p: entry", sock);
2537
2538 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
2539 sock->handshake = handshake_in_progress;
2540 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
2541
2542 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
2543 // to limit the number of threads used for SSLHandshake
2544 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
2545
2546 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
2547 }
2548
2549 #endif /* NO_SECURITYFRAMEWORK */
2550
2551 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
2552 {
2553 TCPSocket *sock = context;
2554 sock->err = mStatus_NoError;
2555
2556 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2557 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2558 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2559 if (filter == EVFILT_WRITE)
2560 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
2561
2562 if (sock->flags & kTCPSocketFlags_UseTLS)
2563 {
2564 #ifndef NO_SECURITYFRAMEWORK
2565 if (!sock->setup)
2566 {
2567 sock->setup = mDNStrue;
2568 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
2569 if (sock->err)
2570 {
2571 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
2572 return;
2573 }
2574 }
2575 if (sock->handshake == handshake_required)
2576 {
2577 spawnSSLHandshake(sock);
2578 return;
2579 }
2580 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
2581 {
2582 return;
2583 }
2584 else if (sock->handshake != handshake_completed)
2585 {
2586 if (!sock->err)
2587 sock->err = mStatus_UnknownErr;
2588 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
2589 }
2590 #else /* NO_SECURITYFRAMEWORK */
2591 sock->err = mStatus_UnsupportedErr;
2592 #endif /* NO_SECURITYFRAMEWORK */
2593 }
2594
2595 doTcpSocketCallback(sock);
2596 }
2597
2598 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2599 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
2600 {
2601 dispatch_queue_t queue = dispatch_get_main_queue();
2602 dispatch_source_t source;
2603 if (flags == EV_DELETE)
2604 {
2605 if (filter == EVFILT_READ)
2606 {
2607 dispatch_source_cancel(entryRef->readSource);
2608 dispatch_release(entryRef->readSource);
2609 entryRef->readSource = mDNSNULL;
2610 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
2611 }
2612 else if (filter == EVFILT_WRITE)
2613 {
2614 dispatch_source_cancel(entryRef->writeSource);
2615 dispatch_release(entryRef->writeSource);
2616 entryRef->writeSource = mDNSNULL;
2617 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
2618 }
2619 else
2620 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
2621 return 0;
2622 }
2623 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
2624
2625 if (filter == EVFILT_READ)
2626 {
2627 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
2628 }
2629 else if (filter == EVFILT_WRITE)
2630 {
2631 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
2632 }
2633 else
2634 {
2635 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
2636 return -1;
2637 }
2638 if (!source) return -1;
2639 dispatch_source_set_event_handler(source, ^{
2640
2641 mDNSs32 stime = mDNSPlatformRawTime();
2642 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
2643 mDNSs32 etime = mDNSPlatformRawTime();
2644 if (etime - stime >= WatchDogReportingThreshold)
2645 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
2646
2647 // Trigger the event delivery to the application. Even though we trigger the
2648 // event completion after handling every event source, these all will hopefully
2649 // get merged
2650 TriggerEventCompletion();
2651
2652 });
2653 dispatch_source_set_cancel_handler(source, ^{
2654 if (entryRef->fdClosed)
2655 {
2656 //LogMsg("CancelHandler: closing fd %d", fd);
2657 close(fd);
2658 }
2659 });
2660 dispatch_resume(source);
2661 if (filter == EVFILT_READ)
2662 entryRef->readSource = source;
2663 else
2664 entryRef->writeSource = source;
2665
2666 return 0;
2667 }
2668
2669 mDNSexport void KQueueLock(mDNS *const m)
2670 {
2671 (void)m; //unused
2672 }
2673 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
2674 {
2675 (void)m; //unused
2676 (void)task; //unused
2677 }
2678 #else
2679 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
2680 {
2681 struct kevent new_event;
2682 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
2683 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
2684 }
2685
2686 mDNSexport void KQueueLock(mDNS *const m)
2687 {
2688 pthread_mutex_lock(&m->p->BigMutex);
2689 m->p->BigMutexStartTime = mDNSPlatformRawTime();
2690 }
2691
2692 mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
2693 {
2694 mDNSs32 end = mDNSPlatformRawTime();
2695 (void)task;
2696 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
2697 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
2698
2699 pthread_mutex_unlock(&m->p->BigMutex);
2700
2701 char wake = 1;
2702 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
2703 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
2704 }
2705 #endif
2706
2707 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
2708 {
2709 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2710 (void) fd; //unused
2711 if (kq->readSource)
2712 {
2713 dispatch_source_cancel(kq->readSource);
2714 kq->readSource = mDNSNULL;
2715 }
2716 if (kq->writeSource)
2717 {
2718 dispatch_source_cancel(kq->writeSource);
2719 kq->writeSource = mDNSNULL;
2720 }
2721 // Close happens in the cancellation handler
2722 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
2723 kq->fdClosed = mDNStrue;
2724 #else
2725 (void)kq; //unused
2726 close(fd);
2727 #endif
2728 }
2729
2730 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2731 {
2732 KQSocketSet *cp = &sock->ss;
2733 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2734 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2735 const int on = 1; // "on" for setsockopt
2736 mStatus err;
2737
2738 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
2739 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2740
2741 // for TCP sockets, the traffic class is set once and not changed
2742 setTrafficClass(skt, useBackgroundTrafficClass);
2743
2744 if (sa_family == AF_INET)
2745 {
2746 // Bind it
2747 struct sockaddr_in addr;
2748 mDNSPlatformMemZero(&addr, sizeof(addr));
2749 addr.sin_family = AF_INET;
2750 addr.sin_port = port->NotAnInteger;
2751 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
2752 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
2753
2754 // Receive interface identifiers
2755 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2756 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
2757
2758 mDNSPlatformMemZero(&addr, sizeof(addr));
2759 socklen_t len = sizeof(addr);
2760 err = getsockname(skt, (struct sockaddr*) &addr, &len);
2761 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
2762
2763 port->NotAnInteger = addr.sin_port;
2764 }
2765 else
2766 {
2767 // Bind it
2768 struct sockaddr_in6 addr6;
2769 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2770 addr6.sin6_family = AF_INET6;
2771 addr6.sin6_port = port->NotAnInteger;
2772 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
2773 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
2774
2775 // We want to receive destination addresses and receive interface identifiers
2776 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
2777 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
2778
2779 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2780 socklen_t len = sizeof(addr6);
2781 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
2782 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
2783
2784 port->NotAnInteger = addr6.sin6_port;
2785
2786 }
2787 *s = skt;
2788 k->KQcallback = tcpKQSocketCallback;
2789 k->KQcontext = sock;
2790 k->KQtask = "mDNSPlatformTCPSocket";
2791 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2792 k->readSource = mDNSNULL;
2793 k->writeSource = mDNSNULL;
2794 k->fdClosed = mDNSfalse;
2795 #endif
2796 return mStatus_NoError;
2797 }
2798
2799 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2800 {
2801 mStatus err;
2802 (void) m;
2803
2804 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
2805 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
2806
2807 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
2808
2809 sock->ss.m = m;
2810 sock->ss.sktv4 = -1;
2811 sock->ss.sktv6 = -1;
2812 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
2813
2814 if (!err)
2815 {
2816 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
2817 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
2818 }
2819 if (err)
2820 {
2821 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
2822 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2823 return(mDNSNULL);
2824 }
2825 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
2826 sock->fd = sock->ss.sktv4;
2827 sock->callback = mDNSNULL;
2828 sock->flags = flags;
2829 sock->context = mDNSNULL;
2830 sock->setup = mDNSfalse;
2831 sock->connected = mDNSfalse;
2832 sock->handshake = handshake_required;
2833 sock->m = m;
2834 sock->err = mStatus_NoError;
2835
2836 return sock;
2837 }
2838
2839 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
2840 {
2841 KQSocketSet *cp = &sock->ss;
2842 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
2843 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
2844 mStatus err = mStatus_NoError;
2845 struct sockaddr_storage ss;
2846
2847 sock->callback = callback;
2848 sock->context = context;
2849 sock->setup = mDNSfalse;
2850 sock->connected = mDNSfalse;
2851 sock->handshake = handshake_required;
2852 sock->err = mStatus_NoError;
2853
2854 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
2855
2856 if (dst->type == mDNSAddrType_IPv4)
2857 {
2858 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
2859 mDNSPlatformMemZero(saddr, sizeof(*saddr));
2860 saddr->sin_family = AF_INET;
2861 saddr->sin_port = dstport.NotAnInteger;
2862 saddr->sin_len = sizeof(*saddr);
2863 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
2864 }
2865 else
2866 {
2867 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
2868 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
2869 saddr6->sin6_family = AF_INET6;
2870 saddr6->sin6_port = dstport.NotAnInteger;
2871 saddr6->sin6_len = sizeof(*saddr6);
2872 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
2873 }
2874
2875 // Watch for connect complete (write is ready)
2876 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2877 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
2878 {
2879 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2880 return errno;
2881 }
2882
2883 // Watch for incoming data
2884 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
2885 {
2886 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2887 return errno;
2888 }
2889
2890 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2891 {
2892 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
2893 return mStatus_UnknownErr;
2894 }
2895
2896 // We bind to the interface and all subsequent packets including the SYN will be sent out
2897 // on this interface
2898 //
2899 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
2900 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
2901 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
2902 {
2903 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
2904 if (dst->type == mDNSAddrType_IPv4)
2905 {
2906 #ifdef IP_BOUND_IF
2907 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2908 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2909 #else
2910 (void)InterfaceID; // Unused
2911 (void)info; // Unused
2912 #endif
2913 }
2914 else
2915 {
2916 #ifdef IPV6_BOUND_IF
2917 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2918 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2919 #else
2920 (void)InterfaceID; // Unused
2921 (void)info; // Unused
2922 #endif
2923 }
2924 }
2925
2926 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
2927 // from which we can infer the destination address family. Hence we need to remember that here.
2928 // Instead of remembering the address family, we remember the right fd.
2929 sock->fd = *s;
2930 sock->kqEntry = k;
2931 // initiate connection wth peer
2932 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
2933 {
2934 if (errno == EINPROGRESS) return mStatus_ConnPending;
2935 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2936 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2937 else
2938 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
2939 return mStatus_ConnFailed;
2940 }
2941
2942 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2943 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2944 return err;
2945 }
2946
2947 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2948 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
2949 {
2950 mStatus err = mStatus_NoError;
2951
2952 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
2953 if (!sock) return(mDNSNULL);
2954
2955 mDNSPlatformMemZero(sock, sizeof(*sock));
2956 sock->fd = fd;
2957 sock->flags = flags;
2958
2959 if (flags & kTCPSocketFlags_UseTLS)
2960 {
2961 #ifndef NO_SECURITYFRAMEWORK
2962 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
2963
2964 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
2965 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
2966
2967 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
2968 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
2969 #else
2970 err = mStatus_UnsupportedErr;
2971 #endif /* NO_SECURITYFRAMEWORK */
2972 }
2973 #ifndef NO_SECURITYFRAMEWORK
2974 exit:
2975 #endif
2976
2977 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
2978 return(sock);
2979 }
2980
2981 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
2982 {
2983 mDNSu16 port;
2984
2985 port = -1;
2986 if (sock)
2987 {
2988 port = sock->ss.port.NotAnInteger;
2989 }
2990 return port;
2991 }
2992
2993 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2994 {
2995 if (ss->sktv4 != -1)
2996 {
2997 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
2998 ss->sktv4 = -1;
2999 }
3000 if (ss->sktv6 != -1)
3001 {
3002 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
3003 ss->sktv6 = -1;
3004 }
3005 if (ss->closeFlag) *ss->closeFlag = 1;
3006 }
3007
3008 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
3009 {
3010 if (sock)
3011 {
3012 #ifndef NO_SECURITYFRAMEWORK
3013 if (sock->tlsContext)
3014 {
3015 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
3016 {
3017 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
3018 // When we come back from SSLHandshake, we will notice that a close was here and
3019 // call this function again which will do the cleanup then.
3020 sock->handshake = handshake_to_be_closed;
3021 return;
3022 }
3023
3024 SSLClose(sock->tlsContext);
3025 CFRelease(sock->tlsContext);
3026 sock->tlsContext = NULL;
3027 }
3028 #endif /* NO_SECURITYFRAMEWORK */
3029 if (sock->ss.sktv4 != -1)
3030 shutdown(sock->ss.sktv4, 2);
3031 if (sock->ss.sktv6 != -1)
3032 shutdown(sock->ss.sktv6, 2);
3033 CloseSocketSet(&sock->ss);
3034 sock->fd = -1;
3035
3036 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
3037 }
3038 }
3039
3040 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
3041 {
3042 ssize_t nread = 0;
3043 *closed = mDNSfalse;
3044
3045 if (sock->flags & kTCPSocketFlags_UseTLS)
3046 {
3047 #ifndef NO_SECURITYFRAMEWORK
3048 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
3049 else if (sock->handshake == handshake_in_progress) return 0;
3050 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
3051
3052 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
3053 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
3054 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
3055 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
3056 else if (err && err != errSSLWouldBlock)
3057 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
3058 #else
3059 nread = -1;
3060 *closed = mDNStrue;
3061 #endif /* NO_SECURITYFRAMEWORK */
3062 }
3063 else
3064 {
3065 static int CLOSEDcount = 0;
3066 static int EAGAINcount = 0;
3067 nread = recv(sock->fd, buf, buflen, 0);
3068
3069 if (nread > 0)
3070 {
3071 CLOSEDcount = 0;
3072 EAGAINcount = 0;
3073 } // On success, clear our error counters
3074 else if (nread == 0)
3075 {
3076 *closed = mDNStrue;
3077 if ((++CLOSEDcount % 1000) == 0)
3078 {
3079 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
3080 assert(CLOSEDcount < 1000);
3081 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
3082 // crash mDNSResponder using assert() and restart fresh. See advantages below:
3083 // 1.Better User Experience
3084 // 2.CrashLogs frequency can be monitored
3085 // 3.StackTrace can be used for more info
3086 }
3087 }
3088 // else nread is negative -- see what kind of error we got
3089 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
3090 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
3091 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
3092 {
3093 nread = 0;
3094 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
3095 }
3096 }
3097
3098 return nread;
3099 }
3100
3101 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
3102 {
3103 int nsent;
3104
3105 if (sock->flags & kTCPSocketFlags_UseTLS)
3106 {
3107 #ifndef NO_SECURITYFRAMEWORK
3108 size_t processed;
3109 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
3110 if (sock->handshake == handshake_in_progress) return 0;
3111 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
3112
3113 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
3114
3115 if (!err) nsent = (int) processed;
3116 else if (err == errSSLWouldBlock) nsent = 0;
3117 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
3118 #else
3119 nsent = -1;
3120 #endif /* NO_SECURITYFRAMEWORK */
3121 }
3122 else
3123 {
3124 nsent = send(sock->fd, msg, len, 0);
3125 if (nsent < 0)
3126 {
3127 if (errno == EAGAIN) nsent = 0;
3128 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
3129 }
3130 }
3131
3132 return nsent;
3133 }
3134
3135 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
3136 {
3137 return sock->fd;
3138 }
3139
3140 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
3141 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
3142 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
3143 {
3144 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
3145 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
3146 const int on = 1;
3147 const int twofivefive = 255;
3148 mStatus err = mStatus_NoError;
3149 char *errstr = mDNSNULL;
3150 const int mtu = 0;
3151
3152 cp->closeFlag = mDNSNULL;
3153
3154 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
3155 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
3156
3157 // set default traffic class
3158 setTrafficClass(skt, mDNSfalse);
3159
3160 #ifdef SO_RECV_ANYIF
3161 // Enable inbound packets on IFEF_AWDL interface.
3162 // Only done for multicast sockets, since we don't expect unicast socket operations
3163 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
3164 if (mDNSSameIPPort(port, MulticastDNSPort))
3165 {
3166 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
3167 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
3168 }
3169 #endif // SO_RECV_ANYIF
3170
3171 // ... with a shared UDP port, if it's for multicast receiving
3172 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort))
3173 {
3174 err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
3175 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
3176 }
3177
3178 // Don't want to wake from sleep for inbound packets on the mDNS sockets
3179 if (mDNSSameIPPort(port, MulticastDNSPort))
3180 {
3181 int nowake = 1;
3182 if (setsockopt(skt, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
3183 LogInfo("SetupSocket: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
3184 }
3185
3186 if (sa_family == AF_INET)
3187 {
3188 // We want to receive destination addresses
3189 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
3190 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
3191
3192 // We want to receive interface identifiers
3193 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
3194 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
3195
3196 // We want to receive packet TTL value so we can check it
3197 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
3198 if (err < 0) { errstr = "setsockopt - IP_RECVTTL"; goto fail; }
3199
3200 // Send unicast packets with TTL 255
3201 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
3202 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
3203
3204 // And multicast packets with TTL 255 too
3205 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
3206 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
3207
3208 // And start listening for packets
3209 struct sockaddr_in listening_sockaddr;
3210 listening_sockaddr.sin_family = AF_INET;
3211 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3212 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
3213 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
3214 if (err) { errstr = "bind"; goto fail; }
3215 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
3216 }
3217 else if (sa_family == AF_INET6)
3218 {
3219 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
3220 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; close(skt); return mStatus_NoError; }
3221
3222 // We want to receive destination addresses and receive interface identifiers
3223 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
3224 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
3225
3226 // We want to receive packet hop count value so we can check it
3227 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
3228 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
3229
3230 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
3231 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
3232 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
3233 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
3234
3235 // Send unicast packets with TTL 255
3236 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
3237 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
3238
3239 // And multicast packets with TTL 255 too
3240 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
3241 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
3242
3243 // Want to receive our own packets
3244 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
3245 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
3246
3247 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
3248 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
3249 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
3250 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
3251 skt, err, errno, strerror(errno));
3252
3253 // And start listening for packets
3254 struct sockaddr_in6 listening_sockaddr6;
3255 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
3256 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
3257 listening_sockaddr6.sin6_family = AF_INET6;
3258 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3259 listening_sockaddr6.sin6_flowinfo = 0;
3260 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
3261 listening_sockaddr6.sin6_scope_id = 0;
3262 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
3263 if (err) { errstr = "bind"; goto fail; }
3264 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
3265 }
3266
3267 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
3268 fcntl(skt, F_SETFD, 1); // set close-on-exec
3269 *s = skt;
3270 k->KQcallback = myKQSocketCallBack;
3271 k->KQcontext = cp;
3272 k->KQtask = "UDP packet reception";
3273 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3274 k->readSource = mDNSNULL;
3275 k->writeSource = mDNSNULL;
3276 k->fdClosed = mDNSfalse;
3277 #endif
3278 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
3279
3280 return(mStatus_NoError);
3281
3282 fail:
3283 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
3284 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
3285 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
3286
3287 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
3288 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
3289 {
3290 err = EADDRINUSE;
3291 if (mDNSSameIPPort(port, MulticastDNSPort))
3292 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
3293 "Congratulations, you've reproduced an elusive bug.\r"
3294 "Please contact the current assignee of <rdar://problem/3814904>.\r"
3295 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
3296 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
3297 }
3298
3299 mDNSPlatformCloseFD(k, skt);
3300 return(err);
3301 }
3302
3303 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
3304 {
3305 mStatus err;
3306 mDNSIPPort port = requestedport;
3307 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
3308 int i = 10000; // Try at most 10000 times to get a unique random port
3309 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
3310 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
3311 mDNSPlatformMemZero(p, sizeof(UDPSocket));
3312 p->ss.port = zeroIPPort;
3313 p->ss.m = m;
3314 p->ss.sktv4 = -1;
3315 p->ss.sktv6 = -1;
3316 p->ss.proxy = mDNSfalse;
3317
3318 do
3319 {
3320 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
3321 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
3322 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
3323 if (!err)
3324 {
3325 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
3326 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
3327 }
3328 i--;
3329 } while (err == EADDRINUSE && randomizePort && i);
3330
3331 if (err)
3332 {
3333 // In customer builds we don't want to log failures with port 5351, because this is a known issue
3334 // of failing to bind to this port when Internet Sharing has already bound to it
3335 // We also don't want to log about port 5350, due to a known bug when some other
3336 // process is bound to it.
3337 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
3338 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3339 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3340 freeL("UDPSocket", p);
3341 return(mDNSNULL);
3342 }
3343 return(p);
3344 }
3345
3346 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
3347 {
3348 CloseSocketSet(&sock->ss);
3349 freeL("UDPSocket", sock);
3350 }
3351
3352 #if COMPILER_LIKES_PRAGMA_MARK
3353 #pragma mark -
3354 #pragma mark - BPF Raw packet sending/receiving
3355 #endif
3356
3357 #if APPLE_OSX_mDNSResponder
3358
3359 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
3360 {
3361 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
3362 NetworkInterfaceInfoOSX *info;
3363
3364 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
3365 if (info == NULL)
3366 {
3367 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
3368 return;
3369 }
3370 if (info->BPF_fd < 0)
3371 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
3372 else
3373 {
3374 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
3375 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
3376 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
3377 }
3378 }
3379
3380 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
3381 {
3382 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
3383 NetworkInterfaceInfoOSX *info;
3384 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
3385 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
3386 // Manually inject an entry into our local ARP cache.
3387 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
3388 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa))
3389 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3390 else
3391 {
3392 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
3393 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
3394 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3395 }
3396 }
3397
3398 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
3399 {
3400 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
3401 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3402 // close will happen in the cancel handler
3403 dispatch_source_cancel(i->BPF_source);
3404 #else
3405
3406 // Note: MUST NOT close() the underlying native BSD sockets.
3407 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
3408 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
3409 CFRunLoopRemoveSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
3410 CFRelease(i->BPF_rls);
3411 CFSocketInvalidate(i->BPF_cfs);
3412 CFRelease(i->BPF_cfs);
3413 #endif
3414 i->BPF_fd = -1;
3415 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
3416 }
3417
3418 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
3419 {
3420 KQueueLock(info->m);
3421
3422 // 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
3423 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
3424 if (info->BPF_fd < 0) goto exit;
3425
3426 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
3427 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
3428 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
3429 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
3430
3431 if (n<0)
3432 {
3433 /* <rdar://problem/10287386>
3434 * sometimes there can be a race condition btw when the bpf socket
3435 * gets data and the callback get scheduled and when we call BIOCSETF (which
3436 * clears the socket). this can cause the read to hang for a really long time
3437 * and effectively prevent us from responding to requests for long periods of time.
3438 * to prevent this make the socket non blocking and just bail if we dont get anything
3439 */
3440 if (errno == EAGAIN)
3441 {
3442 LogMsg("bpf_callback got EAGAIN bailing");
3443 goto exit;
3444 }
3445 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
3446 CloseBPF(info);
3447 goto exit;
3448 }
3449
3450 while (ptr < end)
3451 {
3452 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
3453 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
3454 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
3455 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
3456 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
3457 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
3458 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
3459 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
3460 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
3461 }
3462 exit:
3463 KQueueUnlock(info->m, "bpf_callback");
3464 }
3465 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3466 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
3467 {
3468 bpf_callback_common(info);
3469 }
3470 #else
3471 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
3472 {
3473 (void)cfs;
3474 (void)CallBackType;
3475 (void)address;
3476 (void)data;
3477 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
3478 }
3479 #endif
3480
3481 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
3482 {
3483 LogMsg("mDNSPlatformSendKeepalive called\n");
3484 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
3485 }
3486
3487 mDNSexport mStatus mDNSPlatformClearSPSData(void)
3488 {
3489 CFStringRef spsAddress = NULL;
3490 CFStringRef ownerOPTRec = NULL;
3491
3492 if ((spsAddress = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
3493 {
3494 if (SCDynamicStoreRemoveValue(NULL, spsAddress) == false)
3495 LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy address key");
3496 }
3497
3498 if((ownerOPTRec = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyOPTRecord")))
3499 {
3500 if (SCDynamicStoreRemoveValue(NULL, ownerOPTRec) == false)
3501 LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy owner option record key");
3502 }
3503
3504 if (spsAddress) CFRelease(spsAddress);
3505 if (ownerOPTRec) CFRelease(ownerOPTRec);
3506 return KERN_SUCCESS;
3507 }
3508
3509 mDNSlocal int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
3510 {
3511 struct
3512 {
3513 struct rt_msghdr m_rtm;
3514 char m_space[512];
3515 } m_rtmsg;
3516
3517 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
3518 char *cp = m_rtmsg.m_space;
3519 int seq = 6367, sock, rlen, i;
3520 struct sockaddr_in *sin = NULL;
3521 struct sockaddr_in6 *sin6 = NULL;
3522 struct sockaddr_dl *sdl = NULL;
3523 struct sockaddr_storage sins;
3524 struct sockaddr_dl sdl_m;
3525
3526 #define NEXTADDR(w, s, len) \
3527 if (rtm->rtm_addrs & (w)) \
3528 { \
3529 bcopy((char *)s, cp, len); \
3530 cp += len; \
3531 }
3532
3533 bzero(&sins, sizeof(struct sockaddr_storage));
3534 bzero(&sdl_m, sizeof(struct sockaddr_dl));
3535 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
3536
3537 sock = socket(PF_ROUTE, SOCK_RAW, 0);
3538 if (sock < 0)
3539 {
3540 LogMsg("getMACAddress: Can not open the socket - %s", strerror(errno));
3541 return errno;
3542 }
3543
3544 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
3545 rtm->rtm_type = RTM_GET;
3546 rtm->rtm_flags = 0;
3547 rtm->rtm_version = RTM_VERSION;
3548 rtm->rtm_seq = ++seq;
3549
3550 sdl_m.sdl_len = sizeof(sdl_m);
3551 sdl_m.sdl_family = AF_LINK;
3552 if (family == AF_INET)
3553 {
3554 sin = (struct sockaddr_in*)&sins;
3555 sin->sin_family = AF_INET;
3556 sin->sin_len = sizeof(struct sockaddr_in);
3557 memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
3558 NEXTADDR(RTA_DST, sin, sin->sin_len);
3559 }
3560 else if (family == AF_INET6)
3561 {
3562 sin6 = (struct sockaddr_in6 *)&sins;
3563 sin6->sin6_len = sizeof(struct sockaddr_in6);
3564 sin6->sin6_family = AF_INET6;
3565 memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
3566 NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
3567 }
3568 NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
3569 rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
3570
3571 if (write(sock, (char *)&m_rtmsg, rlen) < 0)
3572 {
3573 LogMsg("getMACAddress: writing to routing socket: %s", strerror(errno));
3574 close(sock);
3575 return errno;
3576 }
3577
3578 do
3579 {
3580 rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
3581 }
3582 while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
3583
3584 if (rlen < 0)
3585 LogMsg("getMACAddress: Read from routing socket failed");
3586
3587 if (family == AF_INET)
3588 {
3589 sin = (struct sockaddr_in *) (rtm + 1);
3590 sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
3591 }
3592 else if (family == AF_INET6)
3593 {
3594 sin6 = (struct sockaddr_in6 *) (rtm +1);
3595 sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
3596 }
3597
3598 if (!sdl)
3599 {
3600 LogMsg("getMACAddress: sdl is NULL for family %d", family);
3601 close(sock);
3602 return -1;
3603 }
3604
3605 // If the address is not on the local net, we get the IP address of the gateway.
3606 // We would have to repeat the process to get the MAC address of the gateway
3607 *gfamily = sdl->sdl_family;
3608 if (sdl->sdl_family == AF_INET)
3609 {
3610 if (sin)
3611 {
3612 struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
3613 memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
3614 }
3615 else
3616 {
3617 LogMsg("getMACAddress: sin is NULL");
3618 }
3619 close(sock);
3620 return -1;
3621 }
3622 else if (sdl->sdl_family == AF_INET6)
3623 {
3624 if (sin6)
3625 {
3626 struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
3627 memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
3628 }
3629 else
3630 {
3631 LogMsg("getMACAddress: sin6 is NULL");
3632 }
3633 close(sock);
3634 return -1;
3635 }
3636
3637 unsigned char *ptr = (unsigned char *)LLADDR(sdl);
3638 for (i = 0; i < ETHER_ADDR_LEN; i++)
3639 (eth)[i] = *(ptr +i);
3640
3641 close(sock);
3642
3643 return KERN_SUCCESS;
3644 }
3645
3646 mDNSlocal int GetRemoteMacinternal(int family, v6addr_t raddr, ethaddr_t eth)
3647 {
3648 int ret = 0;
3649 v6addr_t gateway;
3650 int gfamily = 0;
3651 int count = 0;
3652
3653 do
3654 {
3655 ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
3656 if (ret == -1)
3657 {
3658 memcpy(raddr, gateway, sizeof(family));
3659 family = gfamily;
3660 count++;
3661 }
3662 }
3663 while ((ret == -1) && (count < 5));
3664 return ret;
3665 }
3666
3667 mDNSlocal int StoreSPSMACAddressinternal(int family, v6addr_t spsaddr, const char *ifname)
3668 {
3669 ethaddr_t eth;
3670 char spsip[INET6_ADDRSTRLEN];
3671 int ret = 0;
3672 CFStringRef sckey = NULL;
3673 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
3674 SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
3675 CFMutableDictionaryRef dict = NULL;
3676 CFStringRef entityname = NULL;
3677 CFDictionaryRef ipdict = NULL;
3678 CFArrayRef addrs = NULL;
3679
3680 if ((store == NULL) || (ipstore == NULL))
3681 {
3682 LogMsg("StoreSPSMACAddressinternal: Unable to accesss SC Dynamic Store");
3683 ret = -1;
3684 goto fin;
3685 }
3686
3687 // Get the MAC address of the Sleep Proxy Server
3688 memset(eth, 0, sizeof(eth));
3689 ret = GetRemoteMacinternal(family, spsaddr, eth);
3690 if (ret != 0)
3691 {
3692 LogMsg("StoreSPSMACAddressinternal: Failed to determine the MAC address");
3693 goto fin;
3694 }
3695
3696 // Create/Update the dynamic store entry for the specified interface
3697 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
3698 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3699 if (!dict)
3700 {
3701 LogMsg("StoreSPSMACAddressinternal: SPSCreateDict() Could not create CFDictionary dict");
3702 ret = -1;
3703 goto fin;
3704 }
3705
3706 CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
3707 CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
3708 if (NULL != macaddr)
3709 CFRelease(macaddr);
3710
3711 if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
3712 {
3713 LogMsg("StoreSPSMACAddressinternal: inet_ntop failed: %s", strerror(errno));
3714 ret = -1;
3715 goto fin;
3716 }
3717
3718 CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
3719 CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
3720 if (NULL != ipaddr)
3721 CFRelease(ipaddr);
3722
3723 // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
3724 if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
3725 {
3726 if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
3727 {
3728 if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
3729 {
3730 addrs = CFRetain(addrs);
3731 CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
3732 }
3733 }
3734 }
3735 SCDynamicStoreSetValue(store, sckey, dict);
3736
3737 fin:
3738 if (store) CFRelease(store);
3739 if (ipstore) CFRelease(ipstore);
3740 if (sckey) CFRelease(sckey);
3741 if (dict) CFRelease(dict);
3742 if (ipdict) CFRelease(ipdict);
3743 if (entityname) CFRelease(entityname);
3744 if (addrs) CFRelease(addrs);
3745
3746 return ret;
3747 }
3748
3749 mDNSlocal void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
3750 {
3751 struct
3752 {
3753 v6addr_t saddr;
3754 } addr;
3755 int err = 0;
3756
3757 mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
3758
3759 err = StoreSPSMACAddressinternal(family, (uint8_t *)addr.saddr, ifname);
3760 if (err != 0)
3761 LogMsg("mDNSStoreSPSMACAddress : failed");
3762 }
3763
3764 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
3765 {
3766 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3767
3768 LogInfo("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
3769 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
3770
3771 return KERN_SUCCESS;
3772 }
3773
3774
3775 mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage* msg, int length)
3776 {
3777 int ret = 0;
3778 CFStringRef sckey = NULL;
3779 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreOwnerOPTRecord"), NULL, NULL);
3780 CFMutableDictionaryRef dict = NULL;
3781
3782 if (store == NULL)
3783 {
3784 LogMsg("mDNSPlatformStoreOwnerOptRecord: Unable to accesss SC Dynamic Store");
3785 ret = -1;
3786 goto fin;
3787 }
3788
3789 // Create/Update the dynamic store entry for the specified interface
3790 sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyOPTRecord");
3791 dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3792 if (!dict)
3793 {
3794 LogMsg("mDNSPlatformStoreOwnerOptRecord: Could not create CFDictionary dictionary to store OPT Record");
3795 ret =-1;
3796 goto fin;
3797 }
3798
3799 CFDataRef optRec = NULL;
3800 optRec = CFDataCreate(NULL, (const uint8_t *)msg, (CFIndex)length);
3801 CFDictionarySetValue(dict, CFSTR("OwnerOPTRecord"), optRec);
3802 if (NULL != optRec) CFRelease(optRec);
3803
3804 SCDynamicStoreSetValue(store, sckey, dict);
3805
3806 fin:
3807 if (NULL != store) CFRelease(store);
3808 if (NULL != sckey) CFRelease(sckey);
3809 if (NULL != dict) CFRelease(dict);
3810 return ret;
3811 }
3812
3813 mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr)
3814 {
3815 ethaddr_t eth;
3816 IPAddressMACMapping *addrMapping;
3817 int kr = KERN_FAILURE;
3818 struct
3819 {
3820 v6addr_t addr;
3821 } dst;
3822
3823 mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
3824
3825 kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
3826
3827 // If the call to get the remote MAC address succeeds, allocate and copy
3828 // the values and schedule a task to update the MAC address in the TCP Keepalive record.
3829 if (kr == 0)
3830 {
3831 addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
3832 snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
3833 eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
3834 if (family == AF_INET)
3835 {
3836 addrMapping->ipaddr.type = mDNSAddrType_IPv4;
3837 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
3838 }
3839 else
3840 {
3841 addrMapping->ipaddr.type = mDNSAddrType_IPv6;
3842 mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
3843 }
3844 UpdateRMAC(m, addrMapping);
3845 }
3846 }
3847
3848 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
3849 {
3850 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3851
3852 LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
3853 mDNSGet_RemoteMAC(m, family, raddr->ip.v6.b);
3854
3855 return KERN_SUCCESS;
3856 }
3857
3858 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
3859 {
3860 mDNSs32 intfid;
3861 mDNSs32 error = 0;
3862 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3863
3864 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);
3865 if (error != KERN_SUCCESS)
3866 {
3867 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
3868 return error;
3869 }
3870 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
3871 return error;
3872 }
3873
3874 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
3875
3876 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
3877 {
3878 int numv4 = 0, numv6 = 0;
3879 AuthRecord *rr;
3880
3881 for (rr = m->ResourceRecords; rr; rr=rr->next)
3882 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3883 {
3884 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
3885 numv4++;
3886 }
3887
3888 for (rr = m->ResourceRecords; rr; rr=rr->next)
3889 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3890 {
3891 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
3892 numv6++;
3893 }
3894
3895 if (p4) *p4 = numv4;
3896 if (p6) *p6 = numv6;
3897 return(numv4 + numv6);
3898 }
3899
3900 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
3901 {
3902 NetworkInterfaceInfoOSX *x;
3903
3904 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3905 for (x = m->p->InterfaceList; x; x = x->next) if ((x->ifinfo.InterfaceID == InterfaceID) && (x->BPF_fd >= 0)) break;
3906
3907 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
3908
3909 #define MAX_BPF_ADDRS 250
3910 int numv4 = 0, numv6 = 0;
3911
3912 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
3913 {
3914 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
3915 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
3916 numv6 = MAX_BPF_ADDRS - numv4;
3917 }
3918
3919 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
3920
3921 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3922 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3923 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
3924 {
3925 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
3926
3927 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
3928 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
3929
3930 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3931
3932 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
3933 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
3934 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3935 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
3936
3937 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3938 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
3939 };
3940
3941 struct bpf_insn *pc = &filter[9];
3942 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
3943 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
3944 struct bpf_insn *ret4 = fail + 1;
3945 struct bpf_insn *ret6 = ret4 + 4;
3946
3947 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
3948
3949 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
3950
3951 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
3952 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)
3953 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
3954 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3955
3956 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3957
3958 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
3959 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
3960
3961 // BPF Byte-Order Note
3962 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3963 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3964 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3965 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3966 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3967 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3968 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3969 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3970 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3971 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3972
3973 // IPSEC capture size notes:
3974 // 8 bytes UDP header
3975 // 4 bytes Non-ESP Marker
3976 // 28 bytes IKE Header
3977 // --
3978 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3979
3980 AuthRecord *rr;
3981 for (rr = m->ResourceRecords; rr; rr=rr->next)
3982 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3983 {
3984 mDNSv4Addr a = rr->AddressProxy.ip.v4;
3985 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3986 BPF_SetOffset(pc, jt, ret4);
3987 pc->jf = 0;
3988 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];
3989 pc++;
3990 }
3991 *pc++ = rf;
3992
3993 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
3994 *pc++ = g6; // chk6 points here
3995
3996 // First cancel any previous ND group memberships we had, then create a fresh socket
3997 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
3998 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
3999
4000 for (rr = m->ResourceRecords; rr; rr=rr->next)
4001 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
4002 {
4003 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
4004 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
4005 BPF_SetOffset(pc, jt, ret6);
4006 pc->jf = 0;
4007 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];
4008 pc++;
4009
4010 struct ipv6_mreq i6mr;
4011 i6mr.ipv6mr_interface = x->scope_id;
4012 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
4013 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
4014 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
4015 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
4016
4017 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
4018 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
4019 if (err < 0 && (errno != EADDRNOTAVAIL))
4020 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4021
4022 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
4023 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
4024 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
4025
4026 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
4027 }
4028
4029 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
4030 *pc++ = rf; // fail points here
4031
4032 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
4033 *pc++ = r4a; // ret4 points here
4034 *pc++ = r4b;
4035 *pc++ = r4c;
4036 *pc++ = r4d;
4037
4038 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
4039 *pc++ = r6a; // ret6 points here
4040
4041 struct bpf_program prog = { pc - filter, filter };
4042
4043 #if 0
4044 // For debugging BPF filter program
4045 unsigned int q;
4046 for (q=0; q<prog.bf_len; q++)
4047 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);
4048 #endif
4049
4050 if (!numv4 && !numv6)
4051 {
4052 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
4053 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
4054 // Schedule check to see if we can close this BPF_fd now
4055 if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
4056 // prog.bf_len = 0; This seems to panic the kernel
4057 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
4058 }
4059
4060 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
4061 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
4062 }
4063
4064 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
4065 {
4066 mDNS_Lock(m);
4067
4068 NetworkInterfaceInfoOSX *i;
4069 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
4070 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
4071 else
4072 {
4073 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
4074
4075 struct bpf_version v;
4076 if (ioctl(fd, BIOCVERSION, &v) < 0)
4077 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4078 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
4079 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
4080 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
4081
4082 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
4083 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4084
4085 if (i->BPF_len > sizeof(m->imsg))
4086 {
4087 i->BPF_len = sizeof(m->imsg);
4088 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
4089 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4090 else
4091 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
4092 }
4093
4094 static const u_int opt_one = 1;
4095 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
4096 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4097
4098 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
4099 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4100
4101 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
4102 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4103
4104 /* <rdar://problem/10287386>
4105 * make socket non blocking see comments in bpf_callback_common for more info
4106 */
4107 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
4108 {
4109 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
4110 }
4111
4112 struct ifreq ifr;
4113 mDNSPlatformMemZero(&ifr, sizeof(ifr));
4114 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
4115 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
4116 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
4117 else
4118 {
4119 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
4120 i->BPF_fd = fd;
4121 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
4122 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
4123 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
4124 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
4125 dispatch_resume(i->BPF_source);
4126 #else
4127 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
4128 i->BPF_fd = fd;
4129 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
4130 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
4131 CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
4132 #endif
4133 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
4134 }
4135 }
4136
4137 mDNS_Unlock(m);
4138 }
4139
4140 #endif // APPLE_OSX_mDNSResponder
4141
4142 #if COMPILER_LIKES_PRAGMA_MARK
4143 #pragma mark -
4144 #pragma mark - Key Management
4145 #endif
4146
4147 #ifndef NO_SECURITYFRAMEWORK
4148 mDNSlocal CFArrayRef CopyCertChain(SecIdentityRef identity)
4149 {
4150 CFMutableArrayRef certChain = NULL;
4151 if (!identity) { LogMsg("CopyCertChain: identity is NULL"); return(NULL); }
4152 SecCertificateRef cert;
4153 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
4154 if (err || !cert) LogMsg("CopyCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
4155 else
4156 {
4157 #pragma clang diagnostic push
4158 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4159 SecPolicySearchRef searchRef;
4160 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
4161 if (err || !searchRef) LogMsg("CopyCertChain: SecPolicySearchCreate() returned %d", (int) err);
4162 else
4163 {
4164 SecPolicyRef policy;
4165 err = SecPolicySearchCopyNext(searchRef, &policy);
4166 if (err || !policy) LogMsg("CopyCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
4167 else
4168 {
4169 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
4170 if (!wrappedCert) LogMsg("CopyCertChain: wrappedCert is NULL");
4171 else
4172 {
4173 SecTrustRef trust;
4174 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
4175 if (err || !trust) LogMsg("CopyCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
4176 else
4177 {
4178 err = SecTrustEvaluate(trust, NULL);
4179 if (err) LogMsg("CopyCertChain: SecTrustEvaluate() returned %d", (int) err);
4180 else
4181 {
4182 CFArrayRef rawCertChain;
4183 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
4184 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
4185 if (err || !rawCertChain || !statusChain) LogMsg("CopyCertChain: SecTrustGetResult() returned %d", (int) err);
4186 else
4187 {
4188 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
4189 if (!certChain) LogMsg("CopyCertChain: certChain is NULL");
4190 else
4191 {
4192 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
4193 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
4194 CFArraySetValueAtIndex(certChain, 0, identity);
4195 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
4196 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
4197 }
4198 CFRelease(rawCertChain);
4199 // Do not free statusChain:
4200 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
4201 // certChain: Call the CFRelease function to release this object when you are finished with it.
4202 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
4203 }
4204 }
4205 CFRelease(trust);
4206 }
4207 CFRelease(wrappedCert);
4208 }
4209 CFRelease(policy);
4210 }
4211 CFRelease(searchRef);
4212 }
4213 #pragma clang diagnostic pop
4214 CFRelease(cert);
4215 }
4216 return certChain;
4217 }
4218 #endif /* NO_SECURITYFRAMEWORK */
4219
4220 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
4221 {
4222 #ifdef NO_SECURITYFRAMEWORK
4223 return mStatus_UnsupportedErr;
4224 #else
4225 SecIdentityRef identity = nil;
4226 SecIdentitySearchRef srchRef = nil;
4227 OSStatus err;
4228
4229 #pragma clang diagnostic push
4230 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4231 // search for "any" identity matching specified key use
4232 // In this app, we expect there to be exactly one
4233 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
4234 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
4235
4236 err = SecIdentitySearchCopyNext(srchRef, &identity);
4237 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
4238 #pragma clang diagnostic pop
4239
4240 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
4241 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
4242
4243 // Found one. Call CopyCertChain to create the correct certificate chain.
4244 ServerCerts = CopyCertChain(identity);
4245 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: CopyCertChain error"); return mStatus_UnknownErr; }
4246
4247 return mStatus_NoError;
4248 #endif /* NO_SECURITYFRAMEWORK */
4249 }
4250
4251 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
4252 {
4253 #ifndef NO_SECURITYFRAMEWORK
4254 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
4255 #endif /* NO_SECURITYFRAMEWORK */
4256 }
4257
4258 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
4259 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
4260 {
4261 CFStringEncoding encoding = kCFStringEncodingUTF8;
4262 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
4263 if (cfs)
4264 {
4265 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
4266 CFRelease(cfs);
4267 }
4268 }
4269
4270 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
4271 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
4272 {
4273 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
4274 if (cfs)
4275 {
4276 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
4277 CFRelease(cfs);
4278 }
4279 }
4280
4281 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
4282 {
4283 mDNSs32 val;
4284 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
4285 if (!state) return mDNSfalse;
4286 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
4287 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
4288 return val ? mDNStrue : mDNSfalse;
4289 }
4290
4291 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
4292 {
4293 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
4294
4295 if (sa->sa_family == AF_INET)
4296 {
4297 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
4298 ip->type = mDNSAddrType_IPv4;
4299 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
4300 return(mStatus_NoError);
4301 }
4302
4303 if (sa->sa_family == AF_INET6)
4304 {
4305 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
4306 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
4307 // value into the second word of the IPv6 link-local address, so they can just
4308 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
4309 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
4310 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
4311 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
4312 ip->type = mDNSAddrType_IPv6;
4313 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
4314 return(mStatus_NoError);
4315 }
4316
4317 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
4318 return(mStatus_Invalid);
4319 }
4320
4321 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
4322 {
4323 mDNSEthAddr eth = zeroEthAddr;
4324
4325 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
4326 if (entityname)
4327 {
4328 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, entityname);
4329 if (dict)
4330 {
4331 CFRange range = { 0, 6 }; // Offset, length
4332 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
4333 if (data && CFDataGetLength(data) == 6)
4334 CFDataGetBytes(data, range, eth.b);
4335 CFRelease(dict);
4336 }
4337 CFRelease(entityname);
4338 }
4339
4340 return(eth);
4341 }
4342
4343 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
4344 {
4345 struct ifaddrs *ifa;
4346 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
4347 if (ifa->ifa_addr->sa_family == AF_LINK)
4348 {
4349 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
4350 if (sdl->sdl_index == ifindex)
4351 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
4352 }
4353 *eth = zeroEthAddr;
4354 return -1;
4355 }
4356
4357 #ifndef SIOCGIFWAKEFLAGS
4358 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
4359 #endif
4360
4361 #ifndef IF_WAKE_ON_MAGIC_PACKET
4362 #define IF_WAKE_ON_MAGIC_PACKET 0x01
4363 #endif
4364
4365 #ifndef ifr_wake_flags
4366 #define ifr_wake_flags ifr_ifru.ifru_intval
4367 #endif
4368
4369 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
4370 {
4371 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
4372 if (!service)
4373 {
4374 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
4375 return mDNSfalse;
4376 }
4377
4378 io_name_t n1, n2;
4379 IOObjectGetClass(service, n1);
4380 io_object_t parent;
4381 mDNSBool ret = mDNSfalse;
4382 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
4383 if (kr == KERN_SUCCESS)
4384 {
4385 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
4386 IOObjectGetClass(parent, n2);
4387 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
4388 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
4389 if (!ref)
4390 {
4391 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
4392 ret = mDNSfalse;
4393 }
4394 else
4395 {
4396 ret = mDNStrue;
4397 CFRelease(ref);
4398 }
4399 IOObjectRelease(parent);
4400 CFRelease(keystr);
4401 }
4402 else
4403 {
4404 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
4405 ret = mDNSfalse;
4406 }
4407 IOObjectRelease(service);
4408 return ret;
4409 }
4410
4411
4412 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
4413 {
4414 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
4415 }
4416
4417 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
4418 {
4419 // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
4420 if (!SPSInterface(i)) return(mDNSfalse);
4421
4422 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
4423 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
4424 // when the power source is not AC Power.
4425 if (InterfaceSupportsKeepAlive(&i->ifinfo))
4426 {
4427 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
4428 return mDNStrue;
4429 }
4430
4431 int s = socket(AF_INET, SOCK_DGRAM, 0);
4432 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
4433
4434 struct ifreq ifr;
4435 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
4436 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
4437 {
4438 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
4439 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
4440 // error code is being returned from the kernel, we need to use the kernel version.
4441 #define KERNEL_EOPNOTSUPP 102
4442 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
4443 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
4444 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
4445 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
4446 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
4447 }
4448
4449 close(s);
4450
4451 // 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
4452
4453 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
4454
4455 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
4456 }
4457
4458 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
4459 {
4460 int sockFD;
4461 struct ifreq ifr;
4462
4463 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
4464 if (sockFD < 0)
4465 {
4466 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
4467 return 0;
4468 }
4469
4470 ifr.ifr_addr.sa_family = AF_INET;
4471 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
4472
4473 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
4474 {
4475 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
4476 ifr.ifr_eflags = 0;
4477 }
4478 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
4479
4480 close(sockFD);
4481 return ifr.ifr_eflags;
4482 }
4483
4484 #if TARGET_OS_IPHONE
4485
4486 // Function pointers for the routines we use in the MobileWiFi framework.
4487 static WiFiManagerClientRef (*WiFiManagerClientCreate_p)(CFAllocatorRef allocator, WiFiClientType type) = mDNSNULL;
4488 static CFArrayRef (*WiFiManagerClientCopyDevices_p)(WiFiManagerClientRef manager) = mDNSNULL;
4489 static WiFiNetworkRef (*WiFiDeviceClientCopyCurrentNetwork_p)(WiFiDeviceClientRef device) = mDNSNULL;
4490 static bool (*WiFiNetworkIsCarPlay_p)(WiFiNetworkRef network) = mDNSNULL;
4491
4492 mDNSlocal mDNSBool MobileWiFiLibLoad(void)
4493 {
4494 static mDNSBool isInitialized = mDNSfalse;
4495 static void *MobileWiFiLib_p = mDNSNULL;
4496 static const char path[] = "/System/Library/PrivateFrameworks/MobileWiFi.framework/MobileWiFi";
4497
4498 if (!isInitialized)
4499 {
4500 if (!MobileWiFiLib_p)
4501 {
4502 MobileWiFiLib_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
4503 if (!MobileWiFiLib_p)
4504 {
4505 LogInfo("MobileWiFiLibLoad: dlopen() failed.");
4506 goto exit;
4507 }
4508 }
4509
4510 if (!WiFiManagerClientCreate_p)
4511 {
4512 WiFiManagerClientCreate_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCreate");
4513 if (!WiFiManagerClientCreate_p)
4514 {
4515 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCreate symbol failed.");
4516 goto exit;
4517 }
4518 }
4519
4520 if (!WiFiManagerClientCopyDevices_p)
4521 {
4522 WiFiManagerClientCopyDevices_p = dlsym(MobileWiFiLib_p, "WiFiManagerClientCopyDevices");
4523 if (!WiFiManagerClientCopyDevices_p)
4524 {
4525 LogInfo("MobileWiFiLibLoad: load of WiFiManagerClientCopyDevices symbol failed.");
4526 goto exit;
4527 }
4528 }
4529
4530 if (!WiFiDeviceClientCopyCurrentNetwork_p)
4531 {
4532 WiFiDeviceClientCopyCurrentNetwork_p = dlsym(MobileWiFiLib_p, "WiFiDeviceClientCopyCurrentNetwork");
4533 if (!WiFiDeviceClientCopyCurrentNetwork_p)
4534 {
4535 LogInfo("MobileWiFiLibLoad: load of WiFiDeviceClientCopyCurrentNetwork symbol failed.");
4536 goto exit;
4537 }
4538 }
4539
4540 if (!WiFiNetworkIsCarPlay_p)
4541 {
4542 WiFiNetworkIsCarPlay_p = dlsym(MobileWiFiLib_p, "WiFiNetworkIsCarPlay");
4543 if (!WiFiNetworkIsCarPlay_p)
4544 {
4545 LogInfo("MobileWiFiLibLoad: load of WiFiNetworkIsCarPlay symbol failed.");
4546 goto exit;
4547 }
4548 }
4549
4550 isInitialized = mDNStrue;
4551 }
4552
4553 exit:
4554 return isInitialized;
4555 }
4556
4557 // Return true if the interface is associate to a CarPlay hosted SSID.
4558 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
4559 {
4560 static WiFiManagerClientRef manager = NULL;
4561 mDNSBool rvalue = mDNSfalse;
4562
4563 if (!MobileWiFiLibLoad())
4564 return mDNSfalse;
4565
4566 // If we have associated with a CarPlay hosted SSID, then use the same
4567 // optimizations that are used if an interface has the IFEF_DIRECTLINK flag set.
4568
4569 // Get one WiFiManagerClientRef to use for all calls.
4570 if (manager == NULL)
4571 manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
4572
4573 if (manager == NULL)
4574 {
4575 LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
4576 }
4577 else
4578 {
4579 CFArrayRef devices;
4580
4581 devices = WiFiManagerClientCopyDevices_p(manager);
4582 if (devices != NULL)
4583 {
4584 WiFiDeviceClientRef device;
4585 WiFiNetworkRef network;
4586
4587 device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
4588 network = WiFiDeviceClientCopyCurrentNetwork_p(device);
4589 if (network != NULL)
4590 {
4591 if (WiFiNetworkIsCarPlay_p(network))
4592 {
4593 LogInfo("%s is CarPlay hosted", ifa_name);
4594 rvalue = mDNStrue;
4595 }
4596 CFRelease(network);
4597 }
4598 CFRelease(devices);
4599 }
4600 }
4601
4602 return rvalue;
4603 }
4604
4605 #else // TARGET_OS_IPHONE
4606
4607 mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
4608 {
4609 (void)ifa_name; // unused
4610
4611 // OSX WifiManager currently does not implement WiFiNetworkIsCarPlay()
4612 return mDNSfalse;;
4613 }
4614
4615 #endif // TARGET_OS_IPHONE
4616
4617 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
4618 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
4619 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
4620 // (e.g. sa_family not AF_INET or AF_INET6)
4621 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
4622 {
4623 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
4624 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
4625 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
4626
4627 mDNSAddr ip, mask;
4628 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
4629 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
4630
4631 NetworkInterfaceInfoOSX **p;
4632 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
4633 if (scope_id == (*p)->scope_id &&
4634 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
4635 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
4636 {
4637 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);
4638 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
4639 // When interfaces are created with same MAC address, kernel resurrects the old interface.
4640 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
4641 // we get the corresponding name for the interface index on which the packet was received and check against
4642 // the InterfaceList for a matching name. So, keep the name in sync
4643 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
4644 (*p)->Exists = mDNStrue;
4645 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
4646 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
4647
4648 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
4649 // we may need to start or stop or sleep proxy browse operation
4650 const mDNSBool NetWake = NetWakeInterface(*p);
4651 if ((*p)->ifinfo.NetWake != NetWake)
4652 {
4653 (*p)->ifinfo.NetWake = NetWake;
4654 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
4655 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
4656 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
4657 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
4658 if ((*p)->Registered)
4659 {
4660 mDNS_Lock(m);
4661 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
4662 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
4663 mDNS_Unlock(m);
4664 }
4665 }
4666 // Reset the flag if it has changed this time.
4667 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4668
4669 return(*p);
4670 }
4671
4672 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
4673 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
4674 if (!i) return(mDNSNULL);
4675 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
4676 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
4677 i->ifinfo.ip = ip;
4678 i->ifinfo.mask = mask;
4679 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
4680 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
4681 // We can be configured to disable multicast advertisement, but we want to to support
4682 // local-only services, which need a loopback address record.
4683 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
4684 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
4685 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
4686 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4687
4688 // Setting DirectLink indicates we can do the optimization of skipping the probe phase
4689 // for the interface address records since they should be unique.
4690 if (eflags & IFEF_DIRECTLINK)
4691 i->ifinfo.DirectLink = mDNStrue;
4692 else
4693 i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
4694
4695 i->next = mDNSNULL;
4696 i->m = m;
4697 i->Exists = mDNStrue;
4698 i->Flashing = mDNSfalse;
4699 i->Occulting = mDNSfalse;
4700 i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
4701 if (eflags & IFEF_AWDL)
4702 {
4703 // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
4704 // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
4705 // Bonjour requests over the AWDL interface.
4706 i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
4707 AWDLInterfaceID = i->ifinfo.InterfaceID;
4708 i->ifinfo.DirectLink = mDNStrue;
4709 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
4710 }
4711 else
4712 {
4713 i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
4714 }
4715 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
4716 i->LastSeen = utc;
4717 i->ifa_flags = ifa->ifa_flags;
4718 i->scope_id = scope_id;
4719 i->BSSID = bssid;
4720 i->sa_family = ifa->ifa_addr->sa_family;
4721 i->BPF_fd = -1;
4722 i->BPF_mcfd = -1;
4723 i->BPF_len = 0;
4724 i->Registered = mDNSNULL;
4725
4726 // Do this AFTER i->BSSID has been set up
4727 i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
4728 GetMAC(&i->ifinfo.MAC, scope_id);
4729 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
4730 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
4731
4732 *p = i;
4733 return(i);
4734 }
4735
4736 #if APPLE_OSX_mDNSResponder
4737
4738 #if COMPILER_LIKES_PRAGMA_MARK
4739 #pragma mark -
4740 #pragma mark - AutoTunnel
4741 #endif
4742
4743 #define kRacoonPort 4500
4744
4745 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
4746
4747 #ifndef NO_SECURITYFRAMEWORK
4748
4749 static CFMutableDictionaryRef domainStatusDict = NULL;
4750
4751 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
4752 {
4753 if (q->LongLived)
4754 {
4755 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
4756 return mStatus_NoSuchRecord;
4757 else if (q->state == LLQ_Poll)
4758 return mStatus_PollingMode;
4759 else if (q->state != LLQ_Established && !q->DuplicateOf)
4760 return mStatus_TransientErr;
4761 }
4762
4763 return mStatus_NoError;
4764 }
4765
4766 mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4767 {
4768 mStatus status = mStatus_NoError;
4769 DNSQuestion* q, *worst_q = mDNSNULL;
4770 for (q = m->Questions; q; q=q->next)
4771 if (q->AuthInfo == info)
4772 {
4773 mStatus newStatus = CheckQuestionForStatus(q);
4774 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
4775 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
4776 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
4777 }
4778
4779 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
4780 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
4781 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
4782 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
4783 return status;
4784 }
4785
4786 mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4787 {
4788 AuthRecord *r;
4789
4790 if (info->deltime) return mStatus_NoError;
4791 for (r = m->ResourceRecords; r; r = r->next)
4792 {
4793 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
4794 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
4795 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
4796 // has already checked
4797 const domainname *n = r->resrec.name;
4798 while (n->c[0])
4799 {
4800 DomainAuthInfo *ptr;
4801 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
4802 if (SameDomainName(&ptr->domain, n))
4803 {
4804 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
4805 {
4806 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
4807 return r->updateError;
4808 }
4809 }
4810 n = (const domainname *)(n->c + 1 + n->c[0]);
4811 }
4812 }
4813 return mStatus_NoError;
4814 }
4815
4816 #endif // ndef NO_SECURITYFRAMEWORK
4817
4818 // MUST be called with lock held
4819 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
4820 {
4821 #ifdef NO_SECURITYFRAMEWORK
4822 (void) m;
4823 (void)info;
4824 #else
4825 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
4826 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
4827 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
4828 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
4829 char buffer[1024];
4830 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4831 CFStringRef domain = NULL;
4832 CFStringRef tmp = NULL;
4833 CFNumberRef num = NULL;
4834 mStatus status = mStatus_NoError;
4835 mStatus llqStatus = mStatus_NoError;
4836 char llqBuffer[1024];
4837
4838 mDNS_CheckLock(m);
4839
4840 if (!domainStatusDict)
4841 {
4842 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4843 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
4844 }
4845
4846 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
4847
4848 mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
4849 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4850 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
4851
4852 if (info->deltime)
4853 {
4854 if (CFDictionaryContainsKey(domainStatusDict, domain))
4855 {
4856 CFDictionaryRemoveValue(domainStatusDict, domain);
4857 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4858 }
4859 CFRelease(domain);
4860 CFRelease(dict);
4861
4862 return;
4863 }
4864
4865 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
4866 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4867 if (!tmp)
4868 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
4869 else
4870 {
4871 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
4872 CFRelease(tmp);
4873 }
4874
4875 if (llq)
4876 {
4877 mDNSu32 port = mDNSVal16(llq->ExternalPort);
4878
4879 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4880 if (!num)
4881 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
4882 else
4883 {
4884 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
4885 CFRelease(num);
4886 }
4887
4888 if (llq->Result)
4889 {
4890 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
4891 if (!num)
4892 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
4893 else
4894 {
4895 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
4896 CFRelease(num);
4897 }
4898 }
4899 }
4900
4901 if (tun)
4902 {
4903 mDNSu32 port = mDNSVal16(tun->ExternalPort);
4904
4905 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4906 if (!num)
4907 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
4908 else
4909 {
4910 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
4911 CFRelease(num);
4912 }
4913
4914 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
4915 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4916 if (!tmp)
4917 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
4918 else
4919 {
4920 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
4921 CFRelease(tmp);
4922 }
4923
4924 if (tun->Result)
4925 {
4926 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
4927 if (!num)
4928 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
4929 else
4930 {
4931 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
4932 CFRelease(num);
4933 }
4934 }
4935 }
4936 if (tun || llq)
4937 {
4938 mDNSu32 code = m->LastNATMapResultCode;
4939
4940 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
4941 if (!num)
4942 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
4943 else
4944 {
4945 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
4946 CFRelease(num);
4947 }
4948 }
4949
4950 mDNS_snprintf(buffer, sizeof(buffer), "Success");
4951 llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
4952 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
4953
4954 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
4955 // reported so that it can be fixed automatically (or the user needs to be notified)
4956 if (status != mStatus_NoError)
4957 {
4958 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
4959 }
4960 else if (m->Router.type == mDNSAddrType_None)
4961 {
4962 status = mStatus_NoRouter;
4963 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
4964 }
4965 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
4966 {
4967 status = mStatus_NoRouter;
4968 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
4969 }
4970 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
4971 {
4972 status = mStatus_ServiceNotRunning;
4973 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
4974 }
4975 else if (!llq && !tun)
4976 {
4977 status = mStatus_NotInitializedErr;
4978 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4979 }
4980 else if (llqStatus == mStatus_NoSuchRecord)
4981 {
4982 status = llqStatus;
4983 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
4984 }
4985 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
4986 {
4987 status = mStatus_DoubleNAT;
4988 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
4989 }
4990 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
4991 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
4992 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
4993 {
4994 status = mStatus_NATPortMappingDisabled;
4995 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
4996 }
4997 else if ((llq && llq->Result) || (tun && tun->Result))
4998 {
4999 status = mStatus_NATTraversal;
5000 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
5001 }
5002 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
5003 {
5004 status = mStatus_NATTraversal;
5005 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
5006 }
5007 else
5008 {
5009 status = llqStatus;
5010 mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
5011 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
5012 }
5013
5014 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
5015 if (!num)
5016 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
5017 else
5018 {
5019 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
5020 CFRelease(num);
5021 }
5022
5023 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
5024 if (!tmp)
5025 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
5026 else
5027 {
5028 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
5029 CFRelease(tmp);
5030 }
5031
5032 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
5033 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
5034 {
5035 CFDictionarySetValue(domainStatusDict, domain, dict);
5036 if (!m->ShutdownTime)
5037 {
5038 static char statusBuf[16];
5039 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
5040 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
5041 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
5042 }
5043 }
5044
5045 CFRelease(domain);
5046 CFRelease(dict);
5047
5048 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
5049 #endif // def NO_SECURITYFRAMEWORK
5050 }
5051
5052 // MUST be called with lock held
5053 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
5054 {
5055 #ifdef NO_SECURITYFRAMEWORK
5056 (void) m;
5057 #else
5058 mDNS_CheckLock(m);
5059 DomainAuthInfo* info;
5060 for (info = m->AuthInfoList; info; info = info->next)
5061 if (info->AutoTunnel && !info->deltime)
5062 UpdateAutoTunnelDomainStatus(m, info);
5063 #endif // def NO_SECURITYFRAMEWORK
5064 }
5065
5066 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
5067 {
5068 DomainAuthInfo *info;
5069
5070 for (info = m->AuthInfoList; info; info = info->next)
5071 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
5072 break;
5073
5074 if (info != AnonymousRacoonConfig)
5075 {
5076 AnonymousRacoonConfig = info;
5077 LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
5078 }
5079 }
5080
5081 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
5082
5083 // Caller must hold the lock
5084 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
5085 {
5086 mDNS_CheckLock(m);
5087
5088 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
5089
5090 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
5091 {
5092 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
5093 if (err)
5094 {
5095 record->resrec.RecordType = kDNSRecordTypeUnregistered;
5096 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
5097 return mDNSfalse;
5098 }
5099 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
5100 }
5101 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
5102
5103 return mDNStrue;
5104 }
5105
5106 // Caller must hold the lock
5107 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
5108 {
5109 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
5110 {
5111 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
5112 m->NextSRVUpdate = NonZeroTime(m->timenow);
5113 }
5114 }
5115
5116 // Caller must hold the lock
5117 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
5118 {
5119 mStatus err;
5120 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
5121
5122 mDNS_CheckLock(m);
5123
5124 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
5125 {
5126 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
5127 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
5128 DeregisterAutoTunnelHostRecord(m, info);
5129 }
5130 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
5131 {
5132 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
5133 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
5134 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
5135 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
5136 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
5137 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
5138 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
5139
5140 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
5141 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
5142 else
5143 {
5144 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
5145 m->NextSRVUpdate = NonZeroTime(m->timenow);
5146 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
5147 }
5148 }
5149 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
5150 }
5151
5152 // Caller must hold the lock
5153 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
5154 {
5155 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
5156
5157 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
5158 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
5159 UpdateAutoTunnelHostRecord(m, info);
5160 }
5161
5162 // Caller must hold the lock
5163 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
5164 {
5165 mDNS_CheckLock(m);
5166
5167 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
5168 {
5169 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);
5170 DeregisterAutoTunnelServiceRecords(m, info);
5171 }
5172 else
5173 {
5174 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
5175 {
5176 // 1. Set up our address record for the external tunnel address
5177 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
5178 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
5179 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
5180 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
5181 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
5182 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
5183 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
5184 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
5185
5186 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
5187 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
5188 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
5189 }
5190 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
5191
5192 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
5193 {
5194 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
5195 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
5196 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
5197 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5198 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
5199 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
5200 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
5201 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
5202 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
5203 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
5204 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
5205
5206 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
5207 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
5208 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
5209 }
5210 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
5211
5212 UpdateAutoTunnelHostRecord(m, info);
5213
5214 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
5215 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
5216 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
5217
5218 }
5219 }
5220
5221 // Caller must hold the lock
5222 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
5223 {
5224 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
5225 }
5226
5227 // Caller must hold the lock
5228 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
5229 {
5230 mDNS_CheckLock(m);
5231
5232 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
5233 DeregisterAutoTunnelDeviceInfoRecord(m, info);
5234 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
5235 {
5236 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
5237 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
5238
5239 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
5240 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
5241
5242 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
5243 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
5244 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
5245 }
5246 else
5247 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
5248 }
5249
5250 // Caller must hold the lock
5251 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
5252 {
5253 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
5254
5255 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
5256 UpdateAutoTunnelHostRecord(m, info);
5257 UpdateAutoTunnelDomainStatus(m, info);
5258 }
5259
5260 // Caller must hold the lock
5261 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
5262 {
5263 mDNS_CheckLock(m);
5264
5265 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
5266 DeregisterAutoTunnel6Record(m, info);
5267 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
5268 {
5269 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
5270 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
5271 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
5272 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
5273 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
5274 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
5275 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
5276
5277 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
5278 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
5279 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
5280
5281 UpdateAutoTunnelHostRecord(m, info);
5282
5283 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
5284 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
5285 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
5286
5287 }
5288 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
5289 }
5290
5291 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
5292 {
5293 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
5294 if (result == mStatus_MemFree)
5295 {
5296 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
5297
5298 mDNS_Lock(m);
5299
5300 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
5301 if (rr == &info->AutoTunnelHostRecord)
5302 {
5303 rr->namestorage.c[0] = 0;
5304 m->NextSRVUpdate = NonZeroTime(m->timenow);
5305 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
5306 }
5307 if (m->ShutdownTime)
5308 {
5309 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
5310 mDNS_Unlock(m);
5311 return;
5312 }
5313 if (rr == &info->AutoTunnelHostRecord)
5314 {
5315 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
5316 UpdateAutoTunnelHostRecord(m,info);
5317 }
5318 else if (rr == &info->AutoTunnelDeviceInfo)
5319 {
5320 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
5321 UpdateAutoTunnelDeviceInfoRecord(m,info);
5322 }
5323 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
5324 {
5325 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
5326 UpdateAutoTunnelServiceRecords(m,info);
5327 }
5328 else if (rr == &info->AutoTunnel6Record)
5329 {
5330 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
5331 UpdateAutoTunnel6Record(m,info);
5332 }
5333
5334 mDNS_Unlock(m);
5335 }
5336 }
5337
5338 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
5339 {
5340 DomainAuthInfo *info;
5341
5342 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
5343 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
5344
5345 mDNS_Lock(m);
5346
5347 m->NextSRVUpdate = NonZeroTime(m->timenow);
5348 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
5349
5350 for (info = m->AuthInfoList; info; info = info->next)
5351 if (info->AutoTunnel)
5352 UpdateAutoTunnelServiceRecords(m, info);
5353
5354 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
5355
5356 UpdateAutoTunnelDomainStatuses(m);
5357
5358 mDNS_Unlock(m);
5359 }
5360
5361 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
5362 {
5363 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
5364
5365 mDNS_Lock(m);
5366 // We forcibly deregister the records that are based on the hostname.
5367 // When deregistration of each completes, the MemFree callback will make the
5368 // appropriate Update* call to use the new name to reregister.
5369 DeregisterAutoTunnelHostRecord(m, info);
5370 DeregisterAutoTunnelDeviceInfoRecord(m, info);
5371 DeregisterAutoTunnelServiceRecords(m, info);
5372 DeregisterAutoTunnel6Record(m, info);
5373 m->NextSRVUpdate = NonZeroTime(m->timenow);
5374 mDNS_Unlock(m);
5375 }
5376
5377 // Must be called with the lock held
5378 mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
5379 {
5380 if (info->deltime) return;
5381
5382 if (info->AutoTunnelServiceStarted)
5383 {
5384 // On wake from sleep, this function will be called when determining SRV targets,
5385 // and needs to re-register the host record for the target to be set correctly
5386 UpdateAutoTunnelHostRecord(m, info);
5387 return;
5388 }
5389
5390 info->AutoTunnelServiceStarted = mDNStrue;
5391
5392 // Now that we have a service in this domain, we need to try to register the
5393 // AutoTunnel records, because the relay connection & NAT-T may have already been
5394 // started for another domain. If the relay connection is not up or the NAT-T has not
5395 // yet succeeded, the Update* functions are smart enough to not register the records.
5396 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
5397 // decide whether to register the AutoTunnel records in the calls below.
5398 UpdateAutoTunnelServiceRecords(m, info);
5399 UpdateAutoTunnel6Record(m, info);
5400 UpdateAutoTunnelDeviceInfoRecord(m, info);
5401 UpdateAutoTunnelHostRecord(m, info);
5402
5403 // If the global AutoTunnel NAT-T is not yet started, start it.
5404 if (!m->AutoTunnelNAT.clientContext)
5405 {
5406 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
5407 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
5408 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
5409 m->AutoTunnelNAT.IntPort = IPSECPort;
5410 m->AutoTunnelNAT.RequestedPort = IPSECPort;
5411 m->AutoTunnelNAT.NATLease = 0;
5412 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
5413 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
5414 }
5415 }
5416
5417 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
5418 {
5419 mDNSv6Addr loc_outer6;
5420 mDNSv6Addr rmt_outer6;
5421
5422 // When we are tunneling over IPv6 Relay address, the port number is zero
5423 if (mDNSIPPortIsZero(tun->rmt_outer_port))
5424 {
5425 loc_outer6 = tun->loc_outer6;
5426 rmt_outer6 = tun->rmt_outer6;
5427 }
5428 else
5429 {
5430 loc_outer6 = zerov6Addr;
5431 loc_outer6.b[0] = tun->loc_outer.b[0];
5432 loc_outer6.b[1] = tun->loc_outer.b[1];
5433 loc_outer6.b[2] = tun->loc_outer.b[2];
5434 loc_outer6.b[3] = tun->loc_outer.b[3];
5435
5436 rmt_outer6 = zerov6Addr;
5437 rmt_outer6.b[0] = tun->rmt_outer.b[0];
5438 rmt_outer6.b[1] = tun->rmt_outer.b[1];
5439 rmt_outer6.b[2] = tun->rmt_outer.b[2];
5440 rmt_outer6.b[3] = tun->rmt_outer.b[3];
5441 }
5442
5443 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)));
5444 }
5445
5446 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
5447 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
5448
5449 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
5450 {
5451 DNSQuestion *q = m->Questions;
5452 while (q)
5453 {
5454 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
5455 {
5456 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5457 mDNSQuestionCallback *tmp = q->QuestionCallback;
5458 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
5459 mDNS_StopQuery(m, q);
5460 mDNS_StartQuery(m, q);
5461 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
5462 if (!success) q->NoAnswer = NoAnswer_Fail;
5463 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
5464 // In general we have to assume that the question list might have changed in arbitrary ways.
5465 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
5466 // already in use. The safest solution is just to go back to the start of the list and start again.
5467 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
5468 // just one suspended question, so it's really a 2n algorithm.
5469 q = m->Questions;
5470 }
5471 else
5472 q = q->next;
5473 }
5474 }
5475
5476 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
5477 {
5478 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
5479 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
5480 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
5481 // 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.
5482 // 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.
5483 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
5484 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
5485 }
5486
5487 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
5488 {
5489 ClientTunnel **p = &m->TunnelClients;
5490 while (*p != tun && *p) p = &(*p)->next;
5491 if (*p) *p = tun->next;
5492 ReissueBlockedQuestions(m, &tun->dstname, success);
5493 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
5494 freeL("ClientTunnel", tun);
5495 }
5496
5497 mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
5498 {
5499 ClientTunnel **p;
5500 mDNSBool needSetKeys = mDNStrue;
5501
5502 p = &tun->next;
5503 while (*p)
5504 {
5505 // Is this a tunnel to the same host that we are trying to setup now?
5506 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
5507 else
5508 {
5509 ClientTunnel *old = *p;
5510 if (v6Tunnel)
5511 {
5512 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
5513 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5514 if (old->q.ThisQInterval >= 0)
5515 {
5516 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5517 mDNS_StopQuery(m, &old->q);
5518 }
5519 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
5520 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
5521 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
5522 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
5523 {
5524 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
5525 // the other parameters of the tunnel are different
5526 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5527 AutoTunnelSetKeys(old, mDNSfalse);
5528 }
5529 else
5530 {
5531 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
5532 // as "tun" and "old" are identical
5533 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
5534 &old->rmt_inner);
5535 needSetKeys = mDNSfalse;
5536 }
5537 }
5538 else
5539 {
5540 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
5541 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5542 if (old->q.ThisQInterval >= 0)
5543 {
5544 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5545 mDNS_StopQuery(m, &old->q);
5546 }
5547 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
5548 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
5549 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
5550 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
5551 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
5552 {
5553 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
5554 // the other parameters of the tunnel are different
5555 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5556 AutoTunnelSetKeys(old, mDNSfalse);
5557 }
5558 else
5559 {
5560 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
5561 // as "tun" and "old" are identical
5562 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
5563 &old->rmt_inner);
5564 needSetKeys = mDNSfalse;
5565 }
5566 }
5567
5568 *p = old->next;
5569 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
5570 freeL("ClientTunnel", old);
5571 }
5572 }
5573 return needSetKeys;
5574 }
5575
5576 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
5577 // tunnel will be deleted
5578 mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
5579 {
5580 ClientTunnel **p;
5581
5582 p = &tun->next;
5583 while (*p)
5584 {
5585 // If there is more than one client tunnel to the same host, delete all of them.
5586 // We do this by just checking against the EUI64 rather than the full address
5587 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
5588 else
5589 {
5590 ClientTunnel *old = *p;
5591 if (v6Tunnel)
5592 {
5593 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
5594 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5595 }
5596 else
5597 {
5598 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
5599 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5600 }
5601 if (old->q.ThisQInterval >= 0)
5602 {
5603 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5604 mDNS_StopQuery(m, &old->q);
5605 }
5606 else
5607 {
5608 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
5609 AutoTunnelSetKeys(old, mDNSfalse);
5610 }
5611 *p = old->next;
5612 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
5613 freeL("ClientTunnel", old);
5614 }
5615 }
5616 }
5617
5618 mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
5619 {
5620 mDNSBool needSetKeys = mDNStrue;
5621 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5622 mDNSBool v6Tunnel = mDNSfalse;
5623 DomainAuthInfo *info;
5624
5625 // If the port is zero, then we have a relay address of the peer
5626 if (mDNSIPPortIsZero(tun->rmt_outer_port))
5627 v6Tunnel = mDNStrue;
5628
5629 if (v6Tunnel)
5630 {
5631 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
5632 tun->rmt_outer6 = answer->rdata->u.ipv6;
5633 tun->loc_outer6 = m->AutoTunnelRelayAddr;
5634 }
5635 else
5636 {
5637 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
5638 tun->rmt_outer = answer->rdata->u.ipv4;
5639 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
5640 tmpDst.ip.v4 = tun->rmt_outer;
5641 mDNSAddr tmpSrc = zeroAddr;
5642 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
5643 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
5644 else tun->loc_outer = m->AdvertisedV4.ip.v4;
5645 }
5646
5647 question->ThisQInterval = -1; // So we know this tunnel setup has completed
5648
5649 info = GetAuthInfoForName(m, &tun->dstname);
5650 if (!info)
5651 {
5652 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
5653 ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
5654 return;
5655 }
5656
5657 tun->loc_inner = info->AutoTunnelInnerAddress;
5658
5659 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
5660 // look for existing tunnels to see whether they have the same information for our peer.
5661 // If not, delete them and need to create a new tunnel. If they are same, just use the
5662 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
5663 TunnelClientDeleteAny(m, tun, !v6Tunnel);
5664 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
5665
5666 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5667 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
5668
5669 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
5670 static char msgbuf[32];
5671 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
5672 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
5673 // Kick off any questions that were held pending this tunnel setup
5674 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
5675 }
5676
5677 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5678 {
5679 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5680 DomainAuthInfo *info;
5681
5682 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
5683
5684 if (!AddRecord) return;
5685 mDNS_StopQuery(m, question);
5686
5687 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
5688 // The code below will look for _autotunnel._udp SRV record followed by A record
5689 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
5690 {
5691 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5692 static char msgbuf[16];
5693 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
5694 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
5695 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
5696 return;
5697 }
5698
5699 switch (tun->tc_state)
5700 {
5701 case TC_STATE_AAAA_PEER:
5702 if (question->qtype != kDNSType_AAAA)
5703 {
5704 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
5705 }
5706 info = GetAuthInfoForName(m, &tun->dstname);
5707 if (!info)
5708 {
5709 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
5710 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5711 return;
5712 }
5713 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5714 {
5715 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
5716 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5717 return;
5718 }
5719 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5720 {
5721 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
5722 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5723 return;
5724 }
5725 tun->rmt_inner = answer->rdata->u.ipv6;
5726 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
5727 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
5728 {
5729 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
5730 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
5731 question->qtype = kDNSType_AAAA;
5732 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
5733 }
5734 else
5735 {
5736 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5737 tun->tc_state = TC_STATE_SRV_PEER;
5738 question->qtype = kDNSType_SRV;
5739 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5740 }
5741 AppendDomainName(&question->qname, &tun->dstname);
5742 mDNS_StartQuery(m, &tun->q);
5743 return;
5744 case TC_STATE_AAAA_PEER_RELAY:
5745 if (question->qtype != kDNSType_AAAA)
5746 {
5747 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
5748 }
5749 // If it failed, look for the SRV record.
5750 if (!answer->rdlength)
5751 {
5752 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5753 tun->tc_state = TC_STATE_SRV_PEER;
5754 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5755 AppendDomainName(&question->qname, &tun->dstname);
5756 question->qtype = kDNSType_SRV;
5757 mDNS_StartQuery(m, &tun->q);
5758 return;
5759 }
5760 TunnelClientFinish(m, question, answer);
5761 return;
5762 case TC_STATE_SRV_PEER:
5763 if (question->qtype != kDNSType_SRV)
5764 {
5765 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
5766 }
5767 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
5768 tun->tc_state = TC_STATE_ADDR_PEER;
5769 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
5770 tun->rmt_outer_port = answer->rdata->u.srv.port;
5771 question->qtype = kDNSType_A;
5772 mDNS_StartQuery(m, &tun->q);
5773 return;
5774 case TC_STATE_ADDR_PEER:
5775 if (question->qtype != kDNSType_A)
5776 {
5777 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
5778 }
5779 TunnelClientFinish(m, question, answer);
5780 return;
5781 default:
5782 LogMsg("AutoTunnelCallback: Unknown question %p", question);
5783 }
5784 }
5785
5786 // Must be called with the lock held
5787 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
5788 {
5789 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
5790 if (!p) return;
5791 AssignDomainName(&p->dstname, &q->qname);
5792 p->MarkedForDeletion = mDNSfalse;
5793 p->loc_inner = zerov6Addr;
5794 p->loc_outer = zerov4Addr;
5795 p->loc_outer6 = zerov6Addr;
5796 p->rmt_inner = zerov6Addr;
5797 p->rmt_outer = zerov4Addr;
5798 p->rmt_outer6 = zerov6Addr;
5799 p->rmt_outer_port = zeroIPPort;
5800 p->tc_state = TC_STATE_AAAA_PEER;
5801 p->next = m->TunnelClients;
5802 m->TunnelClients = p; // We intentionally build list in reverse order
5803
5804 p->q.InterfaceID = mDNSInterface_Any;
5805 p->q.flags = 0;
5806 p->q.Target = zeroAddr;
5807 AssignDomainName(&p->q.qname, &q->qname);
5808 p->q.qtype = kDNSType_AAAA;
5809 p->q.qclass = kDNSClass_IN;
5810 p->q.LongLived = mDNSfalse;
5811 p->q.ExpectUnique = mDNStrue;
5812 p->q.ForceMCast = mDNSfalse;
5813 p->q.ReturnIntermed = mDNStrue;
5814 p->q.SuppressUnusable = mDNSfalse;
5815 p->q.SearchListIndex = 0;
5816 p->q.AppendSearchDomains = 0;
5817 p->q.RetryWithSearchDomains = mDNSfalse;
5818 p->q.TimeoutQuestion = 0;
5819 p->q.WakeOnResolve = 0;
5820 p->q.UseBackgroundTrafficClass = mDNSfalse;
5821 p->q.ValidationRequired = 0;
5822 p->q.ValidatingResponse = 0;
5823 p->q.ProxyQuestion = 0;
5824 p->q.qnameOrig = mDNSNULL;
5825 p->q.AnonInfo = mDNSNULL;
5826 p->q.pid = mDNSPlatformGetPID();
5827 p->q.euid = 0;
5828 p->q.QuestionCallback = AutoTunnelCallback;
5829 p->q.QuestionContext = p;
5830
5831 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
5832 mDNS_StartQuery_internal(m, &p->q);
5833 }
5834
5835 #endif // APPLE_OSX_mDNSResponder
5836
5837 #if COMPILER_LIKES_PRAGMA_MARK
5838 #pragma mark -
5839 #pragma mark - Power State & Configuration Change Management
5840 #endif
5841
5842 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
5843 {
5844 mDNSBool foundav4 = mDNSfalse;
5845 mDNSBool foundav6 = mDNSfalse;
5846 struct ifaddrs *ifa = myGetIfAddrs(0);
5847 struct ifaddrs *v4Loopback = NULL;
5848 struct ifaddrs *v6Loopback = NULL;
5849 char defaultname[64];
5850 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
5851 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
5852 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
5853
5854 if (m->SleepState == SleepState_Sleeping) ifa = NULL;
5855
5856 while (ifa)
5857 {
5858 #if LIST_ALL_INTERFACES
5859 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
5860 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5861 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5862 else if (ifa->ifa_addr->sa_family == AF_LINK)
5863 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5864 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5865 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
5866 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5867 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5868 if (!(ifa->ifa_flags & IFF_UP))
5869 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5870 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5871 if (!(ifa->ifa_flags & IFF_MULTICAST))
5872 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5873 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5874 if (ifa->ifa_flags & IFF_POINTOPOINT)
5875 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5876 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5877 if (ifa->ifa_flags & IFF_LOOPBACK)
5878 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5879 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5880 #endif
5881
5882 if (ifa->ifa_addr->sa_family == AF_LINK)
5883 {
5884 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
5885 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
5886 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
5887 }
5888
5889 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
5890 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
5891 {
5892 if (!ifa->ifa_netmask)
5893 {
5894 mDNSAddr ip;
5895 SetupAddr(&ip, ifa->ifa_addr);
5896 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5897 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
5898 }
5899 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5900 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5901 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
5902 {
5903 mDNSAddr ip;
5904 SetupAddr(&ip, ifa->ifa_addr);
5905 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5906 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
5907 }
5908 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5909 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
5910 {
5911 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
5912 }
5913 else
5914 {
5915 // Make sure ifa_netmask->sa_family is set correctly
5916 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5917 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
5918 int ifru_flags6 = 0;
5919
5920 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
5921 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
5922 {
5923 struct in6_ifreq ifr6;
5924 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
5925 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
5926 ifr6.ifr_addr = *sin6;
5927 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
5928 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
5929 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
5930 }
5931
5932 if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
5933 {
5934 if (ifa->ifa_flags & IFF_LOOPBACK)
5935 {
5936 if (ifa->ifa_addr->sa_family == AF_INET)
5937 v4Loopback = ifa;
5938 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
5939 v6Loopback = ifa;
5940 }
5941 else
5942 {
5943 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
5944 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
5945 {
5946 if (ifa->ifa_addr->sa_family == AF_INET)
5947 foundav4 = mDNStrue;
5948 else
5949 foundav6 = mDNStrue;
5950 }
5951 }
5952 }
5953 }
5954 }
5955 ifa = ifa->ifa_next;
5956 }
5957
5958 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5959 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
5960 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
5961
5962 // Now the list is complete, set the McastTxRx setting for each interface.
5963 NetworkInterfaceInfoOSX *i;
5964 for (i = m->p->InterfaceList; i; i = i->next)
5965 if (i->Exists)
5966 {
5967 mDNSBool txrx = MulticastInterface(i);
5968 if (i->ifinfo.McastTxRx != txrx)
5969 {
5970 i->ifinfo.McastTxRx = txrx;
5971 i->Exists = 2; // State change; need to deregister and reregister this interface
5972 }
5973 }
5974
5975 if (InfoSocket >= 0)
5976 close(InfoSocket);
5977
5978 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
5979 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
5980
5981 // Set up the nice label
5982 domainlabel nicelabel;
5983 nicelabel.c[0] = 0;
5984 GetUserSpecifiedFriendlyComputerName(&nicelabel);
5985 if (nicelabel.c[0] == 0)
5986 {
5987 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
5988 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
5989 }
5990
5991 // Set up the RFC 1034-compliant label
5992 domainlabel hostlabel;
5993 hostlabel.c[0] = 0;
5994 GetUserSpecifiedLocalHostName(&hostlabel);
5995 if (hostlabel.c[0] == 0)
5996 {
5997 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
5998 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
5999 }
6000
6001 mDNSBool namechange = mDNSfalse;
6002
6003 // We use a case-sensitive comparison here because even though changing the capitalization
6004 // of the name alone is not significant to DNS, it's still a change from the user's point of view
6005 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
6006 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
6007 else
6008 {
6009 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
6010 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
6011 m->p->usernicelabel = m->nicelabel = nicelabel;
6012 namechange = mDNStrue;
6013 }
6014
6015 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
6016 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
6017 else
6018 {
6019 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
6020 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
6021 m->p->userhostlabel = m->hostlabel = hostlabel;
6022 mDNS_SetFQDN(m);
6023 namechange = mDNStrue;
6024 }
6025
6026 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
6027 {
6028 #if APPLE_OSX_mDNSResponder
6029 DomainAuthInfo *info;
6030 for (info = m->AuthInfoList; info; info = info->next)
6031 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
6032 #endif // APPLE_OSX_mDNSResponder
6033 }
6034
6035 return(mStatus_NoError);
6036 }
6037
6038 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
6039 // Returns -1 if all the one-bits are not contiguous
6040 mDNSlocal int CountMaskBits(mDNSAddr *mask)
6041 {
6042 int i = 0, bits = 0;
6043 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
6044 while (i < bytes)
6045 {
6046 mDNSu8 b = mask->ip.v6.b[i++];
6047 while (b & 0x80) { bits++; b <<= 1; }
6048 if (b) return(-1);
6049 }
6050 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
6051 return(bits);
6052 }
6053
6054 // Returns count of non-link local V4 addresses registered (why? -- SC)
6055 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
6056 {
6057 NetworkInterfaceInfoOSX *i;
6058 int count = 0;
6059
6060 // Recalculate SuppressProbes time based on the current set of active interfaces.
6061 m->SuppressProbes = 0;
6062 for (i = m->p->InterfaceList; i; i = i->next)
6063 if (i->Exists)
6064 {
6065 NetworkInterfaceInfo *const n = &i->ifinfo;
6066 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
6067 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
6068
6069 if (i->Registered && i->Registered != primary) // Sanity check
6070 {
6071 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
6072 i->Registered = mDNSNULL;
6073 }
6074
6075 if (!i->Registered)
6076 {
6077 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
6078 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
6079 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it.
6080 i->Registered = primary;
6081
6082 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
6083 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
6084 // 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.
6085 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
6086
6087 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
6088 // every time it creates a new interface. We think it is a duplicate and hence consider it
6089 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
6090 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
6091 // logs a warning message to system.log noting frequent interface transitions.
6092 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
6093 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
6094 {
6095 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
6096 i->Flashing ? " (Flashing)" : "",
6097 i->Occulting ? " (Occulting)" : "");
6098 mDNS_RegisterInterface(m, n, 0);
6099 }
6100 else
6101 {
6102 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
6103 }
6104
6105 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
6106 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
6107 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
6108 i->Flashing ? " (Flashing)" : "",
6109 i->Occulting ? " (Occulting)" : "",
6110 n->InterfaceActive ? " (Primary)" : "");
6111
6112 if (!n->McastTxRx)
6113 {
6114 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);
6115 #if TARGET_OS_EMBEDDED
6116 // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
6117 // so we leave the multicast group here to clear any residual group membership.
6118 if (i->sa_family == AF_INET)
6119 {
6120 struct ip_mreq imr;
6121 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
6122 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
6123 imr.imr_interface = primary->ifa_v4addr;
6124
6125 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
6126 {
6127 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
6128 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
6129 if (err < 0 && (errno != EADDRNOTAVAIL))
6130 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
6131 }
6132 }
6133 if (i->sa_family == AF_INET6)
6134 {
6135 struct ipv6_mreq i6mr;
6136 i6mr.ipv6mr_interface = primary->scope_id;
6137 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
6138
6139 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
6140 {
6141 LogInfo("SetupActiveInterfaces: %5s(%lu) Doing IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
6142 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
6143 if (err < 0 && (errno != EADDRNOTAVAIL))
6144 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
6145 }
6146 }
6147 #endif // TARGET_OS_EMBEDDED
6148 }
6149 else
6150 {
6151 if (i->sa_family == AF_INET)
6152 {
6153 struct ip_mreq imr;
6154 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
6155 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
6156 imr.imr_interface = primary->ifa_v4addr;
6157
6158 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
6159 // before trying to join the group, to clear out stale kernel state which may be lingering.
6160 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
6161 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
6162 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
6163 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
6164 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
6165 // because by the time we get the configuration change notification, the interface is already gone,
6166 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
6167 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
6168 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
6169 {
6170 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);
6171 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
6172 if (err < 0 && (errno != EADDRNOTAVAIL))
6173 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
6174 }
6175
6176 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
6177 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
6178 // Joining same group twice can give "Address already in use" error -- no need to report that
6179 if (err < 0 && (errno != EADDRINUSE))
6180 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
6181 }
6182 if (i->sa_family == AF_INET6)
6183 {
6184 struct ipv6_mreq i6mr;
6185 i6mr.ipv6mr_interface = primary->scope_id;
6186 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
6187
6188 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
6189 {
6190 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);
6191 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
6192 if (err < 0 && (errno != EADDRNOTAVAIL))
6193 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
6194 }
6195
6196 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
6197 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
6198 // Joining same group twice can give "Address already in use" error -- no need to report that
6199 if (err < 0 && (errno != EADDRINUSE))
6200 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
6201 }
6202 }
6203 }
6204 }
6205
6206 return count;
6207 }
6208
6209 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
6210 {
6211 NetworkInterfaceInfoOSX *i;
6212 for (i = m->p->InterfaceList; i; i = i->next)
6213 {
6214 if (i->Exists) i->LastSeen = utc;
6215 i->Exists = mDNSfalse;
6216 }
6217 }
6218
6219 // Returns count of non-link local V4 addresses deregistered (why? -- SC)
6220 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
6221 {
6222 // First pass:
6223 // If an interface is going away, then deregister this from the mDNSCore.
6224 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
6225 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
6226 // it refers to has gone away we'll crash.
6227 NetworkInterfaceInfoOSX *i;
6228 int count = 0;
6229 for (i = m->p->InterfaceList; i; i = i->next)
6230 {
6231 // If this interface is no longer active, or its InterfaceID is changing, deregister it
6232 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
6233 if (i->Registered)
6234 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
6235 {
6236 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
6237 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
6238 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
6239 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
6240 i->Flashing ? " (Flashing)" : "",
6241 i->Occulting ? " (Occulting)" : "",
6242 i->ifinfo.InterfaceActive ? " (Primary)" : "");
6243
6244 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
6245 // every time it creates a new interface. We think it is a duplicate and hence consider it
6246 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
6247 // stale data returned to the application even after the interface is removed. The application
6248 // then starts to send data but the new interface is not yet created.
6249 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
6250 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
6251 {
6252 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
6253 i->Flashing ? " (Flashing)" : "",
6254 i->Occulting ? " (Occulting)" : "");
6255 mDNS_DeregisterInterface(m, &i->ifinfo, 0);
6256 }
6257 else
6258 {
6259 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
6260 }
6261 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
6262 i->Registered = mDNSNULL;
6263 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
6264 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
6265 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
6266
6267 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
6268 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
6269 }
6270 }
6271
6272 // Second pass:
6273 // Now that everything that's going to deregister has done so, we can clean up and free the memory
6274 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
6275 while (*p)
6276 {
6277 i = *p;
6278 // If no longer active, delete interface from list and free memory
6279 if (!i->Exists)
6280 {
6281 if (i->LastSeen == utc) i->LastSeen = utc - 1;
6282 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
6283 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
6284 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
6285 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
6286 i->ifinfo.InterfaceActive ? " (Primary)" : "");
6287 #if APPLE_OSX_mDNSResponder
6288 if (i->BPF_fd >= 0) CloseBPF(i);
6289 #endif // APPLE_OSX_mDNSResponder
6290 if (delete)
6291 {
6292 *p = i->next;
6293 freeL("NetworkInterfaceInfoOSX", i);
6294 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
6295 }
6296 }
6297 p = &i->next;
6298 }
6299 return count;
6300 }
6301
6302 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
6303 {
6304 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
6305 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
6306 else
6307 {
6308 dnle->next = mDNSNULL;
6309 dnle->uid = uid;
6310 AssignDomainName(&dnle->name, name);
6311 **List = dnle;
6312 *List = &dnle->next;
6313 }
6314 }
6315
6316 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
6317 {
6318 dns_resolver_t *a = *(dns_resolver_t**)aa;
6319 dns_resolver_t *b = *(dns_resolver_t**)bb;
6320
6321 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
6322 }
6323
6324 mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
6325 {
6326 char *buf = ".";
6327 mDNSu32 scopeid = 0;
6328 char ifid_buf[16];
6329
6330 if (domain)
6331 buf = domain;
6332 //
6333 // Hash the search domain name followed by the InterfaceID.
6334 // As we have scoped search domains, we also included InterfaceID. If either of them change,
6335 // we will detect it. Even if the order of them change, we will detect it.
6336 //
6337 // Note: We have to handle a few of these tricky cases.
6338 //
6339 // 1) Current: com, apple.com Changing to: comapple.com
6340 // 2) Current: a.com,b.com Changing to a.comb.com
6341 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
6342 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
6343 //
6344 // There are more variants of the above. The key thing is if we include the null in each case
6345 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
6346 // NULL as part of the name) to be mistakenly thought of as a old name.
6347
6348 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
6349 // mDNS_snprintf always null terminates
6350 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
6351 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
6352
6353 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
6354 MD5_Update(sdc, buf, strlen(buf) + 1);
6355 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
6356 }
6357
6358 mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
6359 {
6360 mDNSu8 md5_hash[MD5_LEN];
6361
6362 MD5_Final(md5_hash, sdc);
6363
6364 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
6365 {
6366 // If the hash is different, either the search domains have changed or
6367 // the ordering between them has changed. Restart the questions that
6368 // would be affected by this.
6369 LogInfo("FinalizeSearchDomains: The hash is different");
6370 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
6371 RetrySearchDomainQuestions(m);
6372 }
6373 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
6374 }
6375
6376 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
6377 {
6378 switch (scope)
6379 {
6380 case kScopeNone:
6381 return "Unscoped";
6382 case kScopeInterfaceID:
6383 return "InterfaceScoped";
6384 case kScopeServiceID:
6385 return "ServiceScoped";
6386 default:
6387 return "Unknown";
6388 }
6389 }
6390
6391 mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
6392 {
6393 const char *scopeString = DNSScopeToString(scope);
6394 int j;
6395 domainname d;
6396
6397 if (scope == kScopeNone)
6398 interfaceId = mDNSInterface_Any;
6399
6400 if (scope == kScopeNone || scope == kScopeInterfaceID)
6401 {
6402 for (j = 0; j < resolver->n_search; j++)
6403 {
6404 if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
6405 {
6406 static char interface_buf[32];
6407 mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(m, interfaceId));
6408 LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
6409 resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
6410 UpdateSearchDomainHash(m, sdc, resolver->search[j], interfaceId);
6411 mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
6412 }
6413 else
6414 {
6415 LogInfo("ConfigSearchDomains: An invalid search domain was detected for %s domain %s n_nameserver %d, (generation= %llu)",
6416 DNSScopeToString(scope), resolver->domain, resolver->n_nameserver, generation);
6417 }
6418 }
6419 }
6420 else
6421 {
6422 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(m,interfaceId));
6423 }
6424 }
6425
6426 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
6427 {
6428 NetworkInterfaceInfoOSX *ni;
6429 mDNSInterfaceID interface;
6430
6431 for (ni = m->p->InterfaceList; ni; ni = ni->next)
6432 {
6433 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
6434 break;
6435 }
6436 if (ni != NULL)
6437 {
6438 interface = ni->ifinfo.InterfaceID;
6439 }
6440 else
6441 {
6442 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
6443 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
6444 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
6445 // As the caller is going to ack the configuration always, we have to add all the DNS servers
6446 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
6447
6448 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
6449
6450 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
6451 interface = (mDNSInterfaceID)(unsigned long)ifindex;
6452 }
6453 return interface;
6454 }
6455
6456 mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
6457 {
6458 char *opt = r->options;
6459 domainname d;
6460
6461 if (opt && !strncmp(opt, "mdns", strlen(opt)))
6462 {
6463 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
6464 {
6465 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
6466 return;
6467 }
6468 mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
6469 }
6470 }
6471
6472 mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
6473 {
6474 int n;
6475 domainname d;
6476 int serviceID = 0;
6477 mDNSBool cellIntf = mDNSfalse;
6478 mDNSBool reqA, reqAAAA;
6479
6480 if (!r->domain || !*r->domain)
6481 {
6482 d.c[0] = 0;
6483 }
6484 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
6485 {
6486 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
6487 return;
6488 }
6489 // Parse the resolver specific attributes that affects all the DNS servers.
6490 if (scope == kScopeServiceID)
6491 {
6492 serviceID = r->service_identifier;
6493 }
6494
6495 #if TARGET_OS_IPHONE
6496 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
6497 #endif
6498 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
6499 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
6500
6501 for (n = 0; n < r->n_nameserver; n++)
6502 {
6503 mDNSAddr saddr;
6504 DNSServer *s;
6505
6506 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
6507 continue;
6508
6509 if (SetupAddr(&saddr, r->nameserver[n]))
6510 {
6511 LogMsg("ConfigDNSServers: Bad address");
6512 continue;
6513 }
6514
6515 // The timeout value is for all the DNS servers in a given resolver, hence we pass
6516 // the timeout value only for the first DNSServer. If we don't have a value in the
6517 // resolver, then use the core's default value
6518 //
6519 // Note: this assumes that when the core picks a list of DNSServers for a question,
6520 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
6521 // tries all the DNS servers in a specified timeout
6522 s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
6523 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
6524 if (s)
6525 {
6526 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
6527 }
6528 }
6529 }
6530
6531 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
6532 // Service scope resolvers. This is indicated by the scope argument.
6533 //
6534 // "resolver" has entries that should only be used for unscoped questions.
6535 //
6536 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
6537 // interface index (q->InterfaceID)
6538 //
6539 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
6540 // a service identifier (q->ServiceID)
6541 //
6542 mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
6543 {
6544 int i;
6545 dns_resolver_t **resolver;
6546 int nresolvers;
6547 const char *scopeString = DNSScopeToString(scope);
6548 mDNSInterfaceID interface;
6549
6550 switch (scope)
6551 {
6552 case kScopeNone:
6553 resolver = config->resolver;
6554 nresolvers = config->n_resolver;
6555 break;
6556 case kScopeInterfaceID:
6557 resolver = config->scoped_resolver;
6558 nresolvers = config->n_scoped_resolver;
6559 break;
6560 case kScopeServiceID:
6561 resolver = config->service_specific_resolver;
6562 nresolvers = config->n_service_specific_resolver;
6563 break;
6564 default:
6565 return;
6566 }
6567 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
6568
6569 for (i = 0; i < nresolvers; i++)
6570 {
6571 dns_resolver_t *r = resolver[i];
6572
6573 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
6574
6575 interface = mDNSInterface_Any;
6576
6577 // Parse the interface index
6578 if (r->if_index != 0)
6579 {
6580 interface = ConfigParseInterfaceID(m, r->if_index);
6581 }
6582
6583 if (setsearch)
6584 {
6585 ConfigSearchDomains(m, resolver[i], interface, scope, sdc, config->generation);
6586
6587 // Parse other scoped resolvers for search lists
6588 if (!setservers)
6589 continue;
6590 }
6591
6592 if (r->port == 5353 || r->n_nameserver == 0)
6593 {
6594 ConfigNonUnicastResolver(m, r);
6595 }
6596 else
6597 {
6598 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
6599 // scoped resolver are not used by other non-scoped or scoped resolvers.
6600 if (scope != kScopeNone)
6601 resGroupID++;
6602
6603 ConfigDNSServers(m, r, interface, scope, resGroupID);
6604 }
6605 }
6606 }
6607
6608 #if APPLE_OSX_mDNSResponder
6609 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
6610 {
6611 if (QuerySuppressed(q))
6612 {
6613 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
6614 return mDNSfalse;
6615 }
6616 if (mDNSOpaque16IsZero(q->TargetQID))
6617 {
6618 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
6619 return mDNSfalse;
6620 }
6621 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
6622 // for trigger.
6623 if (q->LOAddressAnswers)
6624 {
6625 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
6626 return mDNSfalse;
6627 }
6628 return mDNStrue;
6629 }
6630 #endif
6631
6632 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
6633 // We set our state appropriately so that if we start receiving answers, trigger the
6634 // upper layer to retry DNS questions.
6635 #if APPLE_OSX_mDNSResponder
6636 mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
6637 {
6638 if (!QuestionValidForDNSTrigger(q))
6639 return;
6640
6641 // Ignore applications that start and stop queries for no reason before we ever talk
6642 // to any DNS server.
6643 if (!q->triedAllServersOnce)
6644 {
6645 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
6646 return;
6647 }
6648 if (q->qtype == kDNSType_A)
6649 m->p->v4answers = 0;
6650 if (q->qtype == kDNSType_AAAA)
6651 m->p->v6answers = 0;
6652 if (!m->p->v4answers || !m->p->v6answers)
6653 {
6654 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
6655 DNSTypeName(q->qtype));
6656 }
6657 }
6658 #endif
6659
6660 mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
6661 {
6662 mDNS_CheckLock(m);
6663
6664 // Acking the configuration triggers configd to reissue the reachability queries
6665 m->p->DNSTrigger = NonZeroTime(m->timenow);
6666 _dns_configuration_ack(config, "com.apple.mDNSResponder");
6667 }
6668
6669 // If v4q is non-NULL, it means we have received some answers for "A" type questions
6670 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
6671 #if APPLE_OSX_mDNSResponder
6672 mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
6673 {
6674 mDNSBool trigger = mDNSfalse;
6675 mDNSs32 timenow;
6676
6677 // Don't send triggers too often.
6678 // If we have started delivering answers to questions, we should send a trigger
6679 // if the time permits. If we are delivering answers, we should set the state
6680 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
6681 // whether the answers that are being delivered currently is for configd or some
6682 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
6683 // then we won't deliver the trigger later when it is okay to send one as the
6684 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
6685 // v6answers if we are not delivering triggers.
6686 mDNS_Lock(m);
6687 timenow = m->timenow;
6688 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
6689 {
6690 if (!m->p->v4answers || !m->p->v6answers)
6691 {
6692 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
6693 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
6694 }
6695 mDNS_Unlock(m);
6696 return;
6697 }
6698 mDNS_Unlock(m);
6699 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
6700 {
6701 int old = m->p->v4answers;
6702
6703 m->p->v4answers = 1;
6704
6705 // If there are IPv4 answers now and previously we did not have
6706 // any answers, trigger a DNS change so that reachability
6707 // can retry the queries again.
6708 if (!old)
6709 {
6710 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6711 v4q->qname.c, DNSTypeName(v4q->qtype));
6712 trigger = mDNStrue;
6713 }
6714 }
6715 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
6716 {
6717 int old = m->p->v6answers;
6718
6719 m->p->v6answers = 1;
6720 // If there are IPv6 answers now and previously we did not have
6721 // any answers, trigger a DNS change so that reachability
6722 // can retry the queries again.
6723 if (!old)
6724 {
6725 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
6726 v6q->qname.c, DNSTypeName(v6q->qtype));
6727 trigger = mDNStrue;
6728 }
6729 }
6730 if (trigger)
6731 {
6732 dns_config_t *config = dns_configuration_copy();
6733 if (config)
6734 {
6735 mDNS_Lock(m);
6736 AckConfigd(m, config);
6737 mDNS_Unlock(m);
6738 dns_configuration_free(config);
6739 }
6740 else
6741 {
6742 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
6743 }
6744 }
6745 }
6746
6747 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
6748 {
6749 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
6750 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
6751 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
6752 config->resolver[0]->nameserver[0])
6753 {
6754 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
6755 }
6756 else
6757 {
6758 ActiveDirectoryPrimaryDomain.c[0] = 0;
6759 }
6760
6761 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
6762 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
6763 if (config->n_resolver && config->resolver[0]->n_nameserver &&
6764 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
6765 {
6766 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
6767 }
6768 else
6769 {
6770 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
6771 ActiveDirectoryPrimaryDomainLabelCount = 0;
6772 ActiveDirectoryPrimaryDomainServer = zeroAddr;
6773 }
6774 }
6775 #endif
6776
6777 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
6778 {
6779 int i;
6780 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NULL
6781 domainname d;
6782
6783 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_DynamicDNS);
6784 if (ddnsdict)
6785 {
6786 if (fqdn)
6787 {
6788 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
6789 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
6790 {
6791 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
6792 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
6793 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
6794 {
6795 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
6796 if (name)
6797 {
6798 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6799 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
6800 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
6801 else
6802 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
6803 }
6804 }
6805 }
6806 }
6807 if (RegDomains)
6808 {
6809 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
6810 if (regArray && CFArrayGetCount(regArray) > 0)
6811 {
6812 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
6813 if (regDict && DictionaryIsEnabled(regDict))
6814 {
6815 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
6816 if (name)
6817 {
6818 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6819 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6820 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
6821 else
6822 {
6823 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
6824 AppendDNameListElem(&RegDomains, 0, &d);
6825 }
6826 }
6827 }
6828 }
6829 }
6830 if (BrowseDomains)
6831 {
6832 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
6833 if (browseArray)
6834 {
6835 for (i = 0; i < CFArrayGetCount(browseArray); i++)
6836 {
6837 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
6838 if (browseDict && DictionaryIsEnabled(browseDict))
6839 {
6840 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
6841 if (name)
6842 {
6843 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6844 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6845 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
6846 else
6847 {
6848 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
6849 AppendDNameListElem(&BrowseDomains, 0, &d);
6850 }
6851 }
6852 }
6853 }
6854 }
6855 }
6856 CFRelease(ddnsdict);
6857 }
6858 if (RegDomains)
6859 {
6860 CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
6861 if (btmm)
6862 {
6863 CFIndex size = CFDictionaryGetCount(btmm);
6864 const void *key[size];
6865 const void *val[size];
6866 CFDictionaryGetKeysAndValues(btmm, key, val);
6867 for (i = 0; i < size; i++)
6868 {
6869 LogInfo("BackToMyMac %d", i);
6870 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6871 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
6872 else
6873 {
6874 mDNSu32 uid = atoi(buf);
6875 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6876 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
6877 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
6878 {
6879 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
6880 AppendDNameListElem(&RegDomains, uid, &d);
6881 }
6882 }
6883 }
6884 CFRelease(btmm);
6885 }
6886 }
6887
6888 }
6889
6890 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
6891 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
6892 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
6893 {
6894 MD5_CTX sdc; // search domain context
6895 static mDNSu16 resolverGroupID = 0;
6896
6897 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
6898 if (fqdn ) fqdn->c[0] = 0;
6899 if (RegDomains ) *RegDomains = NULL;
6900 if (BrowseDomains) *BrowseDomains = NULL;
6901
6902 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
6903 setservers ? " setservers" : "",
6904 setsearch ? " setsearch" : "",
6905 fqdn ? " fqdn" : "",
6906 RegDomains ? " RegDomains" : "",
6907 BrowseDomains ? " BrowseDomains" : "");
6908
6909 if (setsearch) MD5_Init(&sdc);
6910
6911 // Add the inferred address-based configuration discovery domains
6912 // (should really be in core code I think, not platform-specific)
6913 if (setsearch)
6914 {
6915 struct ifaddrs *ifa = mDNSNULL;
6916 struct sockaddr_in saddr;
6917 mDNSPlatformMemZero(&saddr, sizeof(saddr));
6918 saddr.sin_len = sizeof(saddr);
6919 saddr.sin_family = AF_INET;
6920 saddr.sin_port = 0;
6921 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
6922
6923 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
6924 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
6925
6926 while (ifa)
6927 {
6928 mDNSAddr a, n;
6929 char buf[64];
6930
6931 if (ifa->ifa_addr->sa_family == AF_INET &&
6932 ifa->ifa_netmask &&
6933 !(ifa->ifa_flags & IFF_LOOPBACK) &&
6934 !SetupAddr(&a, ifa->ifa_addr) &&
6935 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
6936 {
6937 // 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
6938 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
6939 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
6940 SetupAddr(&n, ifa->ifa_netmask);
6941 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6942 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
6943 a.ip.v4.b[2] & n.ip.v4.b[2],
6944 a.ip.v4.b[1] & n.ip.v4.b[1],
6945 a.ip.v4.b[0] & n.ip.v4.b[0]);
6946 UpdateSearchDomainHash(m, &sdc, buf, NULL);
6947 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
6948 }
6949 ifa = ifa->ifa_next;
6950 }
6951 }
6952
6953 #ifndef MDNS_NO_DNSINFO
6954 if (setservers || setsearch)
6955 {
6956 dns_config_t *config = dns_configuration_copy();
6957 if (!config)
6958 {
6959 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
6960 // Apparently this is expected behaviour -- "not a bug".
6961 // Accordingly, we suppress syslog messages for the first three minutes after boot.
6962 // If we are still getting failures after three minutes, then we log them.
6963 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
6964 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6965 }
6966 else
6967 {
6968 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
6969 if (m->p->LastConfigGeneration == config->generation)
6970 {
6971 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
6972 dns_configuration_free(config);
6973 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6974 return mDNSfalse;
6975 }
6976 #if APPLE_OSX_mDNSResponder
6977 SetupActiveDirectoryDomain(config);
6978 #endif
6979
6980 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6981 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6982 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6983 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6984 // same resolverGroupID.
6985 //
6986 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6987 ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6988 resolverGroupID += config->n_resolver;
6989
6990 ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6991 resolverGroupID += config->n_scoped_resolver;
6992
6993 ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6994
6995 // Acking provides a hint that we processed this current configuration and
6996 // we will use that from now on, assuming we don't get another one immediately
6997 // after we return from here.
6998 if (ackConfig)
6999 {
7000 // Note: We have to set the generation number here when we are acking.
7001 // For every DNS configuration change, we do the following:
7002 //
7003 // 1) Copy dns configuration, handle search domains change
7004 // 2) Copy dns configuration, handle dns server change
7005 //
7006 // If we update the generation number at step (1), we won't process the
7007 // DNS servers the second time because generation number would be the same.
7008 // As we ack only when we process dns servers, we set the generation number
7009 // during acking.
7010 m->p->LastConfigGeneration = config->generation;
7011 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
7012 AckConfigd(m, config);
7013 }
7014 dns_configuration_free(config);
7015 if (setsearch) FinalizeSearchDomainHash(m, &sdc);
7016 }
7017 }
7018 #endif // MDNS_NO_DNSINFO
7019 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
7020 return mDNStrue;
7021 }
7022
7023
7024 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
7025 {
7026 char buf[256];
7027 (void)m; // Unused
7028
7029 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
7030 if (dict)
7031 {
7032 r->type = mDNSAddrType_IPv4;
7033 r->ip.v4 = zerov4Addr;
7034 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
7035 if (string)
7036 {
7037 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
7038 LogMsg("Could not convert router to CString");
7039 else
7040 {
7041 struct sockaddr_in saddr;
7042 saddr.sin_len = sizeof(saddr);
7043 saddr.sin_family = AF_INET;
7044 saddr.sin_port = 0;
7045 inet_aton(buf, &saddr.sin_addr);
7046 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
7047 }
7048 }
7049 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
7050 if (string)
7051 {
7052 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
7053 struct ifaddrs *ifa = myGetIfAddrs(1);
7054 *v4 = *v6 = zeroAddr;
7055
7056 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
7057 {
7058 LogMsg("Could not convert router to CString");
7059 goto exit;
7060 }
7061 // find primary interface in list
7062 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
7063 {
7064 mDNSAddr tmp6 = zeroAddr;
7065 if (!strcmp(buf, ifa->ifa_name))
7066 {
7067 if (ifa->ifa_addr->sa_family == AF_INET)
7068 {
7069 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4))
7070 SetupAddr(v4, ifa->ifa_addr);
7071 }
7072 else if (ifa->ifa_addr->sa_family == AF_INET6)
7073 {
7074 SetupAddr(&tmp6, ifa->ifa_addr);
7075 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
7076 {
7077 HavePrimaryGlobalv6 = mDNStrue;
7078 *v6 = tmp6;
7079 }
7080 }
7081 }
7082 else
7083 {
7084 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
7085 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
7086 {
7087 SetupAddr(&tmp6, ifa->ifa_addr);
7088 if (tmp6.ip.v6.b[0] >> 5 == 1)
7089 *v6 = tmp6;
7090 }
7091 }
7092 ifa = ifa->ifa_next;
7093 }
7094 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
7095 // V4 to communicate w/ our DNS server
7096 }
7097
7098 exit:
7099 CFRelease(dict);
7100 }
7101 return mStatus_NoError;
7102 }
7103
7104 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
7105 {
7106 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
7107 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
7108 ConvertDomainNameToCString(dname, uname);
7109
7110 char *p = uname;
7111 while (*p)
7112 {
7113 *p = tolower(*p);
7114 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
7115 p++;
7116 }
7117
7118 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
7119 // That single entity is a CFDictionary with name "HostNames".
7120 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
7121 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
7122 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
7123 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
7124 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
7125
7126 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
7127 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
7128 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
7129 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
7130 else
7131 {
7132 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
7133 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
7134 else
7135 {
7136 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
7137 if (HostVals[0])
7138 {
7139 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
7140 if (StateVals[0])
7141 {
7142 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7143 if (StateDict)
7144 {
7145 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
7146 CFRelease(StateDict);
7147 }
7148 CFRelease(StateVals[0]);
7149 }
7150 CFRelease(HostVals[0]);
7151 }
7152 CFRelease(StatusVals[0]);
7153 }
7154 CFRelease(HostKeys[0]);
7155 }
7156 }
7157
7158 #if APPLE_OSX_mDNSResponder
7159 #if !NO_AWACS
7160
7161 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
7162 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
7163 // help catch it
7164 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
7165 {
7166 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
7167 if (!store)
7168 {
7169 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7170 return mDNSfalse;
7171 }
7172 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
7173 if (btmm)
7174 {
7175 CFIndex size = CFDictionaryGetCount(btmm);
7176 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
7177 const void *key[size];
7178 const void *val[size];
7179 domainname dom;
7180 int i;
7181 CFDictionaryGetKeysAndValues(btmm, key, val);
7182 for (i = 0; i < size; i++)
7183 {
7184 LogInfo("BackToMyMac %d", i);
7185 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
7186 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
7187 else
7188 {
7189 mDNSu32 uid = atoi(buf);
7190 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
7191 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
7192 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
7193 {
7194 if (SameDomainName(&dom, d))
7195 {
7196 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
7197 CFRelease(btmm);
7198 CFRelease(store);
7199 return mDNStrue;
7200 }
7201 }
7202 }
7203 }
7204 CFRelease(btmm);
7205 }
7206 CFRelease(store);
7207 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
7208 return mDNSfalse;
7209 }
7210
7211 // Appends data to the buffer
7212 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
7213 {
7214 int len;
7215
7216 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
7217 if (len >= (bufsz - *currlen))
7218 {
7219 // if we have exceeded the space in buf, it has already been NULL terminated
7220 // and we have nothing more to do. Set currlen to the last byte so that the caller
7221 // knows to do the right thing
7222 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
7223 *currlen = bufsz - 1;
7224 return -1;
7225 }
7226 else { (*currlen) += len; }
7227
7228 buf[*currlen] = ',';
7229 if (*currlen >= bufsz)
7230 {
7231 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
7232 *currlen = bufsz - 1;
7233 buf[*currlen] = 0;
7234 return -1;
7235 }
7236 // if we have filled up the buffer exactly, then there is no more work to do
7237 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
7238 (*currlen)++;
7239 return *currlen;
7240 }
7241
7242 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
7243 // BTMM domains, then bring down the connection to the relay.
7244 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
7245 {
7246 DomainAuthInfo *BTMMDomain = mDNSNULL;
7247 DomainAuthInfo *FoundInList;
7248 static mDNSBool AWACSDConnected = mDNSfalse;
7249 char AllUsers[1024]; // maximum size of mach message
7250 char AllPass[1024]; // maximum size of mach message
7251 char username[MAX_DOMAIN_LABEL + 1];
7252 int currulen = 0;
7253 int currplen = 0;
7254
7255 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
7256 // we may not be able to send the dns queries over the relay connection which may be needed
7257 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
7258 // need to make sure that we send the disconnect before attempting the next connect as the
7259 // awacs connections are redirected based on usernames.
7260 //
7261 // For now we send a disconnect immediately. When we start sending dns queries over the relay
7262 // connection, we will need to fix this.
7263
7264 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
7265 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
7266 {
7267 // We need the passwd from the first domain.
7268 BTMMDomain = FoundInList;
7269 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
7270 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
7271 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
7272 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
7273 }
7274
7275 if (BTMMDomain)
7276 {
7277 // In the normal case (where we neither exceed the buffer size nor write bytes that
7278 // fit exactly into the buffer), currulen/currplen should be a different size than
7279 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
7280
7281 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
7282 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
7283
7284 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
7285 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
7286 AWACSDConnected = mDNStrue;
7287 }
7288 else
7289 {
7290 // Disconnect only if we connected previously
7291 if (AWACSDConnected)
7292 {
7293 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
7294 AWACS_Disconnect();
7295 AWACSDConnected = mDNSfalse;
7296 }
7297 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
7298 }
7299 }
7300 #elif !TARGET_OS_EMBEDDED
7301 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
7302 {
7303 (void) m; // Unused
7304 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
7305 }
7306 #endif // ! NO_AWACS
7307
7308 #if !TARGET_OS_EMBEDDED
7309 mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
7310 #endif
7311
7312 #endif // APPLE_OSX_mDNSResponder
7313
7314 // MUST be called holding the lock
7315 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
7316 {
7317 #ifdef NO_SECURITYFRAMEWORK
7318 (void) m;
7319 LogMsg("Note: SetDomainSecrets: no keychain support");
7320 #else
7321 mDNSBool haveAutoTunnels = mDNSfalse;
7322
7323 LogInfo("SetDomainSecrets");
7324
7325 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
7326 // In the case where the user simultaneously removes their DDNS host name and the key
7327 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
7328 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
7329 // address records behind that we no longer have permission to delete.
7330 DomainAuthInfo *ptr;
7331 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
7332 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
7333
7334 #if APPLE_OSX_mDNSResponder
7335 {
7336 // Mark all TunnelClients for deletion
7337 ClientTunnel *client;
7338 for (client = m->TunnelClients; client; client = client->next)
7339 {
7340 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
7341 client->MarkedForDeletion = mDNStrue;
7342 }
7343 }
7344 #endif // APPLE_OSX_mDNSResponder
7345
7346 // String Array used to write list of private domains to Dynamic Store
7347 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7348 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
7349 CFIndex i;
7350 CFDataRef data = NULL;
7351 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
7352 CFArrayRef secrets = NULL;
7353 int err = mDNSKeychainGetSecrets(&secrets);
7354 if (err || !secrets)
7355 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
7356 else
7357 {
7358 CFIndex ArrayCount = CFArrayGetCount(secrets);
7359 // Iterate through the secrets
7360 for (i = 0; i < ArrayCount; ++i)
7361 {
7362 mDNSBool AutoTunnel;
7363 int j, offset;
7364 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
7365 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
7366 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
7367 for (j = 0; j < CFArrayGetCount(entry); ++j)
7368 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
7369 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
7370
7371 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
7372
7373 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
7374 // Get DNS domain this key is for (kmDNSKcWhere)
7375 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
7376 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
7377 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
7378 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
7379 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
7380 stringbuf[CFDataGetLength(data)] = '\0';
7381
7382 AutoTunnel = mDNSfalse;
7383 offset = 0;
7384 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
7385 offset = strlen(dnsprefix);
7386 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
7387 {
7388 AutoTunnel = mDNStrue;
7389 offset = strlen(btmmprefix);
7390 }
7391 domainname domain;
7392 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
7393
7394 // Get key name (kmDNSKcAccount)
7395 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
7396 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
7397 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
7398 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
7399 stringbuf[CFDataGetLength(data)] = '\0';
7400
7401 domainname keyname;
7402 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
7403
7404 // Get key data (kmDNSKcKey)
7405 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
7406 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
7407 {
7408 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
7409 continue;
7410 }
7411 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
7412 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
7413
7414 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
7415 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
7416 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
7417 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
7418 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
7419 {
7420 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
7421 continue;
7422 }
7423 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
7424 hostbuf[CFDataGetLength(data)] = '\0';
7425
7426 domainname hostname;
7427 mDNSIPPort port;
7428 char *hptr;
7429 hptr = strchr(hostbuf, ':');
7430
7431 port.NotAnInteger = 0;
7432 if (hptr)
7433 {
7434 mDNSu8 *p;
7435 mDNSu16 val = 0;
7436
7437 *hptr++ = '\0';
7438 while(hptr && *hptr != 0)
7439 {
7440 if (*hptr < '0' || *hptr > '9')
7441 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
7442 val = val * 10 + *hptr - '0';
7443 hptr++;
7444 }
7445 if (!val) continue;
7446 p = (mDNSu8 *)&val;
7447 port.NotAnInteger = p[0] << 8 | p[1];
7448 }
7449 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
7450 hptr = strchr(hostbuf, '@');
7451 if (hptr)
7452 hptr++;
7453 else
7454 hptr = hostbuf;
7455 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
7456
7457 DomainAuthInfo *FoundInList;
7458 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
7459 if (SameDomainName(&FoundInList->domain, &domain)) break;
7460
7461 #if APPLE_OSX_mDNSResponder
7462 if (FoundInList)
7463 {
7464 // If any client tunnel destination is in this domain, set deletion flag to false
7465 ClientTunnel *client;
7466 for (client = m->TunnelClients; client; client = client->next)
7467 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
7468 {
7469 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
7470 client->MarkedForDeletion = mDNSfalse;
7471 }
7472 }
7473
7474 #endif // APPLE_OSX_mDNSResponder
7475
7476 // Uncomment the line below to view the keys as they're read out of the system keychain
7477 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
7478 //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]));
7479 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
7480
7481 // If didn't find desired domain in the list, make a new entry
7482 ptr = FoundInList;
7483 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
7484 if (!FoundInList)
7485 {
7486 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
7487 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
7488 }
7489
7490 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
7491
7492 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
7493 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
7494 {
7495 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
7496 continue;
7497 }
7498
7499 ConvertDomainNameToCString(&domain, stringbuf);
7500 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
7501 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
7502 }
7503 CFRelease(secrets);
7504 }
7505
7506 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
7507 {
7508 if (privateDnsArray)
7509 CFRelease(privateDnsArray);
7510
7511 privateDnsArray = sa;
7512 CFRetain(privateDnsArray);
7513 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
7514 }
7515 CFRelease(sa);
7516
7517 #if APPLE_OSX_mDNSResponder
7518 {
7519 // clean up ClientTunnels
7520 ClientTunnel **pp = &m->TunnelClients;
7521 while (*pp)
7522 {
7523 if ((*pp)->MarkedForDeletion)
7524 {
7525 ClientTunnel *cur = *pp;
7526 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
7527 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
7528 AutoTunnelSetKeys(cur, mDNSfalse);
7529 *pp = cur->next;
7530 freeL("ClientTunnel", cur);
7531 }
7532 else
7533 pp = &(*pp)->next;
7534 }
7535
7536 mDNSBool needAutoTunnelNAT = mDNSfalse;
7537 DomainAuthInfo *info;
7538 for (info = m->AuthInfoList; info; info = info->next)
7539 {
7540 if (info->AutoTunnel)
7541 {
7542 UpdateAutoTunnelDeviceInfoRecord(m, info);
7543 UpdateAutoTunnelHostRecord(m, info);
7544 UpdateAutoTunnelServiceRecords(m, info);
7545 UpdateAutoTunnel6Record(m, info);
7546 if (info->deltime)
7547 {
7548 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
7549 }
7550 else if (info->AutoTunnelServiceStarted)
7551 needAutoTunnelNAT = true;
7552
7553 UpdateAutoTunnelDomainStatus(m, info);
7554 }
7555 }
7556
7557 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
7558 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
7559 {
7560 // stop the NAT operation, reset port, cleanup state
7561 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
7562 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
7563 m->AutoTunnelNAT.NewAddress = zerov4Addr;
7564 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
7565 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
7566 m->AutoTunnelNAT.Lifetime = 0;
7567 m->AutoTunnelNAT.Result = mStatus_NoError;
7568 m->AutoTunnelNAT.clientContext = mDNSNULL;
7569 }
7570
7571 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
7572 ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
7573 }
7574 #endif // APPLE_OSX_mDNSResponder
7575
7576 CheckSuppressUnusableQuestions(m);
7577
7578 #endif /* NO_SECURITYFRAMEWORK */
7579 }
7580
7581 mDNSexport void SetDomainSecrets(mDNS *m)
7582 {
7583 #if DEBUG
7584 // Don't get secrets for BTMM if running in debug mode
7585 if (!IsDebugSocketInUse())
7586 #endif
7587 SetDomainSecrets_internal(m);
7588 }
7589
7590 mDNSlocal void SetLocalDomains(void)
7591 {
7592 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7593 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
7594
7595 CFArrayAppendValue(sa, CFSTR("local"));
7596 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
7597 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
7598 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
7599 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
7600 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
7601
7602 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
7603 CFRelease(sa);
7604 }
7605
7606 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
7607 {
7608
7609 CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
7610 if (!dict)
7611 {
7612 LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
7613 }
7614 else
7615 {
7616 CFNumberRef number = CFDictionaryGetValue(dict, name);
7617 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
7618 *val = 0;
7619 CFRelease(dict);
7620 }
7621
7622 }
7623
7624 #if APPLE_OSX_mDNSResponder
7625
7626 static CFMutableDictionaryRef spsStatusDict = NULL;
7627 static const CFStringRef kMetricRef = CFSTR("Metric");
7628
7629 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
7630 {
7631 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
7632 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
7633 if (!num)
7634 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
7635 else
7636 {
7637 CFDictionarySetValue(dict, key, num);
7638 CFRelease(num);
7639 }
7640 }
7641
7642 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
7643 {
7644 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7645 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
7646
7647 char buffer[1024];
7648 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
7649 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7650 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
7651 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
7652 CFRelease(spsname);
7653
7654 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
7655 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
7656 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
7657 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
7658
7659 mDNSu32 tmp = SPSMetric(ptr);
7660 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
7661 if (!num)
7662 LogMsg("SPSCreateDict: Could not create CFNumber");
7663 else
7664 {
7665 CFDictionarySetValue(dict, kMetricRef, num);
7666 CFRelease(num);
7667 }
7668
7669 if (ptr[0] >= 12)
7670 {
7671 memcpy(buffer, ptr + 13, ptr[0] - 12);
7672 buffer[ptr[0] - 12] = 0;
7673 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7674 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
7675 else
7676 {
7677 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
7678 CFRelease(spsname);
7679 }
7680 }
7681
7682 return dict;
7683 }
7684
7685 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
7686 {
7687 (void)context;
7688 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
7689 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
7690 NULL);
7691 }
7692
7693 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7694 {
7695 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
7696 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
7697
7698 mDNS_Lock(m);
7699 mDNS_UpdateAllowSleep(m);
7700 mDNS_Unlock(m);
7701
7702 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
7703
7704 if (!spsStatusDict)
7705 {
7706 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7707 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
7708 }
7709
7710 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
7711 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
7712
7713 CFMutableArrayRef array = NULL;
7714
7715 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
7716 {
7717 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7718 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
7719 CFDictionarySetValue(spsStatusDict, ifname, array);
7720 CFRelease(array); // let go of our reference, now that the dict has one
7721 }
7722 else
7723 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
7724
7725 if (!answer) // special call that means the question has been stopped (because the interface is going away)
7726 CFArrayRemoveAllValues(array);
7727 else
7728 {
7729 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
7730 if (!dict) { CFRelease(ifname); return; }
7731
7732 if (AddRecord)
7733 {
7734 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
7735 {
7736 int i=0;
7737 for (i=0; i<CFArrayGetCount(array); i++)
7738 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
7739 break;
7740 CFArrayInsertValueAtIndex(array, i, dict);
7741 }
7742 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
7743 }
7744 else
7745 {
7746 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
7747 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
7748 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
7749 }
7750
7751 CFRelease(dict);
7752 }
7753
7754 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
7755
7756 CFRelease(ifname);
7757 }
7758
7759 #if !TARGET_OS_EMBEDDED
7760 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
7761 {
7762 mDNSs32 val = -1;
7763 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
7764 if (!store)
7765 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7766 else
7767 {
7768 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
7769 if (dict)
7770 {
7771 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
7772 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
7773 CFRelease(dict);
7774 }
7775 CFRelease(store);
7776 }
7777 return val;
7778 }
7779
7780 mDNSlocal void SetSPS(mDNS *const m)
7781 {
7782
7783 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
7784 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
7785
7786 // For devices that are not running NAT, but are set to never sleep, we may choose to act
7787 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
7788 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
7789
7790 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
7791
7792 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
7793 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
7794 // We rate such a device as metric 70 ("Incidentally Available Hardware")
7795 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
7796
7797 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
7798 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
7799 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
7800
7801 #ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
7802 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
7803 if (IsAppleTV())
7804 {
7805 NetworkInterfaceInfo *intf = mDNSNULL;
7806 mDNSEthAddr bssid = zeroEthAddr;
7807 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
7808 {
7809 bssid = GetBSSID(intf->ifname);
7810 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
7811 {
7812 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
7813 sps = 0;
7814 break;
7815 }
7816 }
7817 }
7818 #endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
7819
7820 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
7821 }
7822 #endif // !TARGET_OS_EMBEDDED
7823
7824 // The definitions below should eventually come from some externally-supplied header file.
7825 // However, since these definitions can't really be changed without breaking binary compatibility,
7826 // they should never change, so in practice it should not be a big problem to have them defined here.
7827
7828 enum
7829 { // commands from the daemon to the driver
7830 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
7831 };
7832
7833 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
7834
7835 typedef struct
7836 { // cmd_mDNSOffloadRR structure
7837 uint32_t command; // set to OffloadRR
7838 uint32_t rrBufferSize; // number of bytes of RR records
7839 uint32_t numUDPPorts; // number of SRV UDP ports
7840 uint32_t numTCPPorts; // number of SRV TCP ports
7841 uint32_t numRRRecords; // number of RR records
7842 uint32_t compression; // rrRecords - compression is base for compressed strings
7843 FatPtr rrRecords; // address of array of pointers to the rr records
7844 FatPtr udpPorts; // address of udp port list (SRV)
7845 FatPtr tcpPorts; // address of tcp port list (SRV)
7846 } mDNSOffloadCmd;
7847
7848 #include <IOKit/IOKitLib.h>
7849 #include <dns_util.h>
7850
7851 mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
7852 {
7853 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
7854 int count = 0;
7855
7856 AuthRecord *rr;
7857 for (rr = m->ResourceRecords; rr; rr=rr->next)
7858 {
7859 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
7860 {
7861 if (!portarray)
7862 count++;
7863 else
7864 {
7865 int i;
7866 for (i = 0; i < count; i++)
7867 if (mDNSSameIPPort(portarray[i], rr->resrec.rdata->u.srv.port))
7868 break;
7869
7870 // Add it into the port list only if it not already present in the list
7871 if (i >= count)
7872 portarray[count++] = rr->resrec.rdata->u.srv.port;
7873 }
7874 }
7875 }
7876
7877 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
7878 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
7879 {
7880 LogSPS("GetPortArray Back to My Mac at %d", count);
7881 if (portarray) portarray[count] = IPSECPort;
7882 count++;
7883 }
7884 return(count);
7885 }
7886
7887 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7888 mDNSlocal mDNSBool SupportsTCPKeepAlive()
7889 {
7890 IOReturn ret = kIOReturnSuccess;
7891 CFTypeRef obj = NULL;
7892 mDNSBool supports = mDNSfalse;
7893
7894 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
7895 if ((kIOReturnSuccess == ret) && (obj != NULL))
7896 {
7897 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
7898 CFRelease(obj);
7899 }
7900 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
7901 return supports;
7902 }
7903
7904 mDNSlocal mDNSBool OnBattery(void)
7905 {
7906 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
7907 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
7908 mDNSBool result = mDNSfalse;
7909
7910 if (powerInfo != NULL)
7911 {
7912 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
7913 CFRelease(powerInfo);
7914 }
7915 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
7916 return result;
7917 }
7918
7919 #endif // !TARGET_OS_EMBEDDED
7920
7921 #define TfrRecordToNIC(RR) \
7922 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
7923
7924 mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7925 {
7926 *numbytes = 0;
7927 int count = 0;
7928
7929 AuthRecord *rr;
7930
7931 for (rr = m->ResourceRecords; rr; rr=rr->next)
7932 {
7933 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7934 {
7935 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7936 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7937 // Skip over all other records if we are registering TCP KeepAlive records only
7938 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
7939 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7940 continue;
7941
7942 // Update the record before calculating the number of bytes required
7943 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7944 // attempt to update the record again.
7945 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
7946 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7947
7948 // Offload only Valid Keepalive records
7949 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
7950 continue;
7951 #else
7952 (void) TCPKAOnly; // unused
7953 (void) supportsTCPKA; // unused
7954 (void) intf; // unused
7955 #endif // APPLE_OSX_mDNSResponder
7956 if (TfrRecordToNIC(rr))
7957 {
7958 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
7959 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
7960 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
7961 count++;
7962 }
7963 }
7964 }
7965 return(count);
7966 }
7967
7968 mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7969 {
7970 mDNSu8 *p = msg->data;
7971 const mDNSu8 *const limit = p + *numbytes;
7972 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7973
7974 int count = 0;
7975 AuthRecord *rr;
7976
7977 for (rr = m->ResourceRecords; rr; rr=rr->next)
7978 {
7979 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7980 {
7981 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7982 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7983
7984 // Skip over all other records if we are registering TCP KeepAlive records only
7985 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7986 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7987 continue;
7988
7989 // Offload only Valid Keepalive records
7990 if (isKeepAliveRecord && !mDNSValidKeepAliveRecord(rr))
7991 continue;
7992 #else
7993 (void) TCPKAOnly; // unused
7994 (void) supportsTCPKA; // unused
7995 #endif // APPLE_OSX_mDNSResponder
7996
7997 if (TfrRecordToNIC(rr))
7998 {
7999 records[count].sixtyfourbits = zeroOpaque64;
8000 records[count].ptr = p;
8001 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
8002 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
8003 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
8004 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
8005 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
8006 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
8007 count++;
8008 }
8009 }
8010 }
8011 *numbytes = p - msg->data;
8012 }
8013
8014 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
8015 {
8016 if(!UseInternalSleepProxy)
8017 {
8018 LogMsg("SupportsInNICProxy: Internal Sleep Proxy is disabled");
8019 return mDNSfalse;
8020 }
8021 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
8022 }
8023
8024 mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly) // Called with the lock held
8025 {
8026 mStatus result = mStatus_UnknownErr;
8027 mDNSBool TCPKAOnly = mDNSfalse;
8028 mDNSBool supportsTCPKA = mDNSfalse;
8029 mDNSBool onbattery = mDNSfalse;
8030 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
8031
8032 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8033 onbattery = OnBattery();
8034 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
8035 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
8036
8037 // Only TCP Keepalive records are to be offloaded if
8038 // - The system is on battery
8039 // - OR wake for network access is not set but powernap is enabled
8040 TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
8041 #else
8042 (void) onbattery; // unused;
8043 #endif
8044 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
8045
8046 io_name_t n1, n2;
8047 IOObjectGetClass(service, n1);
8048 io_object_t parent;
8049 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
8050 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
8051 else
8052 {
8053 IOObjectGetClass(parent, n2);
8054 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
8055 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
8056 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
8057 else
8058 {
8059 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
8060 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
8061 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
8062 else if (!UseInternalSleepProxy)
8063 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
8064 else
8065 {
8066 io_connect_t conObj;
8067 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
8068 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
8069 else
8070 {
8071 mDNSOffloadCmd cmd;
8072 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
8073 cmd.command = cmd_mDNSOffloadRR;
8074 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
8075 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
8076 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
8077 cmd.compression = sizeof(DNSMessageHeader);
8078
8079 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
8080 cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
8081 cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
8082 cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
8083
8084 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
8085 msg, cmd.rrBufferSize,
8086 cmd.rrRecords.ptr, cmd.numRRRecords,
8087 cmd.udpPorts.ptr, cmd.numUDPPorts,
8088 cmd.tcpPorts.ptr, cmd.numTCPPorts);
8089
8090 if (msg && cmd.rrRecords.ptr) GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
8091 if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
8092 if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
8093
8094 char outputData[2];
8095 size_t outputDataSize = sizeof(outputData);
8096 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
8097 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
8098 if (kr == KERN_SUCCESS) result = mStatus_NoError;
8099
8100 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
8101 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
8102 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
8103 if (msg) freeL("mDNSOffloadCmd msg", msg);
8104 IOServiceClose(conObj);
8105 }
8106 }
8107 CFRelease(ref);
8108 }
8109 IOObjectRelease(parent);
8110 }
8111 IOObjectRelease(service);
8112 *keepaliveOnly = TCPKAOnly;
8113 return result;
8114 }
8115
8116 #endif // APPLE_OSX_mDNSResponder
8117
8118 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
8119 {
8120 mDNSs32 val = 0;
8121 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
8122
8123 if (DisableSleepProxyClient)
8124 {
8125 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
8126 return mDNSfalse;
8127 }
8128
8129 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
8130
8131 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
8132
8133 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8134 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
8135 // Further policy decisions on whether to offload the records is handled during sleep processing.
8136 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
8137 ret = (mDNSu8)mDNS_WakeOnBattery;
8138 #endif // APPLE_OSX_mDNSResponder
8139
8140 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
8141 return ret;
8142 }
8143
8144 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
8145 {
8146 mDNSs32 val = 0;
8147 // PrioritizeNetworkReachabilityOverSleep has been deprecated.
8148 // GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
8149 // Statically set the PrioritizeNetworkReachabilityOverSleep value to 1 for AppleTV
8150 if (IsAppleTV())
8151 val = 1;
8152 return val != 0 ? mDNStrue : mDNSfalse;
8153 }
8154
8155
8156 #if APPLE_OSX_mDNSResponder
8157 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
8158 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
8159 // the RR relay.
8160 //
8161 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
8162 // service records are deregistered, so they do not appear in peers' Finder sidebars.
8163 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
8164 // depend on their associated SRV record and therefore will be deregistered together in a
8165 // single update with the SRV record.
8166 //
8167 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
8168 // its presence shouldn't delay sleep.
8169 //
8170 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
8171 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
8172 //
8173 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
8174 mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
8175 {
8176 if (!AuthRecord_uDNS(rr)) return mDNStrue;
8177
8178 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
8179 {
8180 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
8181 return mDNSfalse;
8182 }
8183
8184 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
8185 {
8186 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
8187 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
8188 {
8189 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
8190 if (info && info->AutoTunnel)
8191 {
8192 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
8193 return mDNSfalse;
8194 }
8195 }
8196 }
8197
8198 return mDNStrue;
8199 }
8200
8201 // Caller must hold the lock
8202 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
8203 {
8204 DomainAuthInfo *info;
8205 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
8206 // deregister the record, and the MemFree callback won't re-register.
8207 m->AutoTunnelRelayAddr = zerov6Addr;
8208 for (info = m->AuthInfoList; info; info = info->next)
8209 if (info->AutoTunnel)
8210 UpdateAutoTunnel6Record(m, info);
8211 }
8212
8213 #if !TARGET_OS_EMBEDDED
8214 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
8215 {
8216 struct ifaddrs *ifa;
8217 struct ifaddrs *ifaddrs;
8218 mDNSAddr addr;
8219
8220 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
8221
8222 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
8223
8224 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
8225 {
8226 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
8227 continue;
8228 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
8229 continue;
8230 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
8231 {
8232 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
8233 continue;
8234 }
8235 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
8236 {
8237 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
8238 break;
8239 }
8240 }
8241 freeifaddrs(ifaddrs);
8242 return ifa != NULL;
8243 }
8244
8245 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
8246 {
8247 mDNSv6Addr retVal;
8248 struct addrinfo hints;
8249 struct addrinfo *res0;
8250
8251 memset(&hints, 0, sizeof(hints));
8252 hints.ai_family = AF_INET6;
8253 hints.ai_flags = AI_NUMERICHOST;
8254
8255 int err = getaddrinfo(buf, NULL, &hints, &res0);
8256 if (err)
8257 return zerov6Addr;
8258
8259 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
8260
8261 freeaddrinfo(res0);
8262
8263 return retVal;
8264 }
8265
8266 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
8267 {
8268 CFDictionaryRef connd = NULL;
8269 CFDictionaryRef BTMMDict = NULL;
8270
8271 connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
8272 if (!connd)
8273 {
8274 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
8275 goto end;
8276 }
8277
8278 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
8279 if (!BTMMDict)
8280 {
8281 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
8282 goto end;
8283 }
8284
8285 // Non-dictionary is treated as non-existent dictionary
8286 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
8287 {
8288 BTMMDict = NULL;
8289 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
8290 goto end;
8291 }
8292
8293 CFRetain(BTMMDict);
8294
8295 end:
8296 if (connd) CFRelease(connd);
8297
8298 return BTMMDict;
8299 }
8300
8301 #define MAX_IPV6_TEXTUAL 40
8302
8303 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
8304 {
8305 mDNSv6Addr retVal = zerov6Addr;
8306 CFTypeRef string = NULL;
8307 char ifname[IFNAMSIZ];
8308 char address[MAX_IPV6_TEXTUAL];
8309
8310 if (!BTMMDict)
8311 return zerov6Addr;
8312
8313 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
8314 {
8315 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
8316 return zerov6Addr;
8317 }
8318
8319 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
8320 {
8321 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
8322 return zerov6Addr;
8323 }
8324
8325 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
8326 {
8327 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
8328 return zerov6Addr;
8329 }
8330
8331 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
8332 {
8333 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
8334 return zerov6Addr;
8335 }
8336
8337 retVal = IPv6AddressFromString(address);
8338 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
8339
8340 if (mDNSIPv6AddressIsZero(retVal))
8341 return zerov6Addr;
8342
8343 if (!IPv6AddressIsOnInterface(retVal, ifname))
8344 {
8345 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
8346 return zerov6Addr;
8347 }
8348
8349 return retVal;
8350 }
8351
8352 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
8353 {
8354 CFTypeRef zones = NULL;
8355
8356 if (!BTMMDict)
8357 return NULL;
8358
8359 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
8360 {
8361 LogInfo("CopyBTMMZones: Zones key does not exist");
8362 return NULL;
8363 }
8364
8365 return zones;
8366 }
8367
8368 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
8369 {
8370 mDNSv6Addr addr = zerov6Addr;
8371 char buffer[MAX_ESCAPED_DOMAIN_NAME];
8372 CFStringRef domain = NULL;
8373 CFTypeRef theZone = NULL;
8374
8375 if (!zones)
8376 return addr;
8377
8378 ConvertDomainNameToCString(&info->domain, buffer);
8379 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
8380 if (!domain)
8381 return addr;
8382
8383 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
8384 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
8385
8386 CFRelease(domain);
8387
8388 return addr;
8389 }
8390
8391 mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
8392 {
8393 DomainAuthInfo* info;
8394 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
8395 mDNSv6Addr newAddr;
8396
8397 for (info = m->AuthInfoList; info; info = info->next)
8398 {
8399 if (!info->AutoTunnel)
8400 continue;
8401
8402 newAddr = ParseBackToMyMacZone(zones, info);
8403
8404 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
8405 continue;
8406
8407 info->AutoTunnelInnerAddress = newAddr;
8408 DeregisterAutoTunnelHostRecord(m, info);
8409 UpdateAutoTunnelHostRecord(m, info);
8410 UpdateAutoTunnelDomainStatus(m, info);
8411 }
8412 }
8413
8414 // MUST be called holding the lock
8415 mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
8416 {
8417 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
8418 if (!dict)
8419 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
8420 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
8421
8422 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
8423
8424 SetupBackToMyMacInnerAddresses(m, dict);
8425
8426 if (dict) CFRelease(dict);
8427
8428 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
8429 {
8430 m->AutoTunnelRelayAddr = relayAddr;
8431
8432 DomainAuthInfo* info;
8433 for (info = m->AuthInfoList; info; info = info->next)
8434 if (info->AutoTunnel)
8435 {
8436 DeregisterAutoTunnel6Record(m, info);
8437 UpdateAutoTunnel6Record(m, info);
8438 UpdateAutoTunnelDomainStatus(m, info);
8439 }
8440
8441 // Determine whether we need racoon to accept incoming connections
8442 UpdateAnonymousRacoonConfig(m);
8443 }
8444
8445 // If awacsd crashes or exits for some reason, restart it
8446 UpdateBTMMRelayConnection(m);
8447 }
8448 #endif // !TARGET_OS_EMBEDDED
8449 #endif /* APPLE_OSX_mDNSResponder */
8450
8451 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
8452 {
8453 DNSServer *s;
8454 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
8455 for (s = m->DNSServers; s; s = s->next)
8456 {
8457 if (s->addr.ip.v4.b[0] == 17)
8458 {
8459 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
8460 return mDNStrue;
8461 }
8462 }
8463 return mDNSfalse;
8464 }
8465
8466 // Called with KQueueLock & mDNS lock
8467 // SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
8468 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
8469 {
8470 mDNS_CheckLock(m);
8471 if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
8472 {
8473 m->NetworkChanged = NonZeroTime(m->timenow + delay);
8474 LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
8475 }
8476 else
8477 LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
8478 }
8479
8480 // Called with KQueueLock & mDNS lock
8481 mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
8482 {
8483 // If it's not set or it needs to happen sooner than when it's currently set
8484 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
8485 {
8486 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
8487 LogInfo("SetKeyChainTimer: %d", delay);
8488 }
8489 }
8490
8491 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
8492 {
8493 LogInfo("*** Network Configuration Change *** %d ticks late%s",
8494 m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
8495 m->NetworkChanged ? "" : " (no scheduled configuration change)");
8496 m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
8497
8498 // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
8499 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
8500 if (InfoSocket > 0)
8501 {
8502 mDNSBool tentative = mDNSfalse;
8503 struct ifaddrs *ifa = myGetIfAddrs(1);
8504 while (ifa)
8505 {
8506 if (ifa->ifa_addr->sa_family == AF_INET6)
8507 {
8508 struct in6_ifreq ifr6;
8509 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
8510 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
8511 ifr6.ifr_addr = *(struct sockaddr_in6 *)ifa->ifa_addr;
8512 // We need to check for IN6_IFF_TENTATIVE here, not IN6_IFF_NOTREADY, because
8513 // IN6_IFF_NOTREADY includes both IN6_IFF_TENTATIVE and IN6_IFF_DUPLICATED addresses.
8514 // We can expect that an IN6_IFF_TENTATIVE address will shortly become ready,
8515 // but an IN6_IFF_DUPLICATED address may not.
8516 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
8517 {
8518 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
8519 {
8520 LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
8521 tentative = mDNStrue;
8522 // no need to check other interfaces if we already found out that one interface is TENTATIVE
8523 break;
8524 }
8525 }
8526 }
8527 ifa = ifa->ifa_next;
8528 }
8529 close(InfoSocket);
8530 if (tentative)
8531 {
8532 mDNS_Lock(m);
8533 SetNetworkChanged(m, mDNSPlatformOneSecond / 2);
8534 mDNS_Unlock(m);
8535 return;
8536 }
8537 LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
8538 }
8539
8540 mDNSs32 utc = mDNSPlatformUTC();
8541 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8542 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
8543 MarkAllInterfacesInactive(m, utc);
8544 UpdateInterfaceList(m, utc);
8545 ClearInactiveInterfaces(m, utc);
8546 SetupActiveInterfaces(m, utc);
8547
8548 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
8549
8550 mDNS_Lock(m);
8551 ProcessConndConfigChanges(m);
8552 mDNS_Unlock(m);
8553
8554 // Scan to find client tunnels whose questions have completed,
8555 // but whose local inner/outer addresses have changed since the tunnel was set up
8556 ClientTunnel *p;
8557 for (p = m->TunnelClients; p; p = p->next)
8558 if (p->q.ThisQInterval < 0)
8559 {
8560 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
8561 if (!info)
8562 {
8563 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
8564 AutoTunnelSetKeys(p, mDNSfalse);
8565 }
8566 else
8567 {
8568 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
8569
8570 if (!mDNSIPPortIsZero(p->rmt_outer_port))
8571 {
8572 mDNSAddr tmpSrc = zeroAddr;
8573 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
8574 tmpDst.ip.v4 = p->rmt_outer;
8575 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
8576 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
8577 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
8578 {
8579 AutoTunnelSetKeys(p, mDNSfalse);
8580 p->loc_inner = inner;
8581 p->loc_outer = tmpSrc.ip.v4;
8582 AutoTunnelSetKeys(p, mDNStrue);
8583 }
8584 }
8585 else
8586 {
8587 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
8588 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
8589 {
8590 AutoTunnelSetKeys(p, mDNSfalse);
8591 p->loc_inner = inner;
8592 p->loc_outer6 = m->AutoTunnelRelayAddr;
8593 AutoTunnelSetKeys(p, mDNStrue);
8594 }
8595 }
8596 }
8597 }
8598
8599 SetSPS(m);
8600
8601 NetworkInterfaceInfoOSX *i;
8602 for (i = m->p->InterfaceList; i; i = i->next)
8603 {
8604 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
8605 {
8606 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0)
8607 CloseBPF(i);
8608 }
8609 else // else, we're Sleep Proxy Server; open BPF fds
8610 {
8611 if (i->Exists && (i->Registered == i) && SPSInterface(i) && i->BPF_fd == -1)
8612 {
8613 LogMsg("%s mDNSMacOSXNetworkChanged: requesting BPF", i->ifinfo.ifname);
8614 i->BPF_fd = -2;
8615 mDNSRequestBPF();
8616 }
8617 }
8618 }
8619
8620 #endif // APPLE_OSX_mDNSResponder
8621
8622 uDNS_SetupDNSConfig(m);
8623 mDNS_ConfigChanged(m);
8624
8625 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
8626 {
8627 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
8628 LogInfo("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
8629 UpdateDebugState();
8630 }
8631
8632 }
8633
8634 // Copy the fourth slash-delimited element from either:
8635 // State:/Network/Interface/<bsdname>/IPv4
8636 // or
8637 // Setup:/Network/Service/<servicename>/Interface
8638 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
8639 {
8640 CFArrayRef a;
8641 CFStringRef name = NULL;
8642
8643 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
8644 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
8645 if (a != NULL) CFRelease(a);
8646
8647 return name;
8648 }
8649
8650 // Whether a key from a network change notification corresponds to
8651 // an IP service that is explicitly configured for IPv4 Link Local
8652 mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
8653 {
8654 CFDictionaryRef dict = NULL;
8655 CFMutableArrayRef a;
8656 const void **keys = NULL, **vals = NULL;
8657 CFStringRef pattern = NULL;
8658 int i, ic, j, jc;
8659 int found = 0;
8660
8661 jc = CFArrayGetCount(inkeys);
8662 if (!jc) goto done;
8663
8664 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8665 if (a == NULL) goto done;
8666
8667 // Setup:/Network/Service/[^/]+/Interface
8668 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
8669 if (pattern == NULL) goto done;
8670 CFArrayAppendValue(a, pattern);
8671 CFRelease(pattern);
8672
8673 // Setup:/Network/Service/[^/]+/IPv4
8674 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
8675 if (pattern == NULL) goto done;
8676 CFArrayAppendValue(a, pattern);
8677 CFRelease(pattern);
8678
8679 dict = SCDynamicStoreCopyMultiple(NULL, NULL, a);
8680 CFRelease(a);
8681
8682 if (!dict)
8683 {
8684 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
8685 goto done;
8686 }
8687
8688 ic = CFDictionaryGetCount(dict);
8689 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
8690 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
8691 CFDictionaryGetKeysAndValues(dict, keys, vals);
8692
8693 // For each key we were given...
8694 for (j = 0; j < jc; j++)
8695 {
8696 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
8697 CFStringRef ifname = NULL;
8698
8699 char buf[256];
8700
8701 // It would be nice to use a regex here
8702 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
8703
8704 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
8705 if (mDNS_LoggingEnabled)
8706 {
8707 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8708 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
8709 }
8710
8711 // Loop over the interfaces to find matching the ifname, and see if that one has kSCValNetIPv4ConfigMethodLinkLocal
8712 for (i = 0; i < ic; i++)
8713 {
8714 CFDictionaryRef ipv4dict;
8715 CFStringRef name;
8716 CFStringRef serviceid;
8717 CFStringRef configmethod;
8718
8719 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
8720
8721 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
8722
8723 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
8724
8725 if (!CFEqual(ifname, name)) continue;
8726
8727 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
8728 if (mDNS_LoggingEnabled)
8729 {
8730 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8731 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
8732 }
8733
8734 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
8735 CFRelease(serviceid);
8736 if (pattern == NULL) continue;
8737
8738 ipv4dict = CFDictionaryGetValue(dict, pattern);
8739 CFRelease(pattern);
8740 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
8741
8742 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
8743 if (!configmethod) continue;
8744
8745 if (mDNS_LoggingEnabled)
8746 {
8747 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8748 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
8749 }
8750
8751 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found++; break; }
8752 }
8753
8754 CFRelease(ifname);
8755 }
8756
8757 done:
8758 if (vals != NULL) mDNSPlatformMemFree(vals);
8759 if (keys != NULL) mDNSPlatformMemFree(keys);
8760 if (dict != NULL) CFRelease(dict);
8761
8762 return found;
8763 }
8764
8765 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
8766 {
8767 (void)store; // Parameter not used
8768 mDNS *const m = (mDNS *const)context;
8769 KQueueLock(m);
8770 mDNS_Lock(m);
8771
8772 //mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
8773 const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
8774
8775 int c = CFArrayGetCount(changedKeys); // Count changes
8776 CFRange range = { 0, c };
8777 int c_host = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
8778 int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
8779 int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
8780 int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
8781 int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
8782 int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
8783 int c_fast = 0;
8784
8785 // Do immediate network changed processing for "p2p*" interfaces and
8786 // for interfaces with the IFEF_DIRECTLINK flag set or association with a CarPlay
8787 // hosted SSID.
8788 {
8789 CFArrayRef labels;
8790 CFIndex n;
8791 for (int i = 0; i < c; i++)
8792 {
8793 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
8794
8795 // Only look at keys with prefix "State:/Network/Interface/"
8796 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
8797 continue;
8798
8799 // And suffix "IPv6" or "IPv4".
8800 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
8801 continue;
8802
8803 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
8804 if (labels == NULL)
8805 break;
8806 n = CFArrayGetCount(labels);
8807
8808 // Interface changes will have keys of the form:
8809 // State:/Network/Interface/<interfaceName>/IPv6
8810 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
8811 if (n == 5)
8812 {
8813 char buf[256];
8814
8815 // The 4th label (index = 3) should be the interface name.
8816 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
8817 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK) || IsCarPlaySSID(buf)))
8818 {
8819 LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
8820 c_fast++;
8821 CFRelease(labels);
8822 break;
8823 }
8824 }
8825 CFRelease(labels);
8826 }
8827 }
8828
8829 //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
8830 // delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
8831
8832 if (mDNS_LoggingEnabled)
8833 {
8834 int i;
8835 for (i=0; i<c; i++)
8836 {
8837 char buf[256];
8838 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8839 LogInfo("*** Network Configuration Change *** SC key: %s", buf);
8840 }
8841 LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
8842 c, c>1 ? "s" : "",
8843 c_host ? "(Local Hostname) " : "",
8844 c_comp ? "(Computer Name) " : "",
8845 c_udns ? "(DNS) " : "",
8846 c_ddns ? "(DynamicDNS) " : "",
8847 c_btmm ? "(BTMM) " : "",
8848 c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
8849 c_fast ? "(P2P/IFEF_DIRECTLINK/IsCarPlaySSID) " : "",
8850 delay,
8851 (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
8852 }
8853
8854 SetNetworkChanged(m, delay);
8855
8856 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
8857 // so in order for secure updates to be made to the server, make sure to read the keychain and
8858 // setup the DomainAuthInfo before handing the network change.
8859 // If we don't, then we will first try to register services in the clear, then later setup the
8860 // DomainAuthInfo, which is incorrect.
8861 if (c_ddns || c_btmm)
8862 SetKeyChainTimer(m, delay);
8863
8864 // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
8865
8866 mDNS_Unlock(m);
8867 KQueueUnlock(m, "NetworkChanged");
8868 }
8869
8870 #if APPLE_OSX_mDNSResponder
8871 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
8872 {
8873 (void)context;
8874 char buf[IFNAMSIZ];
8875
8876 CFStringRef ifnameStr = (CFStringRef)key;
8877 CFArrayRef array = (CFArrayRef)value;
8878 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
8879 buf[0] = 0;
8880
8881 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
8882 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
8883 }
8884 #endif
8885
8886 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
8887 {
8888 mDNS *const m = (mDNS *const)info;
8889 (void)store;
8890
8891 KQueueLock(m); // serialize with KQueueLoop()
8892
8893 LogInfo("DynamicStoreReconnected: Reconnected");
8894
8895 // State:/Network/MulticastDNS
8896 SetLocalDomains();
8897
8898 // State:/Network/DynamicDNS
8899 if (m->FQDN.c[0])
8900 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
8901
8902 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
8903 // as we receive network change notifications and thus not necessary. But we leave it here
8904 // so that if things are done differently in the future, this code still works.
8905
8906 // State:/Network/PrivateDNS
8907 if (privateDnsArray)
8908 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
8909
8910 #if APPLE_OSX_mDNSResponder
8911 // State:/Network/BackToMyMac
8912 UpdateAutoTunnelDomainStatuses(m);
8913
8914 // State:/Network/Interface/en0/SleepProxyServers
8915 if (spsStatusDict)
8916 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
8917 #endif
8918 KQueueUnlock(m, "DynamicStoreReconnected");
8919 }
8920
8921 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8922 {
8923 mStatus err = -1;
8924 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8925 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8926 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8927 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8928 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8929 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8930
8931 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8932 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8933
8934 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8935 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8936 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8937 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8938 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8939 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8940 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8941 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
8942 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8943 CFArrayAppendValue(patterns, pattern1);
8944 CFArrayAppendValue(patterns, pattern2);
8945 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8946 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8947 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8948
8949 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8950 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8951 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8952 #else
8953 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8954 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8955 CFRunLoopAddSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8956 #endif
8957 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8958 m->p->Store = store;
8959 err = 0;
8960 goto exit;
8961
8962 error:
8963 if (store) CFRelease(store);
8964
8965 exit:
8966 if (patterns) CFRelease(patterns);
8967 if (pattern2) CFRelease(pattern2);
8968 if (pattern1) CFRelease(pattern1);
8969 if (keys) CFRelease(keys);
8970
8971 return(err);
8972 }
8973
8974 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8975
8976 mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
8977 {
8978 AuthRecord *rr;
8979 pfArray_t portArray;
8980 pfArray_t protocolArray;
8981 uint32_t count = 0;
8982
8983 for (rr = m->ResourceRecords; rr; rr=rr->next)
8984 {
8985 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8986 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8987 {
8988 const mDNSu8 *p;
8989
8990 if (count >= PFPortArraySize)
8991 {
8992 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8993 continue;
8994 }
8995
8996 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8997 {
8998 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8999 continue;
9000 }
9001
9002 LogMsg("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
9003
9004 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
9005
9006 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
9007 p = rr->resrec.name->c;
9008
9009 // Skip to App Protocol
9010 if (p[0])
9011 p += 1 + p[0];
9012
9013 // Skip to Transport Protocol
9014 if (p[0])
9015 p += 1 + p[0];
9016
9017 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp"))
9018 {
9019 protocolArray[count] = IPPROTO_TCP;
9020 }
9021 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp"))
9022 {
9023 protocolArray[count] = IPPROTO_UDP;
9024 }
9025 else
9026 {
9027 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
9028 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
9029 return;
9030 }
9031 count++;
9032 }
9033 }
9034 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
9035 }
9036
9037 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
9038 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
9039 {
9040 mDNS *const m = &mDNSStorage;
9041
9042 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
9043 while (intf)
9044 {
9045 if (strncmp(intf->ifname, "p2p", 3) == 0)
9046 {
9047 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
9048 mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
9049 break;
9050 }
9051 intf = GetFirstActiveInterface(intf->next);
9052 }
9053 }
9054
9055 #else // !TARGET_OS_EMBEDDED
9056
9057 // Currently no packet filter setup required on embedded platforms.
9058 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
9059 {
9060 (void) excludeRecord; // unused
9061 }
9062
9063 #endif // !TARGET_OS_EMBEDDED
9064
9065 // Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
9066 // marked to include the AWDL interface.
9067 mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
9068 {
9069 char ifname[IFNAMSIZ];
9070 mDNSu32 interfaceIndex;
9071 DNSQuestion *q;
9072 AuthRecord *rr;
9073 NetworkInterfaceInfoOSX *infoOSX;
9074 mDNSInterfaceID InterfaceID;
9075
9076 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
9077 interfaceIndex = if_nametoindex(ifname);
9078
9079 if (!interfaceIndex)
9080 {
9081 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
9082 return;
9083 }
9084
9085 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
9086 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
9087 if (!infoOSX)
9088 {
9089 LogInfo("newMasterElected: interface %s not yet active", ifname);
9090 return;
9091 }
9092 InterfaceID = infoOSX->ifinfo.InterfaceID;
9093
9094 for (q = m->Questions; q; q=q->next)
9095 {
9096 if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
9097 || q->InterfaceID == InterfaceID)
9098 {
9099 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
9100 mDNSCoreRestartQuestion(m, q);
9101 }
9102 }
9103
9104 for (rr = m->ResourceRecords; rr; rr=rr->next)
9105 {
9106 if ((!rr->resrec.InterfaceID
9107 && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
9108 || rr->resrec.InterfaceID == InterfaceID)
9109 {
9110 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
9111 mDNSCoreRestartRegistration(m, rr, -1);
9112 }
9113 }
9114 }
9115
9116 // An ssth array of all zeroes indicates the peer has no services registered.
9117 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
9118 {
9119 int i;
9120 int *intp = (int *) op->ssth;
9121
9122 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
9123 // it's not, print an error message and return false so that
9124 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
9125 // is received.
9126 if (MAX_SSTH_SIZE % sizeof(int))
9127 {
9128 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
9129 return mDNSfalse;
9130 }
9131
9132 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
9133 {
9134 if (*intp)
9135 return mDNSfalse;
9136 }
9137 return mDNStrue;
9138 }
9139
9140 // Mark records from this peer for deletion from the cache.
9141 mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
9142 {
9143 mDNSu32 slot;
9144 CacheGroup *cg;
9145 CacheRecord *cr;
9146 NetworkInterfaceInfoOSX *infoOSX;
9147 mDNSInterfaceID InterfaceID;
9148
9149 // Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
9150 // locking issues, see: <rdar://problem/21332983>
9151 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
9152 if (!infoOSX)
9153 {
9154 LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
9155 return;
9156 }
9157 InterfaceID = infoOSX->ifinfo.InterfaceID;
9158
9159 FORALL_CACHERECORDS(slot, cg, cr)
9160 {
9161 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
9162 {
9163 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
9164 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
9165
9166 if (purgeNow)
9167 mDNS_PurgeCacheResourceRecord(m, cr);
9168 else
9169 mDNS_Reconfirm_internal(m, cr, 0); // use default minimum reconfirm time
9170 }
9171 }
9172 }
9173
9174 // Handle KEV_DL_NODE_PRESENCE event.
9175 mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
9176 {
9177 char buf[INET6_ADDRSTRLEN];
9178 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
9179
9180 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
9181 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
9182 else
9183 LogInfo("nodePresence: inet_ntop() error");
9184
9185 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
9186 // all zeroes when a node is present and has no services registered.
9187 if (allZeroSSTH(op))
9188 {
9189 mDNSAddr peerAddr;
9190
9191 peerAddr.type = mDNSAddrType_IPv6;
9192 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
9193
9194 LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
9195 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, false);
9196 }
9197 }
9198
9199 // Handle KEV_DL_NODE_ABSENCE event.
9200 mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
9201 {
9202 mDNSAddr peerAddr;
9203 char buf[INET6_ADDRSTRLEN];
9204
9205 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
9206 LogInfo("nodeAbsence: IPv6 address: %s", buf);
9207 else
9208 LogInfo("nodeAbsence: inet_ntop() error");
9209
9210 peerAddr.type = mDNSAddrType_IPv6;
9211 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
9212
9213 LogInfo("nodeAbsence: immediately purge cached records from this peer");
9214 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, true);
9215 }
9216
9217 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
9218 {
9219 mDNS *const m = (mDNS *const)context;
9220
9221 mDNS_Lock(m);
9222
9223 struct { struct kern_event_msg k; char extra[256]; } msg;
9224 int bytes = recv(s1, &msg, sizeof(msg), 0);
9225 if (bytes < 0)
9226 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
9227 else
9228 {
9229 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
9230 bytes, msg.k.total_size,
9231 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
9232 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
9233 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
9234 msg.k.id, msg.k.event_code,
9235 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
9236 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
9237 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
9238 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
9239 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
9240 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
9241 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
9242 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
9243 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
9244 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
9245 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
9246 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
9247 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
9248 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
9249 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
9250 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
9251 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
9252 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
9253 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
9254 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
9255 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
9256 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
9257 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
9258 "?");
9259
9260 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
9261 nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
9262
9263 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
9264 nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
9265
9266 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
9267 newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
9268
9269 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
9270 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
9271 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
9272 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
9273 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
9274
9275 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
9276 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
9277
9278 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
9279
9280 // For p2p interfaces, need to open the advertised service port in the firewall.
9281 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
9282 {
9283 struct net_event_data * p;
9284 p = (struct net_event_data *) &msg.k.event_data;
9285
9286 if (strncmp(p->if_name, "p2p", 3) == 0)
9287 {
9288 char ifname[IFNAMSIZ];
9289 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
9290
9291 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
9292
9293 mDNSSetPacketFilterRules(m, ifname, NULL);
9294 }
9295 }
9296
9297 // For p2p interfaces, need to clear the firewall rules on interface detach
9298 if (msg.k.event_code == KEV_DL_IF_DETACHED)
9299 {
9300 struct net_event_data * p;
9301 p = (struct net_event_data *) &msg.k.event_data;
9302
9303 if (strncmp(p->if_name, "p2p", 3) == 0)
9304 {
9305 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
9306 char ifname[IFNAMSIZ];
9307 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
9308
9309 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
9310
9311 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
9312 }
9313 }
9314 #endif // !TARGET_OS_EMBEDDED
9315
9316 }
9317
9318 mDNS_Unlock(m);
9319 }
9320
9321 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
9322 {
9323 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
9324 if (m->p->SysEventNotifier < 0)
9325 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
9326
9327 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
9328 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
9329 if (err < 0)
9330 {
9331 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
9332 close(m->p->SysEventNotifier);
9333 m->p->SysEventNotifier = -1;
9334 return(mStatus_UnknownErr);
9335 }
9336
9337 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
9338 m->p->SysEventKQueue.KQcontext = m;
9339 m->p->SysEventKQueue.KQtask = "System Event Notifier";
9340 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
9341
9342 return(mStatus_NoError);
9343 }
9344
9345 #ifndef NO_SECURITYFRAMEWORK
9346 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
9347 {
9348 LogInfo("*** Keychain Changed ***");
9349 mDNS *const m = (mDNS *const)context;
9350 SecKeychainRef skc;
9351 OSStatus err = SecKeychainCopyDefault(&skc);
9352 if (!err)
9353 {
9354 if (info->keychain == skc)
9355 {
9356 // 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
9357 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
9358 if (!relevant)
9359 {
9360 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
9361 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
9362 SecKeychainAttributeList *a = NULL;
9363 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
9364 if (!err)
9365 {
9366 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
9367 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
9368 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
9369 SecKeychainItemFreeAttributesAndData(a, NULL);
9370 }
9371 }
9372 if (relevant)
9373 {
9374 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
9375 keychainEvent,
9376 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
9377 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
9378 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
9379 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
9380 KQueueLock(m);
9381 mDNS_Lock(m);
9382
9383 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
9384 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
9385 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
9386 //
9387 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
9388 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
9389 // a one second delay is ok, as we'll still converge to correctness, and there's no race
9390 // condition between the RegistrationDomain and the DomainAuthInfo.
9391 //
9392 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
9393 // the timer here, as it will not get set by NetworkChanged().
9394 SetKeyChainTimer(m, mDNSPlatformOneSecond);
9395
9396 mDNS_Unlock(m);
9397 KQueueUnlock(m, "KeychainChanged");
9398 }
9399 }
9400 CFRelease(skc);
9401 }
9402
9403 return 0;
9404 }
9405 #endif
9406
9407 mDNSlocal void PowerOn(mDNS *const m)
9408 {
9409 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
9410
9411 if (m->p->WakeAtUTC)
9412 {
9413 long utc = mDNSPlatformUTC();
9414 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
9415 if (m->p->WakeAtUTC - utc > 30)
9416 {
9417 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
9418 }
9419 else if (utc - m->p->WakeAtUTC > 30)
9420 {
9421 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
9422 }
9423 else if (IsAppleTV())
9424 {
9425 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
9426 }
9427 else
9428 {
9429 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
9430 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
9431 }
9432 }
9433
9434 // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
9435 // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
9436 // We will clear this assertion as soon as we think the mainenance activities are done.
9437 mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance");
9438
9439 }
9440
9441 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
9442 {
9443 mDNS *const m = (mDNS *const)refcon;
9444 KQueueLock(m);
9445 (void)service; // Parameter not used
9446 debugf("PowerChanged %X %lX", messageType, messageArgument);
9447
9448 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
9449 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9450
9451 switch(messageType)
9452 {
9453 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
9454 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
9455 mDNSCoreMachineSleep(m, true);
9456 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
9457 break;
9458 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
9459 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
9460 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
9461 mDNSCoreMachineSleep(m, true);
9462 break;
9463 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
9464 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
9465 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
9466 if (m->SleepState)
9467 {
9468 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
9469 PowerOn(m);
9470 }
9471 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
9472 // the System Configuration Framework "network changed" event that we expect
9473 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
9474 mDNS_Lock(m);
9475 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
9476 mDNS_Unlock(m);
9477
9478 break;
9479 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
9480 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
9481
9482 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
9483 if (m->SleepState != SleepState_Sleeping)
9484 {
9485 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
9486 m->SleepState = SleepState_Sleeping;
9487 mDNSMacOSXNetworkChanged(m);
9488 }
9489 PowerOn(m);
9490 break;
9491 default: LogSPS("PowerChanged unknown message %X", messageType); break;
9492 }
9493
9494 if ((messageType == kIOMessageSystemWillSleep) || (messageType== kIOMessageCanSystemSleep))
9495 {
9496 m->p->SleepCookie = (long)messageArgument;
9497 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
9498 }
9499
9500 KQueueUnlock(m, "PowerChanged Sleep/Wake");
9501 }
9502
9503 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
9504 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9505 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
9506 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
9507 {
9508 mDNS *const m = (mDNS *const)refcon;
9509 KQueueLock(m);
9510 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
9511 connection, token, eventDescriptor,
9512 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
9513 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
9514 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
9515 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
9516 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
9517
9518 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
9519 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9520
9521 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
9522 {
9523 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
9524 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
9525 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
9526 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
9527 if (m->SleepLimit)
9528 {
9529 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
9530 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
9531 m->SleepLimit = 0;
9532 }
9533 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
9534 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
9535 if (m->SleepState != SleepState_Awake)
9536 {
9537 PowerOn(m);
9538 // If the network notifications have already come before we got the wakeup, we ignored them and
9539 // in case we get no more, we need to trigger one.
9540 mDNS_Lock(m);
9541 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
9542 mDNS_Unlock(m);
9543 }
9544 IOPMConnectionAcknowledgeEvent(connection, token);
9545 }
9546 else
9547 {
9548 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
9549 // we should hear nothing more until we're told that the CPU has started executing again.
9550 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
9551 //sleep(5);
9552 //mDNSMacOSXNetworkChanged(m);
9553 mDNSCoreMachineSleep(m, true);
9554 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
9555 m->p->SleepCookie = token;
9556 }
9557
9558 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
9559 }
9560 #endif
9561
9562 #if COMPILER_LIKES_PRAGMA_MARK
9563 #pragma mark -
9564 #pragma mark - /etc/hosts support
9565 #endif
9566
9567 // Implementation Notes
9568 //
9569 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
9570 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
9571 // them into a hash table. The implementation need to be able to do the following things efficiently
9572 //
9573 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
9574 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
9575 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
9576 // need to be able set the RRSet of a resource record to the first one in the list and also update when
9577 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
9578 // not a duplicate
9579 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
9580 //
9581 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
9582 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
9583 // of the core layer which does all of the above very efficiently
9584
9585 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
9586
9587 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
9588 {
9589 (void)m; // unused
9590 (void)rr;
9591 (void)result;
9592 if (result == mStatus_MemFree)
9593 {
9594 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
9595 freeL("etchosts", rr);
9596 }
9597 }
9598
9599 // Returns true on success and false on failure
9600 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
9601 {
9602 AuthRecord *rr;
9603 mDNSu32 slot;
9604 mDNSu32 namehash;
9605 AuthGroup *ag;
9606 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
9607 mDNSu16 rrtype;
9608
9609 if (!domain)
9610 {
9611 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
9612 return mDNSfalse;
9613 }
9614 if (!sa && !cname)
9615 {
9616 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
9617 return mDNSfalse;
9618 }
9619
9620 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
9621 {
9622 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
9623 return mDNSfalse;
9624 }
9625
9626
9627 if (ifname)
9628 {
9629 mDNSu32 ifindex = if_nametoindex(ifname);
9630 if (!ifindex)
9631 {
9632 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
9633 return mDNSfalse;
9634 }
9635 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
9636 }
9637
9638 if (sa)
9639 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
9640 else
9641 rrtype = kDNSType_CNAME;
9642
9643 // Check for duplicates. See whether we parsed an entry before like this ?
9644 slot = AuthHashSlot(domain);
9645 namehash = DomainNameHashValue(domain);
9646 ag = AuthGroupForName(auth, slot, namehash, domain);
9647 if (ag)
9648 {
9649 rr = ag->members;
9650 while (rr)
9651 {
9652 if (rr->resrec.rrtype == rrtype)
9653 {
9654 if (rrtype == kDNSType_A)
9655 {
9656 mDNSv4Addr ip;
9657 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
9658 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
9659 {
9660 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
9661 return mDNSfalse;
9662 }
9663 }
9664 else if (rrtype == kDNSType_AAAA)
9665 {
9666 mDNSv6Addr ip6;
9667 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
9668 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
9669 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
9670 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
9671 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
9672 {
9673 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
9674 return mDNSfalse;
9675 }
9676 }
9677 else if (rrtype == kDNSType_CNAME)
9678 {
9679 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
9680 {
9681 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
9682 return mDNSfalse;
9683 }
9684 }
9685 }
9686 rr = rr->next;
9687 }
9688 }
9689 rr= mallocL("etchosts", sizeof(*rr));
9690 if (rr == NULL) return mDNSfalse;
9691 mDNSPlatformMemZero(rr, sizeof(*rr));
9692 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
9693 AssignDomainName(&rr->namestorage, domain);
9694
9695 if (sa)
9696 {
9697 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
9698 if (sa->sa_family == AF_INET)
9699 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
9700 else
9701 {
9702 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
9703 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
9704 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
9705 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
9706 }
9707 }
9708 else
9709 {
9710 rr->resrec.rdlength = DomainNameLength(cname);
9711 rr->resrec.rdata->u.name.c[0] = 0;
9712 AssignDomainName(&rr->resrec.rdata->u.name, cname);
9713 }
9714 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9715 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9716 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
9717 InsertAuthRecord(m, auth, rr);
9718 return mDNStrue;
9719 }
9720
9721 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
9722 {
9723 int i;
9724
9725 *name = NULL;
9726 for (i = start; i < length; i++)
9727 {
9728 if (buffer[i] == '#')
9729 return -1;
9730 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
9731 {
9732 *name = &buffer[i];
9733
9734 // Found the start of a name, find the end and null terminate
9735 for (i++; i < length; i++)
9736 {
9737 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9738 {
9739 buffer[i] = 0;
9740 break;
9741 }
9742 }
9743 return i;
9744 }
9745 }
9746 return -1;
9747 }
9748
9749 mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
9750 {
9751 int i;
9752 int ifStart = 0;
9753 char *ifname = NULL;
9754 domainname name1d;
9755 domainname name2d;
9756 char *name1;
9757 char *name2;
9758 int aliasIndex;
9759
9760 //Ignore leading whitespaces and tabs
9761 while (*buffer == ' ' || *buffer == '\t')
9762 {
9763 buffer++;
9764 length--;
9765 }
9766
9767 // Find the end of the address string
9768 for (i = 0; i < length; i++)
9769 {
9770 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
9771 {
9772 if (buffer[i] == '%')
9773 ifStart = i + 1;
9774 buffer[i] = 0;
9775 break;
9776 }
9777 }
9778
9779 // Convert the address string to an address
9780 struct addrinfo hints;
9781 bzero(&hints, sizeof(hints));
9782 hints.ai_flags = AI_NUMERICHOST;
9783 struct addrinfo *gairesults = NULL;
9784 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
9785 {
9786 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
9787 return;
9788 }
9789
9790 if (ifStart)
9791 {
9792 // Parse the interface
9793 ifname = &buffer[ifStart];
9794 for (i = ifStart + 1; i < length; i++)
9795 {
9796 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9797 {
9798 buffer[i] = 0;
9799 break;
9800 }
9801 }
9802 }
9803
9804 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
9805 if (i == length)
9806 {
9807 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
9808 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
9809 {
9810 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9811 freeaddrinfo(gairesults);
9812 return;
9813 }
9814 mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
9815 }
9816 else if (i != -1)
9817 {
9818 domainname first;
9819 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
9820 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
9821 // doing the right thing.
9822
9823 if (!MakeDomainNameFromDNSNameString(&first, name1))
9824 {
9825 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9826 freeaddrinfo(gairesults);
9827 return;
9828 }
9829 mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
9830
9831 // /etc/hosts alias discussion:
9832 //
9833 // If the /etc/hosts has an entry like this
9834 //
9835 // ip_address cname [aliases...]
9836 // 1.2.3.4 sun star bright
9837 //
9838 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
9839 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
9840 //
9841 // To achieve this, we need to add the entry like this:
9842 //
9843 // sun A 1.2.3.4
9844 // star CNAME sun
9845 // bright CNAME sun
9846 //
9847 // We store the first name we parsed in "first" and add the address (A/AAAA) record.
9848 // Then we parse additional names adding CNAME records till we reach the end.
9849
9850 aliasIndex = 0;
9851 while (i < length)
9852 {
9853 // Continue to parse additional aliases until we reach end of the line and
9854 // for each "alias" parsed, add a CNAME record where "alias" points to the first "name".
9855 // See also /etc/hosts alias discussion above
9856
9857 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
9858
9859 if (name2)
9860 {
9861 if ((aliasIndex) && (*buffer == *name2))
9862 break; // break out of the loop if we wrap around
9863
9864 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
9865 {
9866 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
9867 freeaddrinfo(gairesults);
9868 return;
9869 }
9870 // Ignore if it points to itself
9871 if (!SameDomainName(&first, &name2d))
9872 {
9873 if (!mDNSMacOSXCreateEtcHostsEntry(m, &name2d, mDNSNULL, &first, ifname, auth))
9874 {
9875 freeaddrinfo(gairesults);
9876 return;
9877 }
9878 }
9879 else
9880 {
9881 LogInfo("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names first %##s, name2 %##s", first.c, name2d.c);
9882 }
9883 aliasIndex++;
9884 }
9885 else if (!aliasIndex)
9886 {
9887 // We have never parsed any aliases. This case happens if there
9888 // is just one name and some extra white spaces at the end.
9889 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
9890 break;
9891 }
9892 }
9893 }
9894 freeaddrinfo(gairesults);
9895 }
9896
9897 mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
9898 {
9899 mDNSBool good;
9900 char buf[ETCHOSTS_BUFSIZE];
9901 ssize_t len;
9902 FILE *fp;
9903
9904 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
9905
9906 fp = fopen("/etc/hosts", "r");
9907 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
9908
9909 while (1)
9910 {
9911 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
9912 if (!good) break;
9913
9914 // skip comment and empty lines
9915 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
9916 continue;
9917
9918 len = strlen(buf);
9919 if (!len) break; // sanity check
9920 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
9921 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9922 {
9923 buf[len - 1] = '\0';
9924 len = len - 1;
9925 }
9926 // fgets always null terminates and hence even if we have no
9927 // newline at the end, it is null terminated. The callee
9928 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
9929 // buf[length] is zero and hence we decrement len to reflect that.
9930 if (len)
9931 {
9932 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
9933 //here we need to check for just \r but taking extra caution.
9934 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9935 {
9936 buf[len - 1] = '\0';
9937 len = len - 1;
9938 }
9939 }
9940 if (!len) //Sanity Check: len should never be zero
9941 {
9942 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
9943 continue;
9944 }
9945 mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
9946 }
9947 fclose(fp);
9948 }
9949
9950 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
9951
9952 mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
9953 {
9954 #ifdef __DISPATCH_GROUP__
9955 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9956 static dispatch_queue_t etcq = 0;
9957 static dispatch_source_t etcsrc = 0;
9958 static dispatch_source_t hostssrc = 0;
9959
9960 // First time through? just schedule ourselves on the main queue and we'll do the work later
9961 if (!etcq)
9962 {
9963 etcq = dispatch_get_main_queue();
9964 if (etcq)
9965 {
9966 // Do this work on the queue, not here - solves potential synchronization issues
9967 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9968 }
9969 return -1;
9970 }
9971
9972 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9973 #endif
9974
9975 int fd = open("/etc/hosts", O_RDONLY);
9976
9977 #ifdef __DISPATCH_GROUP__
9978 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9979 if (fd == -1)
9980 {
9981 // If the open failed and we're already watching /etc, we're done
9982 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9983
9984 // we aren't watching /etc, we should be
9985 fd = open("/etc", O_RDONLY);
9986 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9987 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9988 if (etcsrc == NULL)
9989 {
9990 close(fd);
9991 return -1;
9992 }
9993 dispatch_source_set_event_handler(etcsrc,
9994 ^{
9995 u_int32_t flags = dispatch_source_get_data(etcsrc);
9996 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9997 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9998 {
9999 dispatch_source_cancel(etcsrc);
10000 dispatch_release(etcsrc);
10001 etcsrc = NULL;
10002 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
10003 return;
10004 }
10005 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
10006 {
10007 mDNSMacOSXUpdateEtcHosts(m);
10008 }
10009 });
10010 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
10011 dispatch_resume(etcsrc);
10012
10013 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
10014 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
10015 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
10016 }
10017
10018 // create a dispatch source to watch for changes to hosts file
10019 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
10020 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
10021 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
10022 if (hostssrc == NULL)
10023 {
10024 close(fd);
10025 return -1;
10026 }
10027 dispatch_source_set_event_handler(hostssrc,
10028 ^{
10029 u_int32_t flags = dispatch_source_get_data(hostssrc);
10030 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
10031 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
10032 {
10033 dispatch_source_cancel(hostssrc);
10034 dispatch_release(hostssrc);
10035 hostssrc = NULL;
10036 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
10037 // the block immediately, we try to open the file and the file may not exist and may
10038 // fail to get a notification in the future. When the file does not exist and
10039 // we start to monitor the directory, on "dispatch_resume" of that source, there
10040 // is no guarantee that the file creation will be notified always because when
10041 // the dispatch_resume returns, the kevent manager may not have registered the
10042 // kevent yet but the file may have been created
10043 usleep(1000000);
10044 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
10045 return;
10046 }
10047 if ((flags & DISPATCH_VNODE_WRITE) != 0)
10048 {
10049 mDNSMacOSXUpdateEtcHosts(m);
10050 }
10051 });
10052 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
10053 dispatch_resume(hostssrc);
10054
10055 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
10056 if (etcsrc)
10057 {
10058 dispatch_source_cancel(etcsrc);
10059 dispatch_release(etcsrc);
10060 etcsrc = NULL;
10061 }
10062
10063 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
10064 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
10065 #else
10066 (void)m;
10067 return fd;
10068 #endif
10069 }
10070
10071 // When /etc/hosts is modified, flush all the cache records as there may be local
10072 // authoritative answers now
10073 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
10074 {
10075 CacheRecord *cr;
10076 mDNSu32 slot;
10077 CacheGroup *cg;
10078
10079 FORALL_CACHERECORDS(slot, cg, cr)
10080 {
10081 // Skip multicast.
10082 if (cr->resrec.InterfaceID) continue;
10083
10084 // If a resource record can answer A or AAAA, they need to be flushed so that we will
10085 // never used to deliver an ADD or RMV
10086 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
10087 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
10088 {
10089 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
10090 mDNS_PurgeCacheResourceRecord(m, cr);
10091 }
10092 }
10093 }
10094
10095 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
10096 mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
10097 {
10098 AuthGroup *ag;
10099 mDNSu32 slot;
10100 AuthRecord *rr, *primary, *rrnext;
10101 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
10102 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
10103 {
10104 primary = NULL;
10105 for (rr = ag->members; rr; rr = rrnext)
10106 {
10107 rrnext = rr->next;
10108 AuthGroup *ag1;
10109 AuthRecord *rr1;
10110 mDNSBool found = mDNSfalse;
10111 ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
10112 if (ag1 && ag1->members)
10113 {
10114 if (!primary) primary = ag1->members;
10115 rr1 = ag1->members;
10116 while (rr1)
10117 {
10118 // We are not using InterfaceID in checking for duplicates. This means,
10119 // if there are two addresses for a given name e.g., fe80::1%en0 and
10120 // fe80::1%en1, we only add the first one. It is not clear whether
10121 // this is a common case. To fix this, we also need to modify
10122 // mDNS_Register_internal in how it handles duplicates. If it becomes a
10123 // common case, we will fix it then.
10124 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
10125 {
10126 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
10127 found = mDNStrue;
10128 break;
10129 }
10130 rr1 = rr1->next;
10131 }
10132 }
10133 if (!found)
10134 {
10135 if (justCheck)
10136 {
10137 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
10138 return mDNStrue;
10139 }
10140 RemoveAuthRecord(m, newhosts, rr);
10141 // if there is no primary, point to self
10142 rr->RRSet = (primary ? primary : rr);
10143 rr->next = NULL;
10144 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
10145 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
10146 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
10147 }
10148 }
10149 }
10150 return mDNSfalse;
10151 }
10152
10153 // Delete entries from the core that are no longer needed. If justCheck is set, this function
10154 // does not delete, just returns true
10155 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
10156 {
10157 AuthGroup *ag;
10158 mDNSu32 slot;
10159 AuthRecord *rr, *rrnext;
10160 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
10161 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
10162 for (rr = ag->members; rr; rr = rrnext)
10163 {
10164 mDNSBool found = mDNSfalse;
10165 AuthGroup *ag1;
10166 AuthRecord *rr1;
10167 rrnext = rr->next;
10168 if (rr->RecordCallback != FreeEtcHosts) continue;
10169 ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
10170 if (ag1)
10171 {
10172 rr1 = ag1->members;
10173 while (rr1)
10174 {
10175 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
10176 {
10177 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
10178 found = mDNStrue;
10179 break;
10180 }
10181 rr1 = rr1->next;
10182 }
10183 }
10184 // there is no corresponding record in newhosts for the same name. This means
10185 // we should delete this from the core.
10186 if (!found)
10187 {
10188 if (justCheck)
10189 {
10190 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
10191 return mDNStrue;
10192 }
10193 // if primary is going away, make sure that the rest of the records
10194 // point to the new primary
10195 if (rr == ag->members)
10196 {
10197 AuthRecord *new_primary = rr->next;
10198 AuthRecord *r = new_primary;
10199 while (r)
10200 {
10201 if (r->RRSet == rr)
10202 {
10203 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
10204 r->RRSet = new_primary;
10205 }
10206 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
10207 r = r->next;
10208 }
10209 }
10210 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
10211 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
10212 }
10213 }
10214 return mDNSfalse;
10215 }
10216
10217 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
10218 {
10219 AuthHash *newhosts = (AuthHash *)context;
10220
10221 mDNS_CheckLock(m);
10222
10223 //Delete old entries from the core if they are not present in the newhosts
10224 EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
10225 // Add the new entries to the core if not already present in the core
10226 EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
10227 }
10228
10229 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
10230 {
10231 mDNSu32 slot;
10232 AuthGroup *ag, *agnext;
10233 AuthRecord *rr, *rrnext;
10234
10235 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
10236 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
10237 {
10238 agnext = ag->next;
10239 for (rr = ag->members; rr; rr = rrnext)
10240 {
10241 rrnext = rr->next;
10242 freeL("etchosts", rr);
10243 }
10244 freeL("AuthGroups", ag);
10245 }
10246 }
10247
10248 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
10249 {
10250 AuthHash newhosts;
10251
10252 // As we will be modifying the core, we can only have one thread running at
10253 // any point in time.
10254 KQueueLock(m);
10255
10256 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
10257
10258 // Get the file desecriptor (will trigger us to start watching for changes)
10259 int fd = mDNSMacOSXGetEtcHostsFD(m);
10260 if (fd != -1)
10261 {
10262 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
10263 mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
10264 }
10265 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
10266
10267 // Optimization: Detect whether /etc/hosts changed or not.
10268 //
10269 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
10270 // newhosts is already registered with core. If we find at least one entry that is not
10271 // registered with core, then it means we have work to do.
10272 //
10273 // 2. Next, we check to see if any of the entries that are registered with core is not present
10274 // in newhosts. If we find at least one entry that is not present, it means we have work to
10275 // do.
10276 //
10277 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
10278 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
10279 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
10280 // in the future and this code does not have to change.
10281 mDNS_Lock(m);
10282 // Add the new entries to the core if not already present in the core
10283 if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
10284 {
10285 // No new entries to add, check to see if we need to delete any old entries from the
10286 // core if they are not present in the newhosts
10287 if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
10288 {
10289 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
10290 FreeNewHosts(&newhosts);
10291 mDNS_Unlock(m);
10292 KQueueUnlock(m, "/etc/hosts changed");
10293 return;
10294 }
10295 }
10296
10297 // This will flush the cache, stop and start the query so that the queries
10298 // can look at the /etc/hosts again
10299 //
10300 // Notes:
10301 //
10302 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
10303 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
10304 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
10305 // delivers these events in the right order and then calls us back to delete them.
10306 //
10307 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
10308 // is a common function that looks at all local auth records and delivers a RMV including
10309 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
10310 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
10311 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
10312 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
10313 // looks normal.
10314 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
10315 FreeNewHosts(&newhosts);
10316 mDNS_Unlock(m);
10317 KQueueUnlock(m, "/etc/hosts changed");
10318 }
10319
10320 #if COMPILER_LIKES_PRAGMA_MARK
10321 #pragma mark -
10322 #pragma mark - Initialization & Teardown
10323 #endif
10324
10325 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
10326 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
10327 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
10328 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
10329
10330 // Major version 13 is 10.9.x
10331 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
10332 {
10333 int major = 0, minor = 0;
10334 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
10335 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
10336 if (vers)
10337 {
10338 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
10339 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
10340 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
10341 if (cfprodname)
10342 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
10343 if (cfprodvers)
10344 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
10345 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
10346 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
10347 CFRelease(vers);
10348 }
10349 if (!major)
10350 {
10351 major = 13;
10352 LogMsg("Note: No Major Build Version number found; assuming 13");
10353 }
10354 if (HINFO_SWstring)
10355 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
10356 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
10357
10358 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
10359 if ((prodname[0] & 0xDF) == 'M')
10360 OSXVers = major;
10361 else
10362 iOSVers = major;
10363 }
10364
10365 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
10366 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
10367 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
10368 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
10369 {
10370 int err = -1;
10371 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
10372 if (s < 3)
10373 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
10374 else
10375 {
10376 struct sockaddr_in s5353;
10377 s5353.sin_family = AF_INET;
10378 s5353.sin_port = MulticastDNSPort.NotAnInteger;
10379 s5353.sin_addr.s_addr = 0;
10380 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
10381 close(s);
10382 }
10383
10384 if (err) LogMsg("No unicast UDP responses");
10385 else debugf("Unicast UDP responses okay");
10386 return(err == 0);
10387 }
10388
10389 mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
10390 {
10391 AuthRecord *rr;
10392 const domainname *pname = (domainname *)"\x9" "localhost";
10393
10394 rr= mallocL("localhosts", sizeof(*rr));
10395 if (rr == NULL) return;
10396 mDNSPlatformMemZero(rr, sizeof(*rr));
10397
10398 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
10399 AssignDomainName(&rr->namestorage, domain);
10400
10401 rr->resrec.rdlength = DomainNameLength(pname);
10402 rr->resrec.rdata->u.name.c[0] = 0;
10403 AssignDomainName(&rr->resrec.rdata->u.name, pname);
10404
10405 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
10406 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
10407 mDNS_Register(m, rr);
10408 }
10409
10410 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
10411 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
10412 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
10413 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
10414 //
10415 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
10416 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
10417 mDNSlocal void SetupLocalHostRecords(mDNS *const m)
10418 {
10419 char buffer[MAX_REVERSE_MAPPING_NAME];
10420 domainname name;
10421 int i;
10422 struct in6_addr addr;
10423 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
10424
10425 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
10426 {
10427 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
10428 ptr[3], ptr[2], ptr[1], ptr[0]);
10429 MakeDomainNameFromDNSNameString(&name, buffer);
10430 CreatePTRRecord(m, &name);
10431 }
10432 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
10433
10434 if (inet_pton(AF_INET6, "::1", &addr) == 1)
10435 {
10436 for (i = 0; i < 16; i++)
10437 {
10438 static const char hexValues[] = "0123456789ABCDEF";
10439 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
10440 buffer[i * 4 + 1] = '.';
10441 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
10442 buffer[i * 4 + 3] = '.';
10443 }
10444 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
10445 MakeDomainNameFromDNSNameString(&name, buffer);
10446 CreatePTRRecord(m, &name);
10447 }
10448 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
10449 }
10450
10451 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
10452 // 1) query for b._dns-sd._udp.local on LocalOnly interface
10453 // (.local manually generated via explicit callback)
10454 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
10455 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
10456 // 4) result above should generate a callback from question in (1). result added to global list
10457 // 5) global list delivered to client via GetSearchDomainList()
10458 // 6) client calls to enumerate domains now go over LocalOnly interface
10459 // (!!!KRS may add outgoing interface in addition)
10460
10461 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
10462 {
10463 mStatus err;
10464
10465 char HINFO_SWstring[256] = "";
10466 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
10467
10468 err = mDNSHelperInit();
10469 if (err)
10470 return err;
10471
10472 // Store mDNSResponder Platform
10473 if (OSXVers)
10474 {
10475 m->mDNS_plat = platform_OSX;
10476 }
10477 else if (iOSVers)
10478 {
10479 if (IsAppleTV())
10480 m->mDNS_plat = platform_Atv;
10481 else
10482 m->mDNS_plat = platform_iOS;
10483 }
10484 else
10485 {
10486 m->mDNS_plat = platform_NonApple;
10487 }
10488
10489 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
10490 // 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.
10491 int i;
10492 for (i=0; i<100; i++)
10493 {
10494 domainlabel testlabel;
10495 testlabel.c[0] = 0;
10496 GetUserSpecifiedLocalHostName(&testlabel);
10497 if (testlabel.c[0]) break;
10498 usleep(50000);
10499 }
10500
10501 m->hostlabel.c[0] = 0;
10502
10503 int get_model[2] = { CTL_HW, HW_MODEL };
10504 size_t len_model = sizeof(HINFO_HWstring_buffer);
10505
10506 // Normal Apple model names are of the form "iPhone2,1", and
10507 // internal code names are strings containing no commas, e.g. "N88AP".
10508 // We used to ignore internal code names, but Apple now uses these internal code names
10509 // even in released shipping products, so we no longer ignore strings containing no commas.
10510 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
10511 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
10512 HINFO_HWstring = HINFO_HWstring_buffer;
10513
10514 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
10515 // For names of the form "N88AP" containg no comma, we use the entire string.
10516 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
10517
10518 if (mDNSPlatformInit_CanReceiveUnicast())
10519 m->CanReceiveUnicastOn5353 = mDNStrue;
10520
10521 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
10522 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
10523 if (hlen + slen < 254)
10524 {
10525 m->HIHardware.c[0] = hlen;
10526 m->HISoftware.c[0] = slen;
10527 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
10528 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
10529 }
10530
10531 m->p->permanentsockets.port = MulticastDNSPort;
10532 m->p->permanentsockets.m = m;
10533 m->p->permanentsockets.sktv4 = -1;
10534 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
10535 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
10536 m->p->permanentsockets.kqsv4.KQtask = "IPv4 UDP packet reception";
10537 m->p->permanentsockets.sktv6 = -1;
10538 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
10539 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
10540 m->p->permanentsockets.kqsv6.KQtask = "IPv6 UDP packet reception";
10541
10542 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
10543 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET) failed error %d errno %d (%s)", err, errno, strerror(errno));
10544 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
10545 if (err) LogMsg("mDNSPlatformInit_setup: SetupSocket(AF_INET6) failed error %d errno %d (%s)", err, errno, strerror(errno));
10546
10547 struct sockaddr_in s4;
10548 socklen_t n4 = sizeof(s4);
10549 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
10550 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
10551 else
10552 m->UnicastPort4.NotAnInteger = s4.sin_port;
10553
10554 if (m->p->permanentsockets.sktv6 >= 0)
10555 {
10556 struct sockaddr_in6 s6;
10557 socklen_t n6 = sizeof(s6);
10558 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
10559 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
10560 }
10561
10562 m->p->InterfaceList = mDNSNULL;
10563 m->p->userhostlabel.c[0] = 0;
10564 m->p->usernicelabel.c[0] = 0;
10565 m->p->prevoldnicelabel.c[0] = 0;
10566 m->p->prevnewnicelabel.c[0] = 0;
10567 m->p->prevoldhostlabel.c[0] = 0;
10568 m->p->prevnewhostlabel.c[0] = 0;
10569 m->p->NotifyUser = 0;
10570 m->p->KeyChainTimer = 0;
10571 m->p->WakeAtUTC = 0;
10572 m->p->RequestReSleep = 0;
10573 // Assume that everything is good to begin with. If something is not working,
10574 // we will detect that when we start sending questions.
10575 m->p->v4answers = 1;
10576 m->p->v6answers = 1;
10577 m->p->DNSTrigger = 0;
10578 m->p->LastConfigGeneration = 0;
10579
10580 #if APPLE_OSX_mDNSResponder
10581 uuid_generate(m->asl_uuid);
10582 #endif
10583
10584 m->AutoTunnelRelayAddr = zerov6Addr;
10585
10586 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
10587 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
10588 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
10589 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
10590 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
10591 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
10592 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
10593 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
10594
10595 err = WatchForNetworkChanges(m);
10596 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
10597
10598 err = WatchForSysEvents(m);
10599 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
10600
10601 mDNSs32 utc = mDNSPlatformUTC();
10602 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
10603 myGetIfAddrs(1);
10604 UpdateInterfaceList(m, utc);
10605 SetupActiveInterfaces(m, utc);
10606
10607 // Explicitly ensure that our Keychain operations utilize the system domain.
10608 #ifndef NO_SECURITYFRAMEWORK
10609 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
10610 #endif
10611
10612 mDNS_Lock(m);
10613 SetDomainSecrets(m);
10614 SetLocalDomains();
10615 mDNS_Unlock(m);
10616
10617 #ifndef NO_SECURITYFRAMEWORK
10618 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
10619 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
10620 #endif
10621
10622 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
10623 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
10624 #else
10625 IOPMConnection c;
10626 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
10627 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
10628 else
10629 {
10630 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
10631 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
10632 else
10633 {
10634 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10635 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
10636 LogInfo("IOPMConnectionSetDispatchQueue is now running");
10637 #else
10638 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
10639 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
10640 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
10641 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10642 }
10643 }
10644 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
10645 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
10646 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
10647 {
10648 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
10649 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
10650 else
10651 {
10652 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10653 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
10654 #else
10655 CFRunLoopAddSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10656 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
10657 }
10658 }
10659
10660 #if APPLE_OSX_mDNSResponder
10661 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
10662 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
10663 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
10664 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
10665 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10666 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10667 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
10668 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
10669 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
10670 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
10671 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
10672 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
10673 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
10674 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10675 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
10676 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
10677 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
10678 #endif // APPLE_OSX_mDNSResponder
10679
10680 // Currently this is not defined. SSL code will eventually fix this. If it becomes
10681 // critical, we will define this to workaround the bug in SSL.
10682 #ifdef __SSL_NEEDS_SERIALIZATION__
10683 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
10684 #else
10685 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
10686 #endif
10687 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
10688
10689 mDNSMacOSXUpdateEtcHosts(m);
10690 SetupLocalHostRecords(m);
10691
10692 return(mStatus_NoError);
10693 }
10694
10695 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
10696 {
10697 #if MDNS_NO_DNSINFO
10698 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
10699 #endif
10700
10701 // Adding interfaces will use this flag, so set it now.
10702 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
10703
10704 #if APPLE_OSX_mDNSResponder
10705 m->SPSBrowseCallback = UpdateSPSStatus;
10706 #endif // APPLE_OSX_mDNSResponder
10707
10708 mStatus result = mDNSPlatformInit_setup(m);
10709
10710 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
10711 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
10712 if (result == mStatus_NoError)
10713 {
10714 mDNSCoreInitComplete(m, mStatus_NoError);
10715
10716 #if !NO_D2D
10717 // We only initialize if mDNSCore successfully initialized.
10718 if (D2DInitialize)
10719 {
10720 D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m) ;
10721 if (ds != kD2DSuccess)
10722 LogMsg("D2DInitialiize failed: %d", ds);
10723 else
10724 LogMsg("D2DInitialize succeeded");
10725 }
10726 #endif // ! NO_D2D
10727
10728 }
10729 result = DNSSECCryptoInit(m);
10730 return(result);
10731 }
10732
10733 mDNSexport void mDNSPlatformClose(mDNS *const m)
10734 {
10735 if (m->p->PowerConnection)
10736 {
10737 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10738 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
10739 #else
10740 CFRunLoopRemoveSource(CFRunLoopGetMain(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10741 #endif
10742 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
10743 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
10744 IODeregisterForSystemPower(&m->p->PowerNotifier);
10745 IOServiceClose ( m->p->PowerConnection);
10746 IONotificationPortDestroy ( m->p->PowerPortRef);
10747 m->p->PowerConnection = 0;
10748 }
10749
10750 if (m->p->Store)
10751 {
10752 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10753 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
10754 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
10755 #else
10756 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->StoreRLS, kCFRunLoopDefaultMode);
10757 CFRunLoopSourceInvalidate(m->p->StoreRLS);
10758 CFRelease(m->p->StoreRLS);
10759 m->p->StoreRLS = NULL;
10760 #endif
10761 CFRelease(m->p->Store);
10762 m->p->Store = NULL;
10763 }
10764
10765 if (m->p->PMRLS)
10766 {
10767 CFRunLoopRemoveSource(CFRunLoopGetMain(), m->p->PMRLS, kCFRunLoopDefaultMode);
10768 CFRunLoopSourceInvalidate(m->p->PMRLS);
10769 CFRelease(m->p->PMRLS);
10770 m->p->PMRLS = NULL;
10771 }
10772
10773 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
10774
10775 #if !NO_D2D
10776 if (D2DTerminate)
10777 {
10778 D2DStatus ds = D2DTerminate();
10779 if (ds != kD2DSuccess)
10780 LogMsg("D2DTerminate failed: %d", ds);
10781 else
10782 LogMsg("D2DTerminate succeeded");
10783 }
10784 #endif // ! NO_D2D
10785
10786 mDNSs32 utc = mDNSPlatformUTC();
10787 MarkAllInterfacesInactive(m, utc);
10788 ClearInactiveInterfaces(m, utc);
10789 CloseSocketSet(&m->p->permanentsockets);
10790
10791 #if APPLE_OSX_mDNSResponder
10792 // clean up tunnels
10793 while (m->TunnelClients)
10794 {
10795 ClientTunnel *cur = m->TunnelClients;
10796 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
10797 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
10798 AutoTunnelSetKeys(cur, mDNSfalse);
10799 m->TunnelClients = cur->next;
10800 freeL("ClientTunnel", cur);
10801 }
10802
10803 if (AnonymousRacoonConfig)
10804 {
10805 AnonymousRacoonConfig = mDNSNULL;
10806 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
10807 }
10808 #endif // APPLE_OSX_mDNSResponder
10809 }
10810
10811 #if COMPILER_LIKES_PRAGMA_MARK
10812 #pragma mark -
10813 #pragma mark - General Platform Support Layer functions
10814 #endif
10815
10816 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
10817 {
10818 return(arc4random());
10819 }
10820
10821 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
10822 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
10823
10824 mDNSexport mStatus mDNSPlatformTimeInit(void)
10825 {
10826 // Notes: Typical values for mach_timebase_info:
10827 // tbi.numer = 1000 million
10828 // tbi.denom = 33 million
10829 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
10830 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
10831 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
10832 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
10833 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
10834 //
10835 // Arithmetic notes:
10836 // tbi.denom is at least 1, and not more than 2^32-1.
10837 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
10838 // tbi.denom is at least 1, and not more than 2^32-1.
10839 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
10840 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
10841 // which is unlikely on any current or future Macintosh.
10842 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
10843 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
10844 struct mach_timebase_info tbi;
10845 kern_return_t result = mach_timebase_info(&tbi);
10846 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
10847 return(result);
10848 }
10849
10850 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
10851 {
10852 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
10853
10854 static uint64_t last_mach_absolute_time = 0;
10855 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
10856 uint64_t this_mach_absolute_time = mach_absolute_time();
10857 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
10858 {
10859 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
10860 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
10861 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10862 last_mach_absolute_time = this_mach_absolute_time;
10863 // Note: This bug happens all the time on 10.3
10864 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10865 "This error occurs from time to time, often on newly released hardware, "
10866 "and usually the exact cause is different in each instance.\r\r"
10867 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10868 "and assign it to Radar Component “Kernel” Version “X”.");
10869 }
10870 last_mach_absolute_time = this_mach_absolute_time;
10871
10872 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
10873 }
10874
10875 mDNSexport mDNSs32 mDNSPlatformUTC(void)
10876 {
10877 return time(NULL);
10878 }
10879
10880 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10881 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
10882 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
10883 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
10884 mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
10885 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
10886 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
10887 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
10888 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
10889 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
10890 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
10891 {
10892 return (qsort(base, nel, width, compar));
10893 }
10894 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10895 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
10896 #endif
10897 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
10898
10899 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
10900 {
10901 if (allowSleep && m->p->IOPMAssertion)
10902 {
10903 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
10904 IOPMAssertionRelease(m->p->IOPMAssertion);
10905 m->p->IOPMAssertion = 0;
10906 }
10907 else if (!allowSleep)
10908 {
10909 #ifdef kIOPMAssertionTypeNoIdleSleep
10910 if (m->p->IOPMAssertion)
10911 {
10912 IOPMAssertionRelease(m->p->IOPMAssertion);
10913 m->p->IOPMAssertion = 0;
10914 }
10915
10916 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10917 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10918 if (assertionName) CFRelease(assertionName);
10919 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10920 #endif
10921 }
10922 }
10923
10924 mDNSexport void mDNSPlatformPreventSleep(mDNS *const m, mDNSu32 timeout, const char *reason)
10925 {
10926 if (m->p->IOPMAssertion)
10927 {
10928 LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
10929 return;
10930 }
10931 #ifdef kIOPMAssertionTypeNoIdleSleep
10932
10933 #if TARGET_OS_EMBEDDED
10934 if (!IsAppleTV())
10935 return; // No need for maintenance wakes on non-AppleTV embedded devices.
10936 #endif
10937
10938 double timeoutVal = (double)timeout;
10939 CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
10940 CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
10941 CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
10942 &kCFTypeDictionaryKeyCallBacks,
10943 &kCFTypeDictionaryValueCallBacks);
10944 if (IsAppleTV())
10945 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
10946 else
10947 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertMaintenanceActivity);
10948
10949 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, Timeout_num);
10950 CFDictionarySetValue(assertionProperties, kIOPMAssertionNameKey, str);
10951
10952 IOPMAssertionCreateWithProperties(assertionProperties, (IOPMAssertionID *)&m->p->IOPMAssertion);
10953 CFRelease(str);
10954 CFRelease(Timeout_num);
10955 CFRelease(assertionProperties);
10956 LogSPS("Got an idle sleep assertion for %d seconds for %s", timeout, reason);
10957 #endif
10958 }
10959
10960 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10961 {
10962 mDNSu32 ifindex;
10963
10964 // Sanity check
10965 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
10966 if (ifindex <= 0)
10967 {
10968 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10969 return;
10970 }
10971 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10972 }
10973
10974 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10975 {
10976 NetworkInterfaceInfoOSX *info;
10977
10978 if (InterfaceID == mDNSInterface_P2P)
10979 return mDNStrue;
10980
10981 // mDNSInterface_BLE not considered a D2D interface for the purpose of this
10982 // routine, since it's not implemented via a D2D plugin.
10983 if (InterfaceID == mDNSInterface_BLE)
10984 return mDNSfalse;
10985
10986 if ( (InterfaceID == mDNSInterface_Any)
10987 || (InterfaceID == mDNSInterfaceMark)
10988 || (InterfaceID == mDNSInterface_LocalOnly)
10989 || (InterfaceID == mDNSInterface_Unicast))
10990 return mDNSfalse;
10991
10992 // Compare to cached AWDL interface ID.
10993 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
10994 return mDNStrue;
10995
10996 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
10997 if (info == NULL)
10998 {
10999 // this log message can print when operations are stopped on an interface that has gone away
11000 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
11001 return mDNSfalse;
11002 }
11003
11004 return (mDNSBool) info->D2DInterface;
11005 }
11006
11007 // Filter records send over P2P (D2D) type interfaces
11008 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
11009 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
11010 {
11011 // For an explicit match to a valid interface ID, return true.
11012 if (rr->resrec.InterfaceID == InterfaceID)
11013 return mDNStrue;
11014
11015 // Only filtering records for D2D type interfaces, return true for all other interface types.
11016 if (!mDNSPlatformInterfaceIsD2D(InterfaceID))
11017 return mDNStrue;
11018
11019 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
11020 if (InterfaceID == AWDLInterfaceID)
11021 {
11022 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
11023 return mDNStrue;
11024 else
11025 return mDNSfalse;
11026 }
11027
11028 // Send record if it is explicitly marked to include all other P2P type interfaces.
11029 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
11030 return mDNStrue;
11031
11032 // Don't send the record over this interface.
11033 return mDNSfalse;
11034 }
11035
11036 // Filter questions send over P2P (D2D) type interfaces.
11037 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
11038 {
11039 // For an explicit match to a valid interface ID, return true.
11040 if (q->InterfaceID == intf->InterfaceID)
11041 return mDNStrue;
11042
11043 // Only filtering questions for D2D type interfaces
11044 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
11045 return mDNStrue;
11046
11047 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
11048 if (intf->InterfaceID == AWDLInterfaceID)
11049 {
11050 if (q->flags & kDNSServiceFlagsIncludeAWDL)
11051 return mDNStrue;
11052 else
11053 return mDNSfalse;
11054 }
11055
11056 // Sent question if it is explicitly marked to include all other P2P type interfaces.
11057 if (q->flags & kDNSServiceFlagsIncludeP2P)
11058 return mDNStrue;
11059
11060 // Don't send the question over this interface.
11061 return mDNSfalse;
11062 }
11063
11064 // Returns true unless record was received over the AWDL interface and
11065 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
11066 // with the kDNSServiceFlagsIncludeAWDL flag set.
11067 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
11068 {
11069 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
11070 return mDNStrue;
11071
11072 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
11073 return mDNSfalse;
11074
11075 return mDNStrue;
11076 }
11077
11078 // formating time to RFC 4034 format
11079 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
11080 {
11081 struct tm tmTime;
11082 time_t t = (time_t)te;
11083 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
11084 // gmtime_r first and then use strftime
11085 gmtime_r(&t, &tmTime);
11086 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
11087 }
11088
11089 mDNSexport mDNSs32 mDNSPlatformGetPID()
11090 {
11091 return getpid();
11092 }
11093
11094 // Schedule a function asynchronously on the main queue
11095 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
11096 {
11097 // KQueueLock/Unlock is used for two purposes
11098 //
11099 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
11100 // serializes the access to the "core"
11101 //
11102 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
11103 // up and calls udsserver_idle which schedules the messages across the uds socket.
11104 // If "func" delivers something to the uds socket from the dispatch thread, it will
11105 // not be delivered immediately if not for the Unlock.
11106 dispatch_async(dispatch_get_main_queue(), ^{
11107 KQueueLock(m);
11108 func(m, context);
11109 KQueueUnlock(m, "mDNSPlatformDispatchAsync");
11110 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
11111 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
11112 // to handle any message that "func" might deliver.
11113 TriggerEventCompletion();
11114 #endif
11115 });
11116 }
11117
11118 // definitions for device-info record construction
11119 #define DEVINFO_MODEL "model="
11120 #define DEVINFO_MODEL_LEN sizeof_string(DEVINFO_MODEL)
11121
11122 #define OSX_VER "osxvers="
11123 #define OSX_VER_LEN sizeof_string(OSX_VER)
11124 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
11125
11126 #define MODEL_COLOR "ecolor="
11127 #define MODEL_COLOR_LEN sizeof_string(MODEL_COLOR)
11128 #define MODEL_RGB_VALUE_LEN sizeof_string("255,255,255") // 'r,g,b'
11129
11130 // Bytes available in TXT record for model name after subtracting space for other
11131 // fixed size strings and their length bytes.
11132 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1) - (MODEL_COLOR_LEN + MODEL_RGB_VALUE_LEN + 1))
11133
11134 mDNSlocal mDNSu8 getModelIconColors(char *color)
11135 {
11136 mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
11137
11138 #if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
11139 mDNSu8 red = 0;
11140 mDNSu8 green = 0;
11141 mDNSu8 blue = 0;
11142
11143 IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
11144 &red, &green, &blue);
11145 if (kIOReturnSuccess == rGetDeviceColor)
11146 {
11147 // IOKit was able to get enclosure color for the current device.
11148 return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
11149 }
11150 #endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
11151
11152 return 0;
11153 }
11154
11155
11156 // Initialize device-info TXT record contents and return total length of record data.
11157 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
11158 {
11159 mDNSu8 *bufferStart = ptr;
11160 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
11161
11162 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
11163 ptr++;
11164 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
11165 ptr += DEVINFO_MODEL_LEN;
11166 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
11167 ptr += len;
11168
11169 // only include this string for OSX
11170 if (OSXVers)
11171 {
11172 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
11173 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
11174 ptr++;
11175 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
11176 ptr += OSX_VER_LEN;
11177 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
11178 // WARNING: This code assumes that OSXVers is always exactly two digits
11179 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
11180 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
11181 ptr += VER_NUM_LEN;
11182
11183 char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
11184 len = getModelIconColors(rgb);
11185 if (len)
11186 {
11187 *ptr = MODEL_COLOR_LEN + len; // length byte
11188 ptr++;
11189
11190 mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
11191 ptr += MODEL_COLOR_LEN;
11192
11193 mDNSPlatformMemCopy(ptr, rgb, len);
11194 ptr += len;
11195 }
11196 }
11197
11198 return (ptr - bufferStart);
11199 }
11200
11201
11202