]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
mDNSResponder-522.1.11.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 // ***************************************************************************
19 // mDNSMacOSX.c:
20 // Supporting routines to run mDNS on a CFRunLoop platform
21 // ***************************************************************************
22
23 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
24 // including ones that mDNSResponder chooses not to use.
25 #define LIST_ALL_INTERFACES 0
26
27 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
28 #include "DNSCommon.h"
29 #include "uDNS.h"
30 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
31 #include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
32 #include "PlatformCommon.h"
33 #include "uds_daemon.h"
34 #include "CryptoSupport.h"
35
36 #include <stdio.h>
37 #include <stdarg.h> // For va_list support
38 #include <stdlib.h> // For arc4random
39 #include <net/if.h>
40 #include <net/if_types.h> // For IFT_ETHER
41 #include <net/if_dl.h>
42 #include <net/bpf.h> // For BIOCSETIF etc.
43 #include <sys/uio.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <sys/event.h>
48 #include <fcntl.h>
49 #include <sys/ioctl.h>
50 #include <time.h> // platform support for UTC time
51 #include <arpa/inet.h> // for inet_aton
52 #include <pthread.h>
53 #include <netdb.h> // for getaddrinfo
54 #include <sys/sockio.h> // for SIOCGIFEFLAGS
55 #include <notify.h>
56 #include <netinet/in.h> // For IP_RECVTTL
57 #ifndef IP_RECVTTL
58 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
59 #endif
60
61 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
62 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
63 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
64 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
65
66 #include <netinet/tcp.h>
67
68 #include <DebugServices.h>
69 #include "dnsinfo.h"
70
71 #include <ifaddrs.h>
72
73 #include <IOKit/IOKitLib.h>
74 #include <IOKit/IOMessage.h>
75
76 #include <IOKit/ps/IOPowerSources.h>
77 #include <IOKit/ps/IOPowerSourcesPrivate.h>
78 #include <IOKit/ps/IOPSKeys.h>
79
80 #include <mach/mach_error.h>
81 #include <mach/mach_port.h>
82 #include <mach/mach_time.h>
83 #include "helper.h"
84 #include "P2PPacketFilter.h"
85
86 #include <asl.h>
87 #include <SystemConfiguration/SCPrivate.h>
88
89 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
90 #include <Kernel/IOKit/apple80211/apple80211_var.h>
91
92 #if APPLE_OSX_mDNSResponder
93 #include <DeviceToDeviceManager/DeviceToDeviceManager.h>
94 #include <AWACS.h>
95 #if !NO_D2D
96 D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
97 D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
98 D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
99 D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
100 D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
101 D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
102 D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
103 void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
104 void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
105 D2DStatus D2DTerminate() __attribute__((weak_import));
106
107 #endif // ! NO_D2D
108
109 #else
110 #define NO_D2D 1
111 #define NO_AWACS 1
112 #endif // APPLE_OSX_mDNSResponder
113
114 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
115 #include <IOKit/platform/IOPlatformSupportPrivate.h>
116 #endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
117
118
119 #define kInterfaceSpecificOption "interface="
120
121 #define mDNS_IOREG_KEY "mDNS_KEY"
122 #define mDNS_IOREG_VALUE "2009-07-30"
123 #define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
124 #define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
125
126 // cache the InterfaceID of the AWDL interface
127 static mDNSInterfaceID AWDLInterfaceID;
128
129 // ***************************************************************************
130 // Globals
131
132 #if COMPILER_LIKES_PRAGMA_MARK
133 #pragma mark - Globals
134 #endif
135
136 // By default we don't offer sleep proxy service
137 // If OfferSleepProxyService is set non-zero (typically via command-line switch),
138 // then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
139 // We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
140 mDNSexport int OfferSleepProxyService = 0;
141 mDNSexport int DisableSleepProxyClient = 0;
142 mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
143
144 mDNSexport int OSXVers, iOSVers;
145 mDNSexport int KQueueFD;
146
147 #ifndef NO_SECURITYFRAMEWORK
148 static CFArrayRef ServerCerts;
149 OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
150 #endif /* NO_SECURITYFRAMEWORK */
151
152 static CFStringRef NetworkChangedKey_IPv4;
153 static CFStringRef NetworkChangedKey_IPv6;
154 static CFStringRef NetworkChangedKey_Hostnames;
155 static CFStringRef NetworkChangedKey_Computername;
156 static CFStringRef NetworkChangedKey_DNS;
157 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
158 static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
159 static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
160 static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
161 static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
162
163 static char HINFO_HWstring_buffer[32];
164 static char *HINFO_HWstring = "Device";
165 static int HINFO_HWstring_prefixlen = 6;
166
167 mDNSexport int WatchDogReportingThreshold = 250;
168
169 dispatch_queue_t SSLqueue;
170
171 //To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue
172 static dispatch_queue_t DynamicStoreQueue;
173
174 #if TARGET_OS_EMBEDDED
175 #define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
176 #endif
177
178 #if APPLE_OSX_mDNSResponder
179 static mDNSu8 SPMetricPortability = 99;
180 static mDNSu8 SPMetricMarginalPower = 99;
181 static mDNSu8 SPMetricTotalPower = 99;
182 static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
183 mDNSexport domainname ActiveDirectoryPrimaryDomain;
184 mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
185 mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
186 #endif // APPLE_OSX_mDNSResponder
187
188 // Don't send triggers too often. We arbitrarily limit it to three minutes.
189 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
190
191 // Used by AutoTunnel
192 const char btmmprefix[] = "btmmdns:";
193 const char dnsprefix[] = "dns:";
194
195 // String Array used to write list of private domains to Dynamic Store
196 static CFArrayRef privateDnsArray = NULL;
197
198 // ***************************************************************************
199 #if COMPILER_LIKES_PRAGMA_MARK
200 #pragma mark -
201 #pragma mark - D2D Support
202 #endif
203
204 #if !NO_D2D
205
206 mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
207 {
208 // AWDL wants the address and reverse address PTR record communicated
209 // via the D2D interface layer.
210 if (interface->InterfaceID == AWDLInterfaceID)
211 {
212 LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
213 external_start_advertising_service(&interface->RR_A.resrec, NULL);
214 external_start_advertising_service(&interface->RR_PTR.resrec, NULL);
215 }
216 }
217
218 mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
219 {
220 if (interface->InterfaceID == AWDLInterfaceID)
221 {
222 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
223 if (interface->RR_A.resrec.RecordType)
224 external_stop_advertising_service(&interface->RR_A.resrec, NULL);
225 if (interface->RR_PTR.resrec.RecordType)
226 external_stop_advertising_service(&interface->RR_PTR.resrec, NULL);
227 }
228 }
229
230 // Name compression items for fake packet version number 1
231 static const mDNSu8 compression_packet_v1 = 0x01;
232
233 static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
234 static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
235 static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
236
237 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
238 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
239
240 typedef struct D2DRecordListElem
241 {
242 struct D2DRecordListElem *next;
243 AuthRecord ar;
244 D2DServiceInstance instanceHandle;
245 D2DTransportType transportType;
246 } D2DRecordListElem;
247
248 static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
249
250 typedef struct D2DBrowseListElem
251 {
252 struct D2DBrowseListElem *next;
253 domainname name;
254 mDNSu16 type;
255 unsigned int refCount;
256 } D2DBrowseListElem;
257
258 D2DBrowseListElem* D2DBrowseList = NULL;
259
260 mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
261 {
262 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
263 ptr[1] = (mDNSu8)((val ) & 0xFF);
264 return ptr + sizeof(mDNSu16);
265 }
266
267 mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
268 {
269 ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
270 ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
271 ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
272 ptr[3] = (mDNSu8)((val ) & 0xFF);
273 return ptr + sizeof(mDNSu32);
274 }
275
276 mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
277 {
278 const mDNSu8 * const start = (const mDNSu8 * const)in;
279 mDNSu8 *ptr = (mDNSu8*)start;
280 while(*ptr)
281 {
282 mDNSu8 c = *ptr;
283 out->c[ptr-start] = *ptr;
284 ptr++;
285 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
286 }
287 out->c[ptr-start] = *ptr;
288 }
289
290 mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
291 {
292 if (mDNS_LoggingEnabled)
293 {
294 LogInfo("%s", __func__);
295 LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
296 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
297 }
298
299 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
300
301 // Check to make sure we're not going to go past the end of the DNSMessage data
302 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
303 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
304
305 // Copy the LHS onto our fake wire packet
306 mDNSPlatformMemCopy(ptr, lhs, lhs_len);
307 ptr += lhs_len - 1;
308
309 // Check the 'fake packet' version number, to ensure that we know how to decompress this data
310 if (*ptr != compression_packet_v1) return mStatus_Incompatible;
311
312 // two bytes of CLASS
313 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
314
315 // four bytes of TTL
316 ptr = putVal32(ptr, 120);
317
318 // Copy the RHS length into the RDLENGTH of our fake wire packet
319 ptr = putVal16(ptr, rhs_len);
320
321 // Copy the RHS onto our fake wire packet
322 mDNSPlatformMemCopy(ptr, rhs, rhs_len);
323 ptr += rhs_len;
324
325 if (mDNS_LoggingEnabled)
326 {
327 LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
328 PrintHex(compression_lhs, ptr - compression_lhs);
329 }
330
331 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
332 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
333 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
334 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
335
336 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
337 AssignDomainName(&rr->namestorage, &m->rec.namestorage);
338 rr->resrec.rdlength = m->rec.r.resrec.rdlength;
339 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
340 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
341 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
342 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
343
344 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
345
346 return mStatus_NoError;
347 }
348
349 mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
350 {
351 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
352 if (!ptr) return ptr;
353 *ptr = (qtype >> 8) & 0xff;
354 ptr += 1;
355 *ptr = qtype & 0xff;
356 ptr += 1;
357 *ptr = compression_packet_v1;
358 return ptr + 1;
359 }
360
361 mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
362 {
363 return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
364 }
365
366 #define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
367
368 mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
369 {
370 mDNSu8 *end;
371 char buffer[49] = {0};
372 char *bufend = buffer + sizeof(buffer);
373
374 if (len > PRINT_DEBUG_BYTES_LIMIT)
375 {
376 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
377 len = PRINT_DEBUG_BYTES_LIMIT;
378 }
379 end = data + len;
380
381 while(data < end)
382 {
383 char *ptr = buffer;
384 for(; data < end && ptr < bufend-1; ptr+=3,data++)
385 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
386 LogInfo(" %s", buffer);
387 }
388 }
389
390 mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
391 {
392 if (!mDNS_LoggingEnabled) return;
393
394 LogInfo("%s:", tag);
395 LogInfo(" LHS: (%d bytes)", lhs_len);
396 PrintHex(lhs, lhs_len);
397
398 if (!rhs) return;
399
400 LogInfo(" RHS: (%d bytes)", rhs_len);
401 PrintHex(rhs, rhs_len);
402 }
403
404 mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
405 {
406 (void)m; // unused
407 if (result == mStatus_MemFree)
408 {
409 D2DRecordListElem **ptr = &D2DRecords;
410 D2DRecordListElem *tmp;
411 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
412 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
413 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
414 tmp = *ptr;
415 *ptr = (*ptr)->next;
416 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
417 mDNSPlatformMemFree(tmp);
418 }
419 }
420
421 mDNSexport void external_connection_release(const domainname *instance)
422 {
423 (void) instance;
424 D2DRecordListElem *ptr = D2DRecords;
425
426 for ( ; ptr ; ptr = ptr->next)
427 {
428 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
429 SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
430 {
431 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
432 ptr->instanceHandle, ptr->transportType);
433 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
434 }
435 }
436 }
437
438 mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
439 {
440 D2DRecordListElem *ptr = D2DRecords;
441 for ( ; ptr ; ptr = ptr->next)
442 {
443 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
444 {
445 mDNS_Deregister(&mDNSStorage, &ptr->ar);
446 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
447 }
448 }
449 }
450
451 mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
452 {
453 D2DBrowseListElem **ptr = &D2DBrowseList;
454
455 for ( ; *ptr; ptr = &(*ptr)->next)
456 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
457 break;
458
459 return ptr;
460 }
461
462 mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
463 {
464 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
465 return *ptr ? (*ptr)->refCount : 0;
466 }
467
468 mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
469 {
470 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
471
472 if (!*ptr)
473 {
474 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
475 mDNSPlatformMemZero(*ptr, sizeof(**ptr));
476 (*ptr)->type = type;
477 AssignDomainName(&(*ptr)->name, name);
478 }
479 (*ptr)->refCount += 1;
480
481 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
482 }
483
484 mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
485 {
486 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
487
488 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
489
490 (*ptr)->refCount -= 1;
491
492 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
493
494 if (!(*ptr)->refCount)
495 {
496 D2DBrowseListElem *tmp = *ptr;
497 *ptr = (*ptr)->next;
498 mDNSPlatformMemFree(tmp);
499 }
500 }
501
502 mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
503 {
504 if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
505 return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
506 else
507 return mStatus_Incompatible;
508 }
509
510 mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
511 {
512 if (result == kD2DSuccess)
513 {
514 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
515
516 mStatus err;
517 D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
518
519 if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
520
521 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
522 if (err)
523 {
524 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
525 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
526 mDNSPlatformMemFree(ptr);
527 return;
528 }
529 err = mDNS_Register(m, &ptr->ar);
530 if (err)
531 {
532 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
533 mDNSPlatformMemFree(ptr);
534 return;
535 }
536
537 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
538 ptr->instanceHandle = instanceHandle;
539 ptr->transportType = transportType;
540 ptr->next = D2DRecords;
541 D2DRecords = ptr;
542 }
543 else
544 LogMsg("xD2DAddToCache: Unexpected result %d", result);
545 }
546
547 mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
548 {
549 D2DRecordListElem *ptr = D2DRecords;
550 D2DRecordListElem *arptr;
551
552 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
553
554 arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
555 if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
556
557 if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
558 {
559 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
560 mDNSPlatformMemFree(arptr);
561 return NULL;
562 }
563
564 while (ptr)
565 {
566 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
567 ptr = ptr->next;
568 }
569
570 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
571 mDNSPlatformMemFree(arptr);
572 return ptr;
573 }
574
575 mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
576 {
577 (void)transportType; // We don't care about this, yet.
578 (void)instanceHandle; // We don't care about this, yet.
579
580 if (result == kD2DSuccess)
581 {
582 D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
583 if (ptr)
584 {
585 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
586 mDNS_Deregister(m, &ptr->ar);
587 }
588 }
589 else
590 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
591 }
592
593 mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
594 {
595 (void)m;
596 (void)key;
597 (void)keySize;
598 (void)value;
599 (void)valueSize;
600
601 if (result == kD2DSuccess)
602 {
603 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
604 if (D2DRetain) D2DRetain(instanceHandle, transportType);
605 }
606 else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
607 }
608
609 mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
610 {
611 (void)m;
612 (void)instanceHandle;
613 (void)transportType;
614 (void)key;
615 (void)keySize;
616 (void)value;
617 (void)valueSize;
618
619 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
620 else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
621 }
622
623 mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
624 {
625 (void)m;
626 (void)instanceHandle;
627 (void)transportType;
628 (void)key;
629 (void)keySize;
630 (void)value;
631 (void)valueSize;
632
633 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
634 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
635 }
636
637 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)
638 {
639 mDNS *m = (mDNS *) userData;
640 const char *eventString = "unknown";
641
642 KQueueLock(m);
643
644 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
645 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
646
647 switch (event)
648 {
649 case D2DServiceFound:
650 eventString = "D2DServiceFound";
651 break;
652 case D2DServiceLost:
653 eventString = "D2DServiceLost";
654 break;
655 case D2DServiceResolved:
656 eventString = "D2DServiceResolved";
657 break;
658 case D2DServiceRetained:
659 eventString = "D2DServiceRetained";
660 break;
661 case D2DServiceReleased:
662 eventString = "D2DServiceReleased";
663 break;
664 default:
665 break;
666 }
667
668 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);
669 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
670
671 switch (event)
672 {
673 case D2DServiceFound:
674 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
675 break;
676 case D2DServiceLost:
677 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
678 break;
679 case D2DServiceResolved:
680 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
681 break;
682 case D2DServiceRetained:
683 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
684 break;
685 case D2DServiceReleased:
686 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
687 break;
688 default:
689 break;
690 }
691
692 // Need to tickle the main kqueue loop to potentially handle records we removed or added.
693 KQueueUnlock(m, "xD2DServiceCallback");
694 }
695
696 // Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
697 // should be called.
698 // When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
699 // will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
700 // If the return value is not D2DTransportMax, excludedTransportType is undefined.
701
702 mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
703 {
704 NetworkInterfaceInfoOSX *info;
705
706 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
707 *excludedTransportType = D2DAWDLTransport;
708
709 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
710 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
711 {
712 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
713 *excludedTransportType = D2DTransportMax;
714 return D2DTransportMax;
715 }
716 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
717 else if (flags & kDNSServiceFlagsIncludeP2P)
718 {
719 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
720 return D2DTransportMax;
721 }
722 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
723 else if (flags & kDNSServiceFlagsIncludeAWDL)
724 {
725 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
726 return D2DAWDLTransport;
727 }
728
729 if (InterfaceID == mDNSInterface_P2P)
730 {
731 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
732 return D2DTransportMax;
733 }
734
735 // Compare to cached AWDL interface ID.
736 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
737 {
738 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
739 return D2DAWDLTransport;
740 }
741
742 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
743 if (info == NULL)
744 {
745 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
746 return D2DTransportMax;
747 }
748
749 // Recognize AirDrop specific p2p* interface based on interface name.
750 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
751 {
752 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
753 return D2DWifiPeerToPeerTransport;
754 }
755
756 // Currently there is no way to identify Bluetooth interface by name,
757 // since they use "en*" based name strings.
758
759 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
760 return D2DTransportMax;
761 }
762
763 mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
764 {
765 domainname lower;
766
767 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
768 {
769 LogInfo("external_start_browsing_for_service: ignoring address record");
770 return;
771 }
772
773 DomainnameToLower(typeDomain, &lower);
774
775 if (!D2DBrowseListRefCount(&lower, qtype))
776 {
777 D2DTransportType transportType, excludedTransport;
778
779 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
780 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
781 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
782
783 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
784 if (transportType == D2DTransportMax)
785 {
786 D2DTransportType i;
787 for (i = 0; i < D2DTransportMax; i++)
788 {
789 if (i == excludedTransport) continue;
790 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
791 }
792 }
793 else
794 {
795 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
796 }
797 }
798 D2DBrowseListRetain(&lower, qtype);
799 }
800
801 mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
802 {
803 domainname lower;
804
805 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
806 {
807 LogInfo("external_stop_browsing_for_service: ignoring address record");
808 return;
809 }
810
811 DomainnameToLower(typeDomain, &lower);
812
813 D2DBrowseListRelease(&lower, qtype);
814 if (!D2DBrowseListRefCount(&lower, qtype))
815 {
816 D2DTransportType transportType, excludedTransport;
817
818 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
819 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
820 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
821
822 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
823 if (transportType == D2DTransportMax)
824 {
825 D2DTransportType i;
826 for (i = 0; i < D2DTransportMax; i++)
827 {
828 if (i == excludedTransport) continue;
829 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
830 }
831 }
832 else
833 {
834 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
835 }
836
837 // The D2D driver may not generate the D2DServiceLost event for this key after
838 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
839 // record cache now.
840 xD2DClearCache(&lower, qtype);
841 }
842 }
843
844 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
845 {
846 domainname lower;
847 mDNSu8 *rhs = NULL;
848 mDNSu8 *end = NULL;
849 D2DTransportType transportType, excludedTransport;
850 DomainnameToLower(resourceRecord->name, &lower);
851
852 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
853 // For SRV records, update packet filter if p2p interface already exists, otherwise,
854 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
855 if (resourceRecord->rrtype == kDNSType_SRV)
856 mDNSUpdatePacketFilter(NULL);
857
858 if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
859 {
860 LogInfo("external_start_advertising_service: ignoring address record");
861 return;
862 }
863 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
864 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
865 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
866
867 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
868 if (transportType == D2DTransportMax)
869 {
870 D2DTransportType i;
871 for (i = 0; i < D2DTransportMax; i++)
872 {
873 if (i == excludedTransport) continue;
874 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
875 }
876 }
877 else
878 {
879 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
880 }
881 }
882
883 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
884 {
885 domainname lower;
886 mDNSu8 *rhs = NULL;
887 mDNSu8 *end = NULL;
888 D2DTransportType transportType, excludedTransport;
889 DomainnameToLower(resourceRecord->name, &lower);
890
891 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
892
893 // For SRV records, update packet filter to to remove this port from list
894 if (resourceRecord->rrtype == kDNSType_SRV)
895 mDNSUpdatePacketFilter(resourceRecord);
896
897 if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
898 {
899 LogInfo("external_stop_advertising_service: ignoring address record");
900 return;
901 }
902 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
903 end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
904 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
905
906 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
907 if (transportType == D2DTransportMax)
908 {
909 D2DTransportType i;
910 for (i = 0; i < D2DTransportMax; i++)
911 {
912 if (i == excludedTransport) continue;
913 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
914 }
915 }
916 else
917 {
918 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
919 }
920 }
921
922 mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
923 {
924 domainname lower;
925 mDNSu8 *rhs = NULL;
926 mDNSu8 *end = NULL;
927 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
928 D2DTransportType transportType, excludedTransport;
929 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
930
931 LogInfo("external_start_resolving_service: %##s", fqdn->c);
932 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
933 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
934 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
935
936 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
937 if (transportType == D2DTransportMax)
938 {
939 // Resolving over all the transports, except for excludedTransport if set.
940 D2DTransportType i;
941 for (i = 0; i < D2DTransportMax; i++)
942 {
943 if (i == excludedTransport) continue;
944 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
945
946 if (i == D2DAWDLTransport)
947 AWDL_used = true;
948 }
949 }
950 else
951 {
952 // Resolving over one specific transport.
953 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
954
955 if (transportType == D2DAWDLTransport)
956 AWDL_used = true;
957 }
958
959 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
960 // We only want these records going to AWDL, so use AWDLInterfaceID as the
961 // interface and don't set any other flags.
962 if (AWDL_used && AWDLInterfaceID)
963 {
964 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
965 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
966 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
967 }
968 }
969
970 mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
971 {
972 domainname lower;
973 mDNSu8 *rhs = NULL;
974 mDNSu8 *end = NULL;
975 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
976 D2DTransportType transportType, excludedTransport;
977 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
978
979 LogInfo("external_stop_resolving_service: %##s", fqdn->c);
980 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
981 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
982 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
983
984 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
985 if (transportType == D2DTransportMax)
986 {
987 D2DTransportType i;
988 for (i = 0; i < D2DTransportMax; i++)
989 {
990 if (i == excludedTransport) continue;
991 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
992
993 if (i == D2DAWDLTransport)
994 AWDL_used = true;
995 }
996 }
997 else
998 {
999 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
1000
1001 if (transportType == D2DAWDLTransport)
1002 AWDL_used = true;
1003 }
1004
1005 // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
1006 // We only want these records going to AWDL, so use AWDLInterfaceID as the
1007 // interface and don't set any other flags.
1008 if (AWDL_used && AWDLInterfaceID)
1009 {
1010 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
1011 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
1012 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
1013 }
1014 }
1015
1016 #elif APPLE_OSX_mDNSResponder
1017
1018 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;}
1019 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;}
1020 mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1021 mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
1022 mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1023 mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
1024
1025 #endif // ! NO_D2D
1026
1027 // ***************************************************************************
1028 // Functions
1029
1030 #if COMPILER_LIKES_PRAGMA_MARK
1031 #pragma mark -
1032 #pragma mark - Utility Functions
1033 #endif
1034
1035 // We only attempt to send and receive multicast packets on interfaces that are
1036 // (a) flagged as multicast-capable
1037 // (b) *not* flagged as point-to-point (e.g. modem)
1038 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
1039 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
1040 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
1041 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
1042
1043 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
1044 {
1045 static int notifyCount = 0;
1046 if (notifyCount) return;
1047
1048 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1049 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1050 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
1051
1052 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1053 #if !ForceAlerts
1054 {
1055 // Determine if we're at Apple (17.*.*.*)
1056 NetworkInterfaceInfoOSX *i;
1057 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
1058 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
1059 break;
1060 if (!i) return; // If not at Apple, don't show the alert
1061 }
1062 #endif
1063
1064 LogMsg("%s", title);
1065 LogMsg("%s", msg);
1066 // Display a notification to the user
1067 notifyCount++;
1068
1069 #ifndef NO_CFUSERNOTIFICATION
1070 mDNSNotify(title, msg);
1071 #endif /* NO_CFUSERNOTIFICATION */
1072 }
1073
1074 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
1075 mDNSlocal mDNSBool IsAppleTV(void)
1076 {
1077 #if TARGET_OS_EMBEDDED
1078 static mDNSBool sInitialized = mDNSfalse;
1079 static mDNSBool sIsAppleTV = mDNSfalse;
1080 CFStringRef deviceClass = NULL;
1081
1082 if(!sInitialized)
1083 {
1084 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
1085 if(deviceClass)
1086 {
1087 if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
1088 sIsAppleTV = mDNStrue;
1089 CFRelease(deviceClass);
1090 }
1091 sInitialized = mDNStrue;
1092 }
1093 return(sIsAppleTV);
1094 #else
1095 return mDNSfalse;
1096 #endif // TARGET_OS_EMBEDDED
1097 }
1098
1099 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
1100 {
1101 static struct ifaddrs *ifa = NULL;
1102
1103 if (refresh && ifa)
1104 {
1105 freeifaddrs(ifa);
1106 ifa = NULL;
1107 }
1108
1109 if (ifa == NULL)
1110 getifaddrs(&ifa);
1111 return ifa;
1112 }
1113
1114 mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
1115 {
1116 CFStringRef sckey = NULL;
1117 Boolean release_sckey = FALSE;
1118 CFDataRef bytes = NULL;
1119 CFPropertyListRef plist = NULL;
1120 SCDynamicStoreRef store = NULL;
1121
1122 switch ((enum mDNSDynamicStoreSetConfigKey)key)
1123 {
1124 case kmDNSMulticastConfig:
1125 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
1126 break;
1127 case kmDNSDynamicConfig:
1128 sckey = CFSTR("State:/Network/DynamicDNS");
1129 break;
1130 case kmDNSPrivateConfig:
1131 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
1132 break;
1133 case kmDNSBackToMyMacConfig:
1134 sckey = CFSTR("State:/Network/BackToMyMac");
1135 break;
1136 case kmDNSSleepProxyServersState:
1137 {
1138 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
1139 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
1140 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
1141 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
1142 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
1143 release_sckey = TRUE;
1144 CFRelease(tmp);
1145 break;
1146 }
1147 case kmDNSDebugState:
1148 sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
1149 break;
1150 default:
1151 LogMsg("unrecognized key %d", key);
1152 goto fin;
1153 }
1154 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
1155 valueCnt, kCFAllocatorNull)))
1156 {
1157 LogMsg("CFDataCreateWithBytesNoCopy of value failed");
1158 goto fin;
1159 }
1160 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
1161 kCFPropertyListImmutable, NULL)))
1162 {
1163 LogMsg("CFPropertyListCreateFromXMLData of bytes failed");
1164 goto fin;
1165 }
1166 CFRelease(bytes);
1167 bytes = NULL;
1168 if (NULL == (store = SCDynamicStoreCreate(NULL,
1169 CFSTR(kmDNSResponderServName), NULL, NULL)))
1170 {
1171 LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
1172 goto fin;
1173 }
1174 SCDynamicStoreSetValue(store, sckey, plist);
1175
1176 fin:
1177 if (NULL != bytes)
1178 CFRelease(bytes);
1179 if (NULL != plist)
1180 CFRelease(plist);
1181 if (NULL != store)
1182 CFRelease(store);
1183 if (release_sckey && sckey)
1184 CFRelease(sckey);
1185 }
1186
1187 mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
1188 {
1189 CFPropertyListRef valueCopy;
1190 char *subkeyCopy = NULL;
1191 if (!value)
1192 return;
1193
1194 // We need to copy the key and value before we dispatch off the block below as the
1195 // caller will free the memory once we return from this function.
1196 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
1197 if (!valueCopy)
1198 {
1199 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
1200 return;
1201 }
1202 if (subkey)
1203 {
1204 int len = strlen(subkey);
1205 subkeyCopy = mDNSPlatformMemAllocate(len + 1);
1206 if (!subkeyCopy)
1207 {
1208 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
1209 return;
1210 }
1211 mDNSPlatformMemCopy(subkeyCopy, subkey, len);
1212 subkeyCopy[len] = 0;
1213 }
1214
1215 dispatch_async(DynamicStoreQueue, ^{
1216 CFWriteStreamRef stream = NULL;
1217 CFDataRef bytes = NULL;
1218 CFStringRef error;
1219 CFIndex ret;
1220
1221 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
1222 {
1223 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
1224 goto END;
1225 }
1226 CFWriteStreamOpen(stream);
1227 ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error);
1228 if (ret == 0)
1229 {
1230 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
1231 goto END;
1232 }
1233 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
1234 {
1235 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
1236 goto END;
1237 }
1238 CFWriteStreamClose(stream);
1239 CFRelease(stream);
1240 stream = NULL;
1241 LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy);
1242 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
1243
1244 END:
1245 CFRelease(valueCopy);
1246 if (NULL != stream)
1247 {
1248 CFWriteStreamClose(stream);
1249 CFRelease(stream);
1250 }
1251 if (NULL != bytes)
1252 CFRelease(bytes);
1253 if (subkeyCopy)
1254 mDNSPlatformMemFree(subkeyCopy);
1255 });
1256 }
1257
1258 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
1259 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
1260 {
1261 NetworkInterfaceInfoOSX *i;
1262 for (i = m->p->InterfaceList; i; i = i->next)
1263 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
1264 ((type == AF_UNSPEC ) ||
1265 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
1266 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
1267 return(NULL);
1268 }
1269
1270 #if TARGET_OS_EMBEDDED
1271 mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void)
1272 {
1273 SCPreferencesRef smDNSManagedPrefs = NULL;
1274 smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID);
1275
1276 return (smDNSManagedPrefs);
1277 }
1278
1279 mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key)
1280 {
1281 mDNSBool val = mDNSfalse;
1282 CFBooleanRef val_cf = NULL;
1283
1284 if (prefs != NULL)
1285 {
1286 val_cf = SCPreferencesGetValue(prefs, key);
1287 if (isA_CFBoolean(val_cf) != NULL)
1288 val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed
1289 else
1290 val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled
1291 }
1292 else
1293 {
1294 LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!");
1295 val = mDNSfalse;
1296 }
1297 if (val_cf)
1298 CFRelease(val_cf);
1299 return (val);
1300 }
1301
1302 mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key)
1303 {
1304 SCPreferencesRef managed = NULL;
1305 mDNSBool ret_value;
1306
1307 managed = mDNSManagedPrefsGet();
1308 ret_value = GetmDNSManagedPrefKeyVal(managed, key);
1309
1310 if (managed)
1311 CFRelease(managed);
1312 return (ret_value);
1313 }
1314 #endif //TARGET_OS_EMBEDDED
1315
1316 mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
1317 {
1318 struct ifaddrs *ifa;
1319 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
1320 if (ifa->ifa_addr->sa_family == AF_LINK)
1321 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
1322 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
1323 return -1;
1324 }
1325
1326 mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
1327 {
1328 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
1329 NetworkInterfaceInfoOSX *i;
1330
1331 // Don't get tricked by inactive interfaces
1332 for (i = m->p->InterfaceList; i; i = i->next)
1333 if (i->Registered && i->scope_id == scope_id) return(i);
1334
1335 return mDNSNULL;
1336 }
1337
1338 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
1339 {
1340 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
1341 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
1342 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
1343
1344 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1345 if (!ifi)
1346 {
1347 // Not found. Make sure our interface list is up to date, then try again.
1348 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
1349 mDNSMacOSXNetworkChanged(m);
1350 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
1351 }
1352
1353 if (!ifi) return(mDNSNULL);
1354
1355 return(ifi->ifinfo.InterfaceID);
1356 }
1357
1358
1359 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
1360 {
1361 NetworkInterfaceInfoOSX *i;
1362 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
1363 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
1364 if (id == mDNSInterface_Any ) return(0);
1365
1366 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
1367
1368 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
1369 for (i = m->p->InterfaceList; i; i = i->next)
1370 if (i->scope_id == scope_id) return(i->scope_id);
1371
1372 // If we are supposed to suppress network change, return "id" back
1373 if (suppressNetworkChange) return scope_id;
1374
1375 // Not found. Make sure our interface list is up to date, then try again.
1376 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
1377 mDNSMacOSXNetworkChanged(m);
1378 for (i = m->p->InterfaceList; i; i = i->next)
1379 if (i->scope_id == scope_id) return(i->scope_id);
1380
1381 return(0);
1382 }
1383
1384 #if APPLE_OSX_mDNSResponder
1385 mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
1386 {
1387 if (iOSVers)
1388 return; // No ASL on iOS
1389
1390 static char buffer[512];
1391 aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
1392
1393 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
1394 if (uuid)
1395 {
1396 char uuidStr[37];
1397 uuid_unparse(*uuid, uuidStr);
1398 asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
1399 }
1400
1401 static char domainBase[] = "com.apple.mDNSResponder.%s";
1402 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
1403 asl_set (asl_msg, "com.apple.message.domain", buffer);
1404
1405 if (result) asl_set(asl_msg, "com.apple.message.result", result);
1406 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
1407
1408 va_list ptr;
1409 va_start(ptr,fmt);
1410 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
1411 va_end(ptr);
1412
1413 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
1414 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
1415 asl_set_filter(NULL, old_filter);
1416 asl_free(asl_msg);
1417 }
1418
1419
1420 mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
1421 {
1422 char buffer[16];
1423
1424 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1425
1426 // If we failed to allocate an aslmsg structure, keep accumulating
1427 // the statistics and try again at the next log interval.
1428 if (!aslmsg)
1429 {
1430 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
1431 return;
1432 }
1433
1434 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
1435
1436 if (m->rrcache_totalused_unicast)
1437 {
1438 mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
1439 }
1440 else
1441 {
1442 LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
1443 buffer[0] = 0;
1444 }
1445 asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
1446
1447 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
1448 asl_set(aslmsg,"com.apple.message.Latency0", buffer);
1449 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
1450 asl_set(aslmsg,"com.apple.message.Latency10", buffer);
1451 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
1452 asl_set(aslmsg,"com.apple.message.Latency20", buffer);
1453 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
1454 asl_set(aslmsg,"com.apple.message.Latency50", buffer);
1455 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
1456 asl_set(aslmsg,"com.apple.message.Latency100", buffer);
1457
1458 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
1459 asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
1460 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
1461 asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
1462 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
1463 asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
1464 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
1465 asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
1466
1467 // Ignore IndeterminateStatus as we don't log them
1468 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
1469 asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
1470 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
1471 asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
1472 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
1473 asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
1474 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
1475 asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
1476
1477 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
1478 asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
1479 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
1480 asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
1481 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
1482 asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
1483 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
1484 asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
1485
1486 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1487 asl_free(aslmsg);
1488 }
1489
1490 // Calculate packets per hour given total packet count and interval in seconds.
1491 // Cast one term of multiplication to (long) to use 64-bit arithmetic
1492 // and avoid a potential 32-bit overflow prior to the division.
1493 #define ONE_HOUR 3600
1494 #define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
1495
1496 // Put packet rate data in discrete buckets.
1497 mDNSlocal int mDNSBucketData(int inputData, int interval)
1498 {
1499 if (!interval)
1500 {
1501 LogMsg("mDNSBucketData: interval is zero!");
1502 return 0;
1503 }
1504
1505 int ratePerHour = PACKET_RATE(inputData, interval);
1506 int bucket;
1507
1508 if (ratePerHour == 0)
1509 bucket = 0;
1510 else if (ratePerHour <= 10)
1511 bucket = 10;
1512 else if (ratePerHour <= 100)
1513 bucket = 100;
1514 else if (ratePerHour <= 1000)
1515 bucket = 1000;
1516 else if (ratePerHour <= 5000)
1517 bucket = 5000;
1518 else if (ratePerHour <= 10000)
1519 bucket = 10000;
1520 else if (ratePerHour <= 50000)
1521 bucket = 50000;
1522 else if (ratePerHour <= 100000)
1523 bucket = 100000;
1524 else if (ratePerHour <= 250000)
1525 bucket = 250000;
1526 else if (ratePerHour <= 500000)
1527 bucket = 500000;
1528 else
1529 bucket = 1000000;
1530
1531 return bucket;
1532 }
1533
1534 mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
1535 {
1536 static mDNSs32 last_PktNum, last_MPktNum;
1537 static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
1538 static mDNSs32 last_RemoteSubnet;
1539
1540 mDNSs32 interval;
1541 char buffer[16];
1542 mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
1543 mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
1544 mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
1545 mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
1546 mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
1547
1548
1549 // save starting values for new interval
1550 last_PktNum = m->PktNum;
1551 last_MPktNum = m->MPktNum;
1552 last_UnicastPacketsSent = m->UnicastPacketsSent;
1553 last_MulticastPacketsSent = m->MulticastPacketsSent;
1554 last_RemoteSubnet = m->RemoteSubnet;
1555
1556 // Need a non-zero active time interval.
1557 if (!m->ActiveStatTime)
1558 return;
1559
1560 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
1561 interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
1562
1563 // Use a minimum of 30 minutes of awake time to calculate average packet rates.
1564 // The rounded awake interval should not be greater than the rounded reporting
1565 // interval.
1566 if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
1567 return;
1568
1569 aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
1570
1571 if (!aslmsg)
1572 {
1573 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
1574 return;
1575 }
1576 // log in MessageTracer format
1577 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
1578
1579 snprintf(buffer, sizeof(buffer), "%d", interval);
1580 asl_set(aslmsg,"com.apple.message.interval", buffer);
1581
1582 // log the packet rates as packets per hour
1583 snprintf(buffer, sizeof(buffer), "%d",
1584 mDNSBucketData(inUnicast, m->ActiveStatTime));
1585 asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
1586
1587 snprintf(buffer, sizeof(buffer), "%d",
1588 mDNSBucketData(inMulticast, m->ActiveStatTime));
1589 asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
1590
1591 snprintf(buffer, sizeof(buffer), "%d",
1592 mDNSBucketData(outUnicast, m->ActiveStatTime));
1593 asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
1594
1595 snprintf(buffer, sizeof(buffer), "%d",
1596 mDNSBucketData(outMulticast, m->ActiveStatTime));
1597 asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
1598
1599 snprintf(buffer, sizeof(buffer), "%d",
1600 mDNSBucketData(remoteSubnet, m->ActiveStatTime));
1601 asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
1602
1603 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
1604
1605 asl_free(aslmsg);
1606 }
1607
1608 // Log multicast and unicast traffic statistics to MessageTracer on OSX
1609 mDNSexport void mDNSLogStatistics(mDNS *const m)
1610 {
1611 // MessageTracer only available on OSX
1612 if (iOSVers)
1613 return;
1614
1615 mDNSs32 currentUTC = mDNSPlatformUTC();
1616
1617 // log runtime statistics
1618 if ((currentUTC - m->NextStatLogTime) >= 0)
1619 {
1620 m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
1621 // If StatStartTime is zero, it hasn't been reinitialized yet
1622 // in the wakeup code path.
1623 if (m->StatStartTime)
1624 {
1625 m->ActiveStatTime += currentUTC - m->StatStartTime;
1626 }
1627
1628 // Only log statistics if we have recorded some active time during
1629 // this statistics interval.
1630 if (m->ActiveStatTime)
1631 {
1632 mDNSLogBonjourStatistics(m);
1633 mDNSLogDNSSECStatistics(m);
1634 }
1635
1636 // Start a new statistics gathering interval.
1637 m->StatStartTime = currentUTC;
1638 m->ActiveStatTime = 0;
1639 }
1640 }
1641
1642 #endif // APPLE_OSX_mDNSResponder
1643
1644 #if COMPILER_LIKES_PRAGMA_MARK
1645 #pragma mark -
1646 #pragma mark - UDP & TCP send & receive
1647 #endif
1648
1649 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
1650 {
1651 mDNSBool result = mDNSfalse;
1652 SCNetworkConnectionFlags flags;
1653 CFDataRef remote_addr;
1654 CFMutableDictionaryRef options;
1655 SCNetworkReachabilityRef ReachRef = NULL;
1656
1657 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1658 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
1659 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
1660 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
1661 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
1662 CFRelease(options);
1663 CFRelease(remote_addr);
1664
1665 if (!ReachRef)
1666 {
1667 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
1668 goto end;
1669 }
1670 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
1671 {
1672 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
1673 goto end;
1674 }
1675 result = flags & kSCNetworkFlagsConnectionRequired;
1676
1677 end:
1678 if (ReachRef)
1679 CFRelease(ReachRef);
1680 return result;
1681 }
1682
1683 // Set traffic class for socket
1684 mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
1685 {
1686 int traffic_class;
1687
1688 if (useBackgroundTrafficClass)
1689 traffic_class = SO_TC_BK_SYS;
1690 else
1691 traffic_class = SO_TC_CTL;
1692
1693 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
1694 }
1695
1696 mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
1697 {
1698 if (src)
1699 {
1700 int s;
1701
1702 if (dst->type == mDNSAddrType_IPv4)
1703 {
1704 s = src->ss.sktv4;
1705 }
1706 else
1707 {
1708 s = src->ss.sktv6;
1709 }
1710
1711 if (q->pid)
1712 {
1713 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
1714 {
1715 LogInfo("mDNSPlatformSetDelegatePID: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
1716 }
1717 }
1718 else
1719 {
1720 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
1721 {
1722 LogInfo("mDNSPlatformSetDelegatePID: Delegate UUID failed %s", strerror(errno));
1723 }
1724 }
1725 }
1726 }
1727
1728 // Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1729 // Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1730 // OR send via our primary v4 unicast socket
1731 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1732 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
1733 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
1734 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
1735 {
1736 NetworkInterfaceInfoOSX *info = mDNSNULL;
1737 struct sockaddr_storage to;
1738 int s = -1, err;
1739 mStatus result = mStatus_NoError;
1740
1741 if (InterfaceID)
1742 {
1743 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
1744 if (info == NULL)
1745 {
1746 // We may not have registered interfaces with the "core" as we may not have
1747 // seen any interface notifications yet. This typically happens during wakeup
1748 // where we might try to send DNS requests (non-SuppressUnusable questions internal
1749 // to mDNSResponder) before we receive network notifications.
1750 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
1751 return mStatus_BadParamErr;
1752 }
1753 }
1754
1755 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
1756
1757 if (dst->type == mDNSAddrType_IPv4)
1758 {
1759 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
1760 sin_to->sin_len = sizeof(*sin_to);
1761 sin_to->sin_family = AF_INET;
1762 sin_to->sin_port = dstPort.NotAnInteger;
1763 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1764 s = (src ? src->ss : m->p->permanentsockets).sktv4;
1765
1766 if (info) // Specify outgoing interface
1767 {
1768 if (!mDNSAddrIsDNSMulticast(dst))
1769 {
1770 #ifdef IP_BOUND_IF
1771 if (info->scope_id == 0)
1772 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
1773 else
1774 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
1775 #else
1776 {
1777 static int displayed = 0;
1778 if (displayed < 1000)
1779 {
1780 displayed++;
1781 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
1782 }
1783 }
1784 #endif
1785 }
1786 else
1787 #ifdef IP_MULTICAST_IFINDEX
1788 {
1789 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
1790 // We get an error when we compile on a machine that supports this option and run the binary on
1791 // a different machine that does not support it
1792 if (err < 0)
1793 {
1794 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
1795 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1796 if (err < 0 && !m->p->NetworkChanged)
1797 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1798 }
1799 }
1800 #else
1801 {
1802 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
1803 if (err < 0 && !m->p->NetworkChanged)
1804 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
1805
1806 }
1807 #endif
1808 }
1809 }
1810
1811 else if (dst->type == mDNSAddrType_IPv6)
1812 {
1813 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
1814 sin6_to->sin6_len = sizeof(*sin6_to);
1815 sin6_to->sin6_family = AF_INET6;
1816 sin6_to->sin6_port = dstPort.NotAnInteger;
1817 sin6_to->sin6_flowinfo = 0;
1818 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
1819 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
1820 s = (src ? src->ss : m->p->permanentsockets).sktv6;
1821 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
1822 {
1823 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
1824 if (err < 0)
1825 {
1826 char name[IFNAMSIZ];
1827 if (if_indextoname(info->scope_id, name) != NULL)
1828 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
1829 else
1830 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
1831 }
1832 }
1833 }
1834
1835 else
1836 {
1837 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1838 #if ForceAlerts
1839 *(long*)0 = 0;
1840 #endif
1841 return mStatus_BadParamErr;
1842 }
1843
1844 if (s >= 0)
1845 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1846 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
1847 else
1848 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1849 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1850
1851 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1852 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1853 if (s < 0) return(mStatus_Invalid);
1854
1855 // switch to background traffic class for this message if requested
1856 if (useBackgroundTrafficClass)
1857 setTrafficClass(s, useBackgroundTrafficClass);
1858
1859 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1860
1861 // set traffic class back to default value
1862 if (useBackgroundTrafficClass)
1863 setTrafficClass(s, mDNSfalse);
1864
1865 if (err < 0)
1866 {
1867 static int MessageCount = 0;
1868 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1869 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1870 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1871 // Don't report EHOSTUNREACH in the first three minutes after boot
1872 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1873 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1874 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1875 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1876 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1877 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
1878 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
1879 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1880 else
1881 {
1882 MessageCount++;
1883 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
1884 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
1885 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1886 else // If logging is enabled, remove the cap and log aggressively
1887 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
1888 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
1889 }
1890
1891 result = mStatus_UnknownErr;
1892 }
1893
1894 #ifdef IP_BOUND_IF
1895 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1896 {
1897 static const mDNSu32 ifindex = 0;
1898 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1899 }
1900 #endif
1901
1902 return(result);
1903 }
1904
1905 mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1906 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1907 {
1908 static unsigned int numLogMessages = 0;
1909 struct iovec databuffers = { (char *)buffer, max };
1910 struct msghdr msg;
1911 ssize_t n;
1912 struct cmsghdr *cmPtr;
1913 char ancillary[1024];
1914
1915 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1916
1917 // Set up the message
1918 msg.msg_name = (caddr_t)from;
1919 msg.msg_namelen = *fromlen;
1920 msg.msg_iov = &databuffers;
1921 msg.msg_iovlen = 1;
1922 msg.msg_control = (caddr_t)&ancillary;
1923 msg.msg_controllen = sizeof(ancillary);
1924 msg.msg_flags = 0;
1925
1926 // Receive the data
1927 n = recvmsg(s, &msg, 0);
1928 if (n<0)
1929 {
1930 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1931 return(-1);
1932 }
1933 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1934 {
1935 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
1936 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
1937 return(-1);
1938 }
1939 if (msg.msg_flags & MSG_CTRUNC)
1940 {
1941 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1942 return(-1);
1943 }
1944
1945 *fromlen = msg.msg_namelen;
1946
1947 // Parse each option out of the ancillary data.
1948 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1949 {
1950 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1951 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1952 {
1953 dstaddr->type = mDNSAddrType_IPv4;
1954 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1955 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1956 }
1957 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1958 {
1959 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1960 if (sdl->sdl_nlen < IF_NAMESIZE)
1961 {
1962 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1963 ifname[sdl->sdl_nlen] = 0;
1964 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1965 }
1966 }
1967 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1968 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1969 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1970 {
1971 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1972 dstaddr->type = mDNSAddrType_IPv6;
1973 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1974 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1975 }
1976 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1977 *ttl = *(int*)CMSG_DATA(cmPtr);
1978 }
1979
1980 return(n);
1981 }
1982
1983 mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
1984 {
1985 NetworkInterfaceInfo *intf;
1986
1987 if (addr->type == mDNSAddrType_IPv4)
1988 {
1989 for (intf = m->HostInterfaces; intf; intf = intf->next)
1990 {
1991 if (intf->ip.type == addr->type && intf->McastTxRx)
1992 {
1993 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
1994 {
1995 return(intf->InterfaceID);
1996 }
1997 }
1998 }
1999 }
2000
2001 if (addr->type == mDNSAddrType_IPv6)
2002 {
2003 for (intf = m->HostInterfaces; intf; intf = intf->next)
2004 {
2005 if (intf->ip.type == addr->type && intf->McastTxRx)
2006 {
2007 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
2008 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
2009 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
2010 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
2011 {
2012 return(intf->InterfaceID);
2013 }
2014 }
2015 }
2016 }
2017 return(mDNSInterface_Any);
2018 }
2019
2020 mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
2021 {
2022 // We should have a DNSMessage header followed by the question and an answer
2023 // which also includes a CNAME (that's when this function is called). To keep it
2024 // simple, we expect at least the size of DNSMessage header(12) and size of "A"
2025 // record (14 bytes).
2026 char buffer[26];
2027 int ret;
2028
2029 (void) m;
2030
2031 if (!src)
2032 return mDNSfalse;
2033
2034 ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK);
2035 if (ret > 0)
2036 return mDNStrue;
2037 else
2038 return mDNSfalse;
2039 }
2040
2041 mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
2042 {
2043 KQSocketSet *const ss = (KQSocketSet *)context;
2044 mDNS *const m = ss->m;
2045 int err = 0, count = 0, closed = 0;
2046
2047 if (filter != EVFILT_READ)
2048 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
2049
2050 if (s1 != ss->sktv4 && s1 != ss->sktv6)
2051 {
2052 LogMsg("myKQSocketCallBack: native socket %d", s1);
2053 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
2054 }
2055
2056 while (!closed)
2057 {
2058 mDNSAddr senderAddr, destAddr;
2059 mDNSIPPort senderPort;
2060 struct sockaddr_storage from;
2061 size_t fromlen = sizeof(from);
2062 char packetifname[IF_NAMESIZE] = "";
2063 mDNSu8 ttl;
2064 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
2065 if (err < 0) break;
2066
2067 count++;
2068 if (from.ss_family == AF_INET)
2069 {
2070 struct sockaddr_in *s = (struct sockaddr_in*)&from;
2071 senderAddr.type = mDNSAddrType_IPv4;
2072 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
2073 senderPort.NotAnInteger = s->sin_port;
2074 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2075 }
2076 else if (from.ss_family == AF_INET6)
2077 {
2078 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
2079 senderAddr.type = mDNSAddrType_IPv6;
2080 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
2081 senderPort.NotAnInteger = sin6->sin6_port;
2082 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
2083 }
2084 else
2085 {
2086 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
2087 return;
2088 }
2089
2090 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
2091 mDNSInterfaceID InterfaceID = mDNSNULL;
2092 //NetworkInterfaceInfo *intf = m->HostInterfaces;
2093 //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
2094
2095 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
2096 while (intf && strcmp(intf->ifinfo.ifname, packetifname)) intf = intf->next;
2097
2098 // When going to sleep we deregister all our interfaces, but if the machine
2099 // takes a few seconds to sleep we may continue to receive multicasts
2100 // during that time, which would confuse mDNSCoreReceive, because as far
2101 // as it's concerned, we should have no active interfaces any more.
2102 // Hence we ignore multicasts for which we can find no matching InterfaceID.
2103 if (intf)
2104 InterfaceID = intf->ifinfo.InterfaceID;
2105 else if (mDNSAddrIsDNSMulticast(&destAddr))
2106 continue;
2107
2108 if (!InterfaceID)
2109 {
2110 InterfaceID = FindMyInterface(m, &destAddr);
2111 }
2112
2113 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
2114 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
2115
2116 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
2117 // loop when that happens, or we may try to read from an invalid FD. We do this by
2118 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
2119 // if it closes the socketset.
2120 ss->closeFlag = &closed;
2121
2122 if (ss->proxy)
2123 {
2124 m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
2125 senderPort, &destAddr, ss->port, InterfaceID, NULL);
2126 }
2127 else
2128 {
2129 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
2130 }
2131
2132 // if we didn't close, we can safely dereference the socketset, and should to
2133 // reset the closeFlag, since it points to something on the stack
2134 if (!closed) ss->closeFlag = mDNSNULL;
2135 }
2136
2137 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
2138 {
2139 // Something is busted here.
2140 // kqueue says there is a packet, but myrecvfrom says there is not.
2141 // Try calling select() to get another opinion.
2142 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
2143 // All of this is racy, as data may have arrived after the call to select()
2144 static unsigned int numLogMessages = 0;
2145 int save_errno = errno;
2146 int so_error = -1;
2147 int so_nread = -1;
2148 int fionread = -1;
2149 socklen_t solen = sizeof(int);
2150 fd_set readfds;
2151 struct timeval timeout;
2152 int selectresult;
2153 FD_ZERO(&readfds);
2154 FD_SET(s1, &readfds);
2155 timeout.tv_sec = 0;
2156 timeout.tv_usec = 0;
2157 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
2158 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
2159 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
2160 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
2161 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
2162 if (ioctl(s1, FIONREAD, &fionread) == -1)
2163 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
2164 if (numLogMessages++ < 100)
2165 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
2166 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
2167 if (numLogMessages > 5)
2168 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
2169 "Congratulations, you've reproduced an elusive bug.\r"
2170 "Please contact the current assignee of <rdar://problem/3375328>.\r"
2171 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2172 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2173
2174 sleep(1); // After logging this error, rate limit so we don't flood syslog
2175 }
2176 }
2177
2178 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
2179 {
2180 mDNSBool c = !sock->connected;
2181 sock->connected = mDNStrue;
2182 sock->callback(sock, sock->context, c, sock->err);
2183 // Note: the callback may call CloseConnection here, which frees the context structure!
2184 }
2185
2186 #ifndef NO_SECURITYFRAMEWORK
2187
2188 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
2189 {
2190 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2191 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2192 if (ret >= 0) { *dataLength = ret; return(noErr); }
2193 *dataLength = 0;
2194 if (errno == EAGAIN ) return(errSSLWouldBlock);
2195 if (errno == ENOENT ) return(errSSLClosedGraceful);
2196 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
2197 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
2198 return(errSSLClosedAbort);
2199 }
2200
2201 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
2202 {
2203 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
2204 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
2205 if (ret > 0) { *dataLength = ret; return(noErr); }
2206 *dataLength = 0;
2207 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
2208 if ( errno == EAGAIN ) return(errSSLWouldBlock);
2209 if ( errno == ECONNRESET) return(errSSLClosedAbort);
2210 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
2211 return(errSSLClosedAbort);
2212 }
2213
2214 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
2215 {
2216 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
2217
2218 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
2219 if (!sock->tlsContext)
2220 {
2221 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
2222 return(mStatus_UnknownErr);
2223 }
2224
2225 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
2226 if (err)
2227 {
2228 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
2229 goto fail;
2230 }
2231
2232 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
2233 if (err)
2234 {
2235 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
2236 goto fail;
2237 }
2238
2239 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
2240 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
2241 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
2242 if (err)
2243 {
2244 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
2245 goto fail;
2246 }
2247
2248 // We already checked for NULL in hostname and this should never happen. Hence, returning -1
2249 // (error not in OSStatus space) is okay.
2250 if (!sock->hostname.c[0])
2251 {
2252 LogMsg("ERROR: tlsSetupSock: hostname NULL");
2253 err = -1;
2254 goto fail;
2255 }
2256
2257 ConvertDomainNameToCString(&sock->hostname, domname_cstr);
2258 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
2259 if (err)
2260 {
2261 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
2262 goto fail;
2263 }
2264
2265 return(err);
2266
2267 fail:
2268 if (sock->tlsContext)
2269 CFRelease(sock->tlsContext);
2270 return(err);
2271 }
2272
2273 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2274 mDNSlocal void doSSLHandshake(TCPSocket *sock)
2275 {
2276 mStatus err = SSLHandshake(sock->tlsContext);
2277
2278 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
2279 //defined, KQueueLock is a noop. Hence we need to serialize here
2280 //
2281 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
2282 //We need the rest of the logic also. Otherwise, we can enable the READ
2283 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
2284 //ConnFailed which means we are going to free the tcpInfo. While it
2285 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
2286 //and potentially call doTCPCallback with error which can close the fd and free the
2287 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
2288 //is already freed.
2289
2290 dispatch_async(dispatch_get_main_queue(), ^{
2291
2292 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2293
2294 if (sock->handshake == handshake_to_be_closed)
2295 {
2296 LogInfo("SSLHandshake completed after close");
2297 mDNSPlatformTCPCloseConnection(sock);
2298 }
2299 else
2300 {
2301 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2302 else LogMsg("doSSLHandshake: sock->fd is -1");
2303
2304 if (err == errSSLWouldBlock)
2305 sock->handshake = handshake_required;
2306 else
2307 {
2308 if (err)
2309 {
2310 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2311 CFRelease(sock->tlsContext);
2312 sock->tlsContext = NULL;
2313 }
2314
2315 sock->err = err ? mStatus_ConnFailed : 0;
2316 sock->handshake = handshake_completed;
2317
2318 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2319 doTcpSocketCallback(sock);
2320 }
2321 }
2322
2323 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2324 return;
2325 });
2326 }
2327 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2328 mDNSlocal void *doSSLHandshake(TCPSocket *sock)
2329 {
2330 // Warning: Touching sock without the kqueue lock!
2331 // We're protected because sock->handshake == handshake_in_progress
2332 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
2333 mStatus err = SSLHandshake(sock->tlsContext);
2334
2335 KQueueLock(m);
2336 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
2337
2338 if (sock->handshake == handshake_to_be_closed)
2339 {
2340 LogInfo("SSLHandshake completed after close");
2341 mDNSPlatformTCPCloseConnection(sock);
2342 }
2343 else
2344 {
2345 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
2346 else LogMsg("doSSLHandshake: sock->fd is -1");
2347
2348 if (err == errSSLWouldBlock)
2349 sock->handshake = handshake_required;
2350 else
2351 {
2352 if (err)
2353 {
2354 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
2355 CFRelease(sock->tlsContext);
2356 sock->tlsContext = NULL;
2357 }
2358
2359 sock->err = err ? mStatus_ConnFailed : 0;
2360 sock->handshake = handshake_completed;
2361
2362 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
2363 doTcpSocketCallback(sock);
2364 }
2365 }
2366
2367 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
2368 KQueueUnlock(m, "doSSLHandshake");
2369 return NULL;
2370 }
2371 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2372
2373 mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
2374 {
2375 debugf("spawnSSLHandshake %p: entry", sock);
2376
2377 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
2378 sock->handshake = handshake_in_progress;
2379 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
2380
2381 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
2382 // to limit the number of threads used for SSLHandshake
2383 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
2384
2385 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
2386 }
2387
2388 #endif /* NO_SECURITYFRAMEWORK */
2389
2390 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
2391 {
2392 TCPSocket *sock = context;
2393 sock->err = mStatus_NoError;
2394
2395 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
2396 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
2397 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
2398 if (filter == EVFILT_WRITE)
2399 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
2400
2401 if (sock->flags & kTCPSocketFlags_UseTLS)
2402 {
2403 #ifndef NO_SECURITYFRAMEWORK
2404 if (!sock->setup)
2405 {
2406 sock->setup = mDNStrue;
2407 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
2408 if (sock->err)
2409 {
2410 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
2411 return;
2412 }
2413 }
2414 if (sock->handshake == handshake_required)
2415 {
2416 spawnSSLHandshake(sock);
2417 return;
2418 }
2419 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
2420 {
2421 return;
2422 }
2423 else if (sock->handshake != handshake_completed)
2424 {
2425 if (!sock->err)
2426 sock->err = mStatus_UnknownErr;
2427 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
2428 }
2429 #else /* NO_SECURITYFRAMEWORK */
2430 sock->err = mStatus_UnsupportedErr;
2431 #endif /* NO_SECURITYFRAMEWORK */
2432 }
2433
2434 doTcpSocketCallback(sock);
2435 }
2436
2437 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2438 mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
2439 {
2440 dispatch_queue_t queue = dispatch_get_main_queue();
2441 dispatch_source_t source;
2442 if (flags == EV_DELETE)
2443 {
2444 if (filter == EVFILT_READ)
2445 {
2446 dispatch_source_cancel(entryRef->readSource);
2447 dispatch_release(entryRef->readSource);
2448 entryRef->readSource = mDNSNULL;
2449 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
2450 }
2451 else if (filter == EVFILT_WRITE)
2452 {
2453 dispatch_source_cancel(entryRef->writeSource);
2454 dispatch_release(entryRef->writeSource);
2455 entryRef->writeSource = mDNSNULL;
2456 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
2457 }
2458 else
2459 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
2460 return 0;
2461 }
2462 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
2463
2464 if (filter == EVFILT_READ)
2465 {
2466 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
2467 }
2468 else if (filter == EVFILT_WRITE)
2469 {
2470 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
2471 }
2472 else
2473 {
2474 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
2475 return -1;
2476 }
2477 if (!source) return -1;
2478 dispatch_source_set_event_handler(source, ^{
2479
2480 mDNSs32 stime = mDNSPlatformRawTime();
2481 entryRef->KQcallback(fd, filter, entryRef->KQcontext);
2482 mDNSs32 etime = mDNSPlatformRawTime();
2483 if (etime - stime >= WatchDogReportingThreshold)
2484 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
2485
2486 // Trigger the event delivery to the application. Even though we trigger the
2487 // event completion after handling every event source, these all will hopefully
2488 // get merged
2489 TriggerEventCompletion();
2490
2491 });
2492 dispatch_source_set_cancel_handler(source, ^{
2493 if (entryRef->fdClosed)
2494 {
2495 //LogMsg("CancelHandler: closing fd %d", fd);
2496 close(fd);
2497 }
2498 });
2499 dispatch_resume(source);
2500 if (filter == EVFILT_READ)
2501 entryRef->readSource = source;
2502 else
2503 entryRef->writeSource = source;
2504
2505 return 0;
2506 }
2507
2508 mDNSexport void KQueueLock(mDNS *const m)
2509 {
2510 (void)m; //unused
2511 }
2512 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
2513 {
2514 (void)m; //unused
2515 (void)task; //unused
2516 }
2517 #else
2518 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
2519 {
2520 struct kevent new_event;
2521 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
2522 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
2523 }
2524
2525 mDNSexport void KQueueLock(mDNS *const m)
2526 {
2527 pthread_mutex_lock(&m->p->BigMutex);
2528 m->p->BigMutexStartTime = mDNSPlatformRawTime();
2529 }
2530
2531 mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
2532 {
2533 mDNSs32 end = mDNSPlatformRawTime();
2534 (void)task;
2535 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
2536 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
2537
2538 pthread_mutex_unlock(&m->p->BigMutex);
2539
2540 char wake = 1;
2541 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
2542 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
2543 }
2544 #endif
2545
2546 mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
2547 {
2548 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2549 (void) fd; //unused
2550 if (kq->readSource)
2551 {
2552 dispatch_source_cancel(kq->readSource);
2553 kq->readSource = mDNSNULL;
2554 }
2555 if (kq->writeSource)
2556 {
2557 dispatch_source_cancel(kq->writeSource);
2558 kq->writeSource = mDNSNULL;
2559 }
2560 // Close happens in the cancellation handler
2561 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
2562 kq->fdClosed = mDNStrue;
2563 #else
2564 (void)kq; //unused
2565 close(fd);
2566 #endif
2567 }
2568
2569 mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2570 {
2571 KQSocketSet *cp = &sock->ss;
2572 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2573 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2574 const int on = 1; // "on" for setsockopt
2575 mStatus err;
2576
2577 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
2578 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2579
2580 // for TCP sockets, the traffic class is set once and not changed
2581 setTrafficClass(skt, useBackgroundTrafficClass);
2582
2583 if (sa_family == AF_INET)
2584 {
2585 // Bind it
2586 struct sockaddr_in addr;
2587 mDNSPlatformMemZero(&addr, sizeof(addr));
2588 addr.sin_family = AF_INET;
2589 addr.sin_port = port->NotAnInteger;
2590 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
2591 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
2592
2593 // Receive interface identifiers
2594 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
2595 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
2596
2597 mDNSPlatformMemZero(&addr, sizeof(addr));
2598 socklen_t len = sizeof(addr);
2599 err = getsockname(skt, (struct sockaddr*) &addr, &len);
2600 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
2601
2602 port->NotAnInteger = addr.sin_port;
2603 }
2604 else
2605 {
2606 // Bind it
2607 struct sockaddr_in6 addr6;
2608 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2609 addr6.sin6_family = AF_INET6;
2610 addr6.sin6_port = port->NotAnInteger;
2611 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
2612 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
2613
2614 // We want to receive destination addresses and receive interface identifiers
2615 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
2616 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; }
2617
2618 mDNSPlatformMemZero(&addr6, sizeof(addr6));
2619 socklen_t len = sizeof(addr6);
2620 err = getsockname(skt, (struct sockaddr *) &addr6, &len);
2621 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
2622
2623 port->NotAnInteger = addr6.sin6_port;
2624
2625 }
2626 *s = skt;
2627 k->KQcallback = tcpKQSocketCallback;
2628 k->KQcontext = sock;
2629 k->KQtask = "mDNSPlatformTCPSocket";
2630 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
2631 k->readSource = mDNSNULL;
2632 k->writeSource = mDNSNULL;
2633 k->fdClosed = mDNSfalse;
2634 #endif
2635 return mStatus_NoError;
2636 }
2637
2638 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
2639 {
2640 mStatus err;
2641 (void) m;
2642
2643 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
2644 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
2645
2646 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
2647
2648 sock->ss.m = m;
2649 sock->ss.sktv4 = -1;
2650 sock->ss.sktv6 = -1;
2651 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
2652
2653 if (!err)
2654 {
2655 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
2656 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
2657 }
2658 if (err)
2659 {
2660 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
2661 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
2662 return(mDNSNULL);
2663 }
2664 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
2665 sock->fd = sock->ss.sktv4;
2666 sock->callback = mDNSNULL;
2667 sock->flags = flags;
2668 sock->context = mDNSNULL;
2669 sock->setup = mDNSfalse;
2670 sock->connected = mDNSfalse;
2671 sock->handshake = handshake_required;
2672 sock->m = m;
2673 sock->err = mStatus_NoError;
2674
2675 return sock;
2676 }
2677
2678 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
2679 {
2680 KQSocketSet *cp = &sock->ss;
2681 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
2682 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
2683 mStatus err = mStatus_NoError;
2684 struct sockaddr_storage ss;
2685
2686 sock->callback = callback;
2687 sock->context = context;
2688 sock->setup = mDNSfalse;
2689 sock->connected = mDNSfalse;
2690 sock->handshake = handshake_required;
2691 sock->err = mStatus_NoError;
2692
2693 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
2694
2695 if (dst->type == mDNSAddrType_IPv4)
2696 {
2697 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
2698 mDNSPlatformMemZero(saddr, sizeof(*saddr));
2699 saddr->sin_family = AF_INET;
2700 saddr->sin_port = dstport.NotAnInteger;
2701 saddr->sin_len = sizeof(*saddr);
2702 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
2703 }
2704 else
2705 {
2706 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
2707 mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
2708 saddr6->sin6_family = AF_INET6;
2709 saddr6->sin6_port = dstport.NotAnInteger;
2710 saddr6->sin6_len = sizeof(*saddr6);
2711 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
2712 }
2713
2714 // Watch for connect complete (write is ready)
2715 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
2716 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
2717 {
2718 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2719 return errno;
2720 }
2721
2722 // Watch for incoming data
2723 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
2724 {
2725 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
2726 return errno;
2727 }
2728
2729 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
2730 {
2731 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
2732 return mStatus_UnknownErr;
2733 }
2734
2735 // We bind to the interface and all subsequent packets including the SYN will be sent out
2736 // on this interface
2737 //
2738 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
2739 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
2740 if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
2741 {
2742 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
2743 if (dst->type == mDNSAddrType_IPv4)
2744 {
2745 #ifdef IP_BOUND_IF
2746 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2747 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2748 #else
2749 (void)InterfaceID; // Unused
2750 (void)info; // Unused
2751 #endif
2752 }
2753 else
2754 {
2755 #ifdef IPV6_BOUND_IF
2756 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
2757 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
2758 #else
2759 (void)InterfaceID; // Unused
2760 (void)info; // Unused
2761 #endif
2762 }
2763 }
2764
2765 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
2766 // from which we can infer the destination address family. Hence we need to remember that here.
2767 // Instead of remembering the address family, we remember the right fd.
2768 sock->fd = *s;
2769 sock->kqEntry = k;
2770 // initiate connection wth peer
2771 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
2772 {
2773 if (errno == EINPROGRESS) return mStatus_ConnPending;
2774 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
2775 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
2776 else
2777 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
2778 return mStatus_ConnFailed;
2779 }
2780
2781 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
2782 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
2783 return err;
2784 }
2785
2786 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
2787 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
2788 {
2789 mStatus err = mStatus_NoError;
2790
2791 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
2792 if (!sock) return(mDNSNULL);
2793
2794 mDNSPlatformMemZero(sock, sizeof(*sock));
2795 sock->fd = fd;
2796 sock->flags = flags;
2797
2798 if (flags & kTCPSocketFlags_UseTLS)
2799 {
2800 #ifndef NO_SECURITYFRAMEWORK
2801 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
2802
2803 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
2804 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
2805
2806 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
2807 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
2808 #else
2809 err = mStatus_UnsupportedErr;
2810 #endif /* NO_SECURITYFRAMEWORK */
2811 }
2812 #ifndef NO_SECURITYFRAMEWORK
2813 exit:
2814 #endif
2815
2816 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
2817 return(sock);
2818 }
2819
2820 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
2821 {
2822 mDNSu16 port;
2823
2824 port = -1;
2825 if (sock)
2826 {
2827 port = sock->ss.port.NotAnInteger;
2828 }
2829 return port;
2830 }
2831
2832 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
2833 {
2834 if (ss->sktv4 != -1)
2835 {
2836 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
2837 ss->sktv4 = -1;
2838 }
2839 if (ss->sktv6 != -1)
2840 {
2841 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
2842 ss->sktv6 = -1;
2843 }
2844 if (ss->closeFlag) *ss->closeFlag = 1;
2845 }
2846
2847 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
2848 {
2849 if (sock)
2850 {
2851 #ifndef NO_SECURITYFRAMEWORK
2852 if (sock->tlsContext)
2853 {
2854 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
2855 {
2856 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
2857 // When we come back from SSLHandshake, we will notice that a close was here and
2858 // call this function again which will do the cleanup then.
2859 sock->handshake = handshake_to_be_closed;
2860 return;
2861 }
2862
2863 SSLClose(sock->tlsContext);
2864 CFRelease(sock->tlsContext);
2865 sock->tlsContext = NULL;
2866 }
2867 #endif /* NO_SECURITYFRAMEWORK */
2868 if (sock->ss.sktv4 != -1)
2869 shutdown(sock->ss.sktv4, 2);
2870 if (sock->ss.sktv6 != -1)
2871 shutdown(sock->ss.sktv6, 2);
2872 CloseSocketSet(&sock->ss);
2873 sock->fd = -1;
2874
2875 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
2876 }
2877 }
2878
2879 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
2880 {
2881 ssize_t nread = 0;
2882 *closed = mDNSfalse;
2883
2884 if (sock->flags & kTCPSocketFlags_UseTLS)
2885 {
2886 #ifndef NO_SECURITYFRAMEWORK
2887 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
2888 else if (sock->handshake == handshake_in_progress) return 0;
2889 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2890
2891 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
2892 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
2893 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
2894 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
2895 else if (err && err != errSSLWouldBlock)
2896 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
2897 #else
2898 nread = -1;
2899 *closed = mDNStrue;
2900 #endif /* NO_SECURITYFRAMEWORK */
2901 }
2902 else
2903 {
2904 static int CLOSEDcount = 0;
2905 static int EAGAINcount = 0;
2906 nread = recv(sock->fd, buf, buflen, 0);
2907
2908 if (nread > 0)
2909 {
2910 CLOSEDcount = 0;
2911 EAGAINcount = 0;
2912 } // On success, clear our error counters
2913 else if (nread == 0)
2914 {
2915 *closed = mDNStrue;
2916 if ((++CLOSEDcount % 1000) == 0)
2917 {
2918 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
2919 assert(CLOSEDcount < 1000);
2920 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
2921 // crash mDNSResponder using assert() and restart fresh. See advantages below:
2922 // 1.Better User Experience
2923 // 2.CrashLogs frequency can be monitored
2924 // 3.StackTrace can be used for more info
2925 }
2926 }
2927 // else nread is negative -- see what kind of error we got
2928 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
2929 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
2930 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
2931 {
2932 nread = 0;
2933 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
2934 }
2935 }
2936
2937 return nread;
2938 }
2939
2940 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
2941 {
2942 int nsent;
2943
2944 if (sock->flags & kTCPSocketFlags_UseTLS)
2945 {
2946 #ifndef NO_SECURITYFRAMEWORK
2947 size_t processed;
2948 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
2949 if (sock->handshake == handshake_in_progress) return 0;
2950 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
2951
2952 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
2953
2954 if (!err) nsent = (int) processed;
2955 else if (err == errSSLWouldBlock) nsent = 0;
2956 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
2957 #else
2958 nsent = -1;
2959 #endif /* NO_SECURITYFRAMEWORK */
2960 }
2961 else
2962 {
2963 nsent = send(sock->fd, msg, len, 0);
2964 if (nsent < 0)
2965 {
2966 if (errno == EAGAIN) nsent = 0;
2967 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
2968 }
2969 }
2970
2971 return nsent;
2972 }
2973
2974 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
2975 {
2976 return sock->fd;
2977 }
2978
2979 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
2980 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
2981 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
2982 {
2983 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
2984 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
2985 const int on = 1;
2986 const int twofivefive = 255;
2987 mStatus err = mStatus_NoError;
2988 char *errstr = mDNSNULL;
2989 const int mtu = 0;
2990
2991 cp->closeFlag = mDNSNULL;
2992
2993 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
2994 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
2995
2996 // set default traffic class
2997 setTrafficClass(skt, mDNSfalse);
2998
2999 #ifdef SO_RECV_ANYIF
3000 // Enable inbound packets on IFEF_AWDL interface.
3001 // Only done for multicast sockets, since we don't expect unicast socket operations
3002 // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
3003 if (mDNSSameIPPort(port, MulticastDNSPort))
3004 {
3005 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
3006 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
3007 }
3008 #endif // SO_RECV_ANYIF
3009
3010 // ... with a shared UDP port, if it's for multicast receiving
3011 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
3012 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
3013
3014 if (sa_family == AF_INET)
3015 {
3016 // We want to receive destination addresses
3017 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
3018 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
3019
3020 // We want to receive interface identifiers
3021 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
3022 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
3023
3024 // We want to receive packet TTL value so we can check it
3025 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
3026 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
3027
3028 // Send unicast packets with TTL 255
3029 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
3030 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
3031
3032 // And multicast packets with TTL 255 too
3033 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
3034 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
3035
3036 // And start listening for packets
3037 struct sockaddr_in listening_sockaddr;
3038 listening_sockaddr.sin_family = AF_INET;
3039 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3040 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
3041 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
3042 if (err) { errstr = "bind"; goto fail; }
3043 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
3044 }
3045 else if (sa_family == AF_INET6)
3046 {
3047 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
3048 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; }
3049
3050 // We want to receive destination addresses and receive interface identifiers
3051 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
3052 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
3053
3054 // We want to receive packet hop count value so we can check it
3055 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
3056 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
3057
3058 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
3059 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
3060 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
3061 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
3062
3063 // Send unicast packets with TTL 255
3064 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
3065 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
3066
3067 // And multicast packets with TTL 255 too
3068 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
3069 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
3070
3071 // Want to receive our own packets
3072 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
3073 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
3074
3075 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
3076 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
3077 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
3078 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
3079 skt, err, errno, strerror(errno));
3080
3081 // And start listening for packets
3082 struct sockaddr_in6 listening_sockaddr6;
3083 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
3084 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
3085 listening_sockaddr6.sin6_family = AF_INET6;
3086 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
3087 listening_sockaddr6.sin6_flowinfo = 0;
3088 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
3089 listening_sockaddr6.sin6_scope_id = 0;
3090 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
3091 if (err) { errstr = "bind"; goto fail; }
3092 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
3093 }
3094
3095 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
3096 fcntl(skt, F_SETFD, 1); // set close-on-exec
3097 *s = skt;
3098 k->KQcallback = myKQSocketCallBack;
3099 k->KQcontext = cp;
3100 k->KQtask = "UDP packet reception";
3101 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3102 k->readSource = mDNSNULL;
3103 k->writeSource = mDNSNULL;
3104 k->fdClosed = mDNSfalse;
3105 #endif
3106 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
3107
3108 return(err);
3109
3110 fail:
3111 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
3112 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
3113 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
3114
3115 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
3116 if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
3117 {
3118 err = EADDRINUSE;
3119 if (mDNSSameIPPort(port, MulticastDNSPort))
3120 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
3121 "Congratulations, you've reproduced an elusive bug.\r"
3122 "Please contact the current assignee of <rdar://problem/3814904>.\r"
3123 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
3124 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
3125 }
3126
3127 mDNSPlatformCloseFD(k, skt);
3128 return(err);
3129 }
3130
3131 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
3132 {
3133 mStatus err;
3134 mDNSIPPort port = requestedport;
3135 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
3136 int i = 10000; // Try at most 10000 times to get a unique random port
3137 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
3138 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
3139 mDNSPlatformMemZero(p, sizeof(UDPSocket));
3140 p->ss.port = zeroIPPort;
3141 p->ss.m = m;
3142 p->ss.sktv4 = -1;
3143 p->ss.sktv6 = -1;
3144 p->ss.proxy = mDNSfalse;
3145
3146 do
3147 {
3148 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
3149 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
3150 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
3151 if (!err)
3152 {
3153 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
3154 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
3155 }
3156 i--;
3157 } while (err == EADDRINUSE && randomizePort && i);
3158
3159 if (err)
3160 {
3161 // In customer builds we don't want to log failures with port 5351, because this is a known issue
3162 // of failing to bind to this port when Internet Sharing has already bound to it
3163 // We also don't want to log about port 5350, due to a known bug when some other
3164 // process is bound to it.
3165 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
3166 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3167 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
3168 freeL("UDPSocket", p);
3169 return(mDNSNULL);
3170 }
3171 return(p);
3172 }
3173
3174 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
3175 {
3176 CloseSocketSet(&sock->ss);
3177 freeL("UDPSocket", sock);
3178 }
3179
3180 #if COMPILER_LIKES_PRAGMA_MARK
3181 #pragma mark -
3182 #pragma mark - BPF Raw packet sending/receiving
3183 #endif
3184
3185 #if APPLE_OSX_mDNSResponder
3186
3187 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
3188 {
3189 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
3190 NetworkInterfaceInfoOSX *info;
3191
3192 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
3193 if (info == NULL)
3194 {
3195 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
3196 return;
3197 }
3198 if (info->BPF_fd < 0)
3199 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
3200 else
3201 {
3202 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
3203 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
3204 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
3205 }
3206 }
3207
3208 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
3209 {
3210 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
3211 NetworkInterfaceInfoOSX *info;
3212 info = IfindexToInterfaceInfoOSX(m, InterfaceID);
3213 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
3214 // Manually inject an entry into our local ARP cache.
3215 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
3216 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL))
3217 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3218 else
3219 {
3220 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
3221 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
3222 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
3223 }
3224 }
3225
3226 mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
3227 {
3228 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
3229 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3230 // close will happen in the cancel handler
3231 dispatch_source_cancel(i->BPF_source);
3232 #else
3233
3234 // Note: MUST NOT close() the underlying native BSD sockets.
3235 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
3236 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
3237 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3238 CFRelease(i->BPF_rls);
3239 CFSocketInvalidate(i->BPF_cfs);
3240 CFRelease(i->BPF_cfs);
3241 #endif
3242 i->BPF_fd = -1;
3243 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
3244 }
3245
3246 mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
3247 {
3248 KQueueLock(info->m);
3249
3250 // 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
3251 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
3252 if (info->BPF_fd < 0) goto exit;
3253
3254 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
3255 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
3256 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
3257 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
3258
3259 if (n<0)
3260 {
3261 /* <rdar://problem/10287386>
3262 * sometimes there can be a race condition btw when the bpf socket
3263 * gets data and the callback get scheduled and when we call BIOCSETF (which
3264 * clears the socket). this can cause the read to hang for a really long time
3265 * and effectively prevent us from responding to requests for long periods of time.
3266 * to prevent this make the socket non blocking and just bail if we dont get anything
3267 */
3268 if (errno == EAGAIN)
3269 {
3270 LogMsg("bpf_callback got EAGAIN bailing");
3271 goto exit;
3272 }
3273 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
3274 CloseBPF(info);
3275 goto exit;
3276 }
3277
3278 while (ptr < end)
3279 {
3280 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
3281 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
3282 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
3283 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
3284 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
3285 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
3286 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
3287 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
3288 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
3289 }
3290 exit:
3291 KQueueUnlock(info->m, "bpf_callback");
3292 }
3293 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3294 mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
3295 {
3296 bpf_callback_common(info);
3297 }
3298 #else
3299 mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
3300 {
3301 (void)cfs;
3302 (void)CallBackType;
3303 (void)address;
3304 (void)data;
3305 bpf_callback_common((NetworkInterfaceInfoOSX *)context);
3306 }
3307 #endif
3308
3309 mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
3310 {
3311 LogMsg("mDNSPlatformSendKeepalive called\n");
3312 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
3313 }
3314
3315 mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
3316 {
3317 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3318 LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
3319 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
3320 return KERN_SUCCESS;
3321 }
3322
3323 mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
3324 {
3325 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3326
3327 mDNSGetRemoteMAC(m, family, raddr->ip.v6.b);
3328 return KERN_SUCCESS;
3329 }
3330
3331 mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
3332 {
3333 mDNSs32 intfid;
3334 mDNSs32 error = 0;
3335 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
3336
3337 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);
3338 if (error != KERN_SUCCESS)
3339 {
3340 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
3341 return error;
3342 }
3343 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
3344 return error;
3345 }
3346
3347 #define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
3348
3349 mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
3350 {
3351 int numv4 = 0, numv6 = 0;
3352 AuthRecord *rr;
3353
3354 for (rr = m->ResourceRecords; rr; rr=rr->next)
3355 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3356 {
3357 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
3358 numv4++;
3359 }
3360
3361 for (rr = m->ResourceRecords; rr; rr=rr->next)
3362 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3363 {
3364 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
3365 numv6++;
3366 }
3367
3368 if (p4) *p4 = numv4;
3369 if (p6) *p6 = numv6;
3370 return(numv4 + numv6);
3371 }
3372
3373 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
3374 {
3375 NetworkInterfaceInfoOSX *x;
3376
3377 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
3378 for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
3379
3380 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
3381
3382 #define MAX_BPF_ADDRS 250
3383 int numv4 = 0, numv6 = 0;
3384
3385 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
3386 {
3387 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
3388 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
3389 numv6 = MAX_BPF_ADDRS - numv4;
3390 }
3391
3392 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
3393
3394 // Caution: This is a static structure, so we need to be careful that any modifications we make to it
3395 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
3396 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
3397 {
3398 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
3399
3400 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
3401 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
3402
3403 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
3404
3405 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
3406 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
3407 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
3408 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
3409
3410 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
3411 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
3412 };
3413
3414 struct bpf_insn *pc = &filter[9];
3415 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
3416 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
3417 struct bpf_insn *ret4 = fail + 1;
3418 struct bpf_insn *ret6 = ret4 + 4;
3419
3420 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
3421
3422 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
3423
3424 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
3425 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)
3426 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
3427 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
3428
3429 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
3430
3431 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
3432 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
3433
3434 // BPF Byte-Order Note
3435 // The BPF API designers apparently thought that programmers would not be smart enough to use htons
3436 // and htonl correctly to convert numeric values to network byte order on little-endian machines,
3437 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
3438 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
3439 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
3440 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
3441 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
3442 // so that when the BPF API goes through and swaps them all, they end up back as they should be.
3443 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
3444 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
3445
3446 // IPSEC capture size notes:
3447 // 8 bytes UDP header
3448 // 4 bytes Non-ESP Marker
3449 // 28 bytes IKE Header
3450 // --
3451 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
3452
3453 AuthRecord *rr;
3454 for (rr = m->ResourceRecords; rr; rr=rr->next)
3455 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
3456 {
3457 mDNSv4Addr a = rr->AddressProxy.ip.v4;
3458 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3459 BPF_SetOffset(pc, jt, ret4);
3460 pc->jf = 0;
3461 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];
3462 pc++;
3463 }
3464 *pc++ = rf;
3465
3466 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
3467 *pc++ = g6; // chk6 points here
3468
3469 // First cancel any previous ND group memberships we had, then create a fresh socket
3470 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
3471 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
3472
3473 for (rr = m->ResourceRecords; rr; rr=rr->next)
3474 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
3475 {
3476 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
3477 pc->code = BPF_JMP + BPF_JEQ + BPF_K;
3478 BPF_SetOffset(pc, jt, ret6);
3479 pc->jf = 0;
3480 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];
3481 pc++;
3482
3483 struct ipv6_mreq i6mr;
3484 i6mr.ipv6mr_interface = x->scope_id;
3485 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
3486 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
3487 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
3488 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
3489
3490 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
3491 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
3492 if (err < 0 && (errno != EADDRNOTAVAIL))
3493 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3494
3495 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
3496 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
3497 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
3498
3499 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
3500 }
3501
3502 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
3503 *pc++ = rf; // fail points here
3504
3505 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
3506 *pc++ = r4a; // ret4 points here
3507 *pc++ = r4b;
3508 *pc++ = r4c;
3509 *pc++ = r4d;
3510
3511 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
3512 *pc++ = r6a; // ret6 points here
3513
3514 struct bpf_program prog = { pc - filter, filter };
3515
3516 #if 0
3517 // For debugging BPF filter program
3518 unsigned int q;
3519 for (q=0; q<prog.bf_len; q++)
3520 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);
3521 #endif
3522
3523 if (!numv4 && !numv6)
3524 {
3525 LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
3526 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
3527 // Schedule check to see if we can close this BPF_fd now
3528 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
3529 // prog.bf_len = 0; This seems to panic the kernel
3530 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
3531 }
3532
3533 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
3534 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
3535 }
3536
3537 mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
3538 {
3539 mDNS_Lock(m);
3540
3541 NetworkInterfaceInfoOSX *i;
3542 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
3543 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
3544 else
3545 {
3546 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
3547
3548 struct bpf_version v;
3549 if (ioctl(fd, BIOCVERSION, &v) < 0)
3550 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3551 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
3552 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
3553 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
3554
3555 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
3556 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3557
3558 if (i->BPF_len > sizeof(m->imsg))
3559 {
3560 i->BPF_len = sizeof(m->imsg);
3561 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
3562 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3563 else
3564 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
3565 }
3566
3567 static const u_int opt_one = 1;
3568 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
3569 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3570
3571 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
3572 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3573
3574 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
3575 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3576
3577 /* <rdar://problem/10287386>
3578 * make socket non blocking see comments in bpf_callback_common for more info
3579 */
3580 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
3581 {
3582 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
3583 }
3584
3585 struct ifreq ifr;
3586 mDNSPlatformMemZero(&ifr, sizeof(ifr));
3587 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3588 if (ioctl(fd, BIOCSETIF, &ifr) < 0)
3589 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
3590 else
3591 {
3592 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
3593 i->BPF_fd = fd;
3594 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
3595 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
3596 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
3597 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
3598 dispatch_resume(i->BPF_source);
3599 #else
3600 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
3601 i->BPF_fd = fd;
3602 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
3603 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
3604 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
3605 #endif
3606 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
3607 }
3608 }
3609
3610 mDNS_Unlock(m);
3611 }
3612
3613 #endif // APPLE_OSX_mDNSResponder
3614
3615 #if COMPILER_LIKES_PRAGMA_MARK
3616 #pragma mark -
3617 #pragma mark - Key Management
3618 #endif
3619
3620 #ifndef NO_SECURITYFRAMEWORK
3621 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
3622 {
3623 CFMutableArrayRef certChain = NULL;
3624 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
3625 SecCertificateRef cert;
3626 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
3627 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
3628 else
3629 {
3630 SecPolicySearchRef searchRef;
3631 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
3632 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
3633 else
3634 {
3635 SecPolicyRef policy;
3636 err = SecPolicySearchCopyNext(searchRef, &policy);
3637 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
3638 else
3639 {
3640 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
3641 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
3642 else
3643 {
3644 SecTrustRef trust;
3645 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
3646 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
3647 else
3648 {
3649 err = SecTrustEvaluate(trust, NULL);
3650 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
3651 else
3652 {
3653 CFArrayRef rawCertChain;
3654 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
3655 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
3656 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
3657 else
3658 {
3659 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
3660 if (!certChain) LogMsg("getCertChain: certChain is NULL");
3661 else
3662 {
3663 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
3664 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
3665 CFArraySetValueAtIndex(certChain, 0, identity);
3666 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
3667 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
3668 }
3669 CFRelease(rawCertChain);
3670 // Do not free statusChain:
3671 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
3672 // certChain: Call the CFRelease function to release this object when you are finished with it.
3673 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
3674 }
3675 }
3676 CFRelease(trust);
3677 }
3678 CFRelease(wrappedCert);
3679 }
3680 CFRelease(policy);
3681 }
3682 CFRelease(searchRef);
3683 }
3684 CFRelease(cert);
3685 }
3686 return certChain;
3687 }
3688 #endif /* NO_SECURITYFRAMEWORK */
3689
3690 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
3691 {
3692 #ifdef NO_SECURITYFRAMEWORK
3693 return mStatus_UnsupportedErr;
3694 #else
3695 SecIdentityRef identity = nil;
3696 SecIdentitySearchRef srchRef = nil;
3697 OSStatus err;
3698
3699 // search for "any" identity matching specified key use
3700 // In this app, we expect there to be exactly one
3701 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
3702 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
3703
3704 err = SecIdentitySearchCopyNext(srchRef, &identity);
3705 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
3706
3707 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3708 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
3709
3710 // Found one. Call getCertChain to create the correct certificate chain.
3711 ServerCerts = GetCertChain(identity);
3712 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
3713
3714 return mStatus_NoError;
3715 #endif /* NO_SECURITYFRAMEWORK */
3716 }
3717
3718 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
3719 {
3720 #ifndef NO_SECURITYFRAMEWORK
3721 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
3722 #endif /* NO_SECURITYFRAMEWORK */
3723 }
3724
3725 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
3726 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
3727 {
3728 CFStringEncoding encoding = kCFStringEncodingUTF8;
3729 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
3730 if (cfs)
3731 {
3732 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3733 CFRelease(cfs);
3734 }
3735 }
3736
3737 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
3738 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
3739 {
3740 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
3741 if (cfs)
3742 {
3743 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
3744 CFRelease(cfs);
3745 }
3746 }
3747
3748 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
3749 {
3750 mDNSs32 val;
3751 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
3752 if (!state) return mDNSfalse;
3753 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
3754 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
3755 return val ? mDNStrue : mDNSfalse;
3756 }
3757
3758 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
3759 {
3760 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
3761
3762 if (sa->sa_family == AF_INET)
3763 {
3764 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
3765 ip->type = mDNSAddrType_IPv4;
3766 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
3767 return(mStatus_NoError);
3768 }
3769
3770 if (sa->sa_family == AF_INET6)
3771 {
3772 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
3773 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
3774 // value into the second word of the IPv6 link-local address, so they can just
3775 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
3776 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
3777 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
3778 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
3779 ip->type = mDNSAddrType_IPv6;
3780 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
3781 return(mStatus_NoError);
3782 }
3783
3784 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
3785 return(mStatus_Invalid);
3786 }
3787
3788 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
3789 {
3790 mDNSEthAddr eth = zeroEthAddr;
3791 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
3792 if (!store)
3793 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3794 else
3795 {
3796 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
3797 if (entityname)
3798 {
3799 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
3800 if (dict)
3801 {
3802 CFRange range = { 0, 6 }; // Offset, length
3803 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
3804 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
3805 CFRelease(dict);
3806 }
3807 CFRelease(entityname);
3808 }
3809 CFRelease(store);
3810 }
3811 return(eth);
3812 }
3813
3814 mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
3815 {
3816 struct ifaddrs *ifa;
3817 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
3818 if (ifa->ifa_addr->sa_family == AF_LINK)
3819 {
3820 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
3821 if (sdl->sdl_index == ifindex)
3822 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
3823 }
3824 *eth = zeroEthAddr;
3825 return -1;
3826 }
3827
3828 #ifndef SIOCGIFWAKEFLAGS
3829 #define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
3830 #endif
3831
3832 #ifndef IF_WAKE_ON_MAGIC_PACKET
3833 #define IF_WAKE_ON_MAGIC_PACKET 0x01
3834 #endif
3835
3836 #ifndef ifr_wake_flags
3837 #define ifr_wake_flags ifr_ifru.ifru_intval
3838 #endif
3839
3840 mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
3841 {
3842 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
3843 if (!service)
3844 {
3845 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
3846 return mDNSfalse;
3847 }
3848
3849 io_name_t n1, n2;
3850 IOObjectGetClass(service, n1);
3851 io_object_t parent;
3852 mDNSBool ret = mDNSfalse;
3853 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
3854 if (kr == KERN_SUCCESS)
3855 {
3856 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
3857 IOObjectGetClass(parent, n2);
3858 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
3859 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
3860 if (!ref)
3861 {
3862 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
3863 ret = mDNSfalse;
3864 }
3865 else
3866 {
3867 ret = mDNStrue;
3868 CFRelease(ref);
3869 }
3870 IOObjectRelease(parent);
3871 CFRelease(keystr);
3872 }
3873 else
3874 {
3875 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
3876 ret = mDNSfalse;
3877 }
3878 IOObjectRelease(service);
3879 return ret;
3880 }
3881
3882
3883 mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
3884 {
3885 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
3886 }
3887
3888 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
3889 {
3890 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
3891 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
3892
3893 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
3894 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
3895 // when the power source is not AC Power.
3896 if (InterfaceSupportsKeepAlive(&i->ifinfo))
3897 {
3898 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
3899 return mDNStrue;
3900 }
3901
3902 int s = socket(AF_INET, SOCK_DGRAM, 0);
3903 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
3904
3905 struct ifreq ifr;
3906 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
3907 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
3908 {
3909 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
3910 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
3911 // error code is being returned from the kernel, we need to use the kernel version.
3912 #define KERNEL_EOPNOTSUPP 102
3913 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
3914 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
3915 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
3916 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
3917 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
3918 }
3919
3920 close(s);
3921
3922 // 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
3923
3924 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
3925
3926 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
3927 }
3928
3929 mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
3930 {
3931 int sockFD;
3932 struct ifreq ifr;
3933
3934 sockFD = socket(AF_INET, SOCK_DGRAM, 0);
3935 if (sockFD < 0)
3936 {
3937 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
3938 return 0;
3939 }
3940
3941 ifr.ifr_addr.sa_family = AF_INET;
3942 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
3943
3944 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
3945 {
3946 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
3947 ifr.ifr_eflags = 0;
3948 }
3949 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
3950
3951 close(sockFD);
3952 return ifr.ifr_eflags;
3953 }
3954
3955 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
3956 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
3957 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
3958 // (e.g. sa_family not AF_INET or AF_INET6)
3959 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
3960 {
3961 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
3962 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
3963 u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
3964
3965 mDNSAddr ip, mask;
3966 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
3967 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
3968
3969 NetworkInterfaceInfoOSX **p;
3970 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
3971 if (scope_id == (*p)->scope_id &&
3972 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
3973 mDNSSameEthAddress(&bssid, &(*p)->BSSID))
3974 {
3975 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);
3976 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
3977 // When interfaces are created with same MAC address, kernel resurrects the old interface.
3978 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
3979 // we get the corresponding name for the interface index on which the packet was received and check against
3980 // the InterfaceList for a matching name. So, keep the name in sync
3981 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
3982 (*p)->Exists = mDNStrue;
3983 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
3984 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
3985
3986 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
3987 // we may need to start or stop or sleep proxy browse operation
3988 const mDNSBool NetWake = NetWakeInterface(*p);
3989 if ((*p)->ifinfo.NetWake != NetWake)
3990 {
3991 (*p)->ifinfo.NetWake = NetWake;
3992 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
3993 // If this interface is not already registered (i.e. it's a dormant interface we had in our list
3994 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
3995 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
3996 if ((*p)->Registered)
3997 {
3998 mDNS_Lock(m);
3999 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
4000 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
4001 mDNS_Unlock(m);
4002 }
4003 }
4004 // Reset the flag if it has changed this time.
4005 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4006
4007 return(*p);
4008 }
4009
4010 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
4011 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
4012 if (!i) return(mDNSNULL);
4013 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
4014 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
4015 i->ifinfo.ip = ip;
4016 i->ifinfo.mask = mask;
4017 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
4018 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
4019 // We can be configured to disable multicast advertisement, but we want to to support
4020 // local-only services, which need a loopback address record.
4021 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
4022 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
4023 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
4024 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
4025
4026 i->next = mDNSNULL;
4027 i->m = m;
4028 i->Exists = mDNStrue;
4029 i->Flashing = mDNSfalse;
4030 i->Occulting = mDNSfalse;
4031 i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
4032 i->DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse;
4033 if (eflags & IFEF_AWDL)
4034 {
4035 AWDLInterfaceID = i->ifinfo.InterfaceID;
4036 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
4037 }
4038 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
4039 i->LastSeen = utc;
4040 i->ifa_flags = ifa->ifa_flags;
4041 i->scope_id = scope_id;
4042 i->BSSID = bssid;
4043 i->sa_family = ifa->ifa_addr->sa_family;
4044 i->BPF_fd = -1;
4045 i->BPF_mcfd = -1;
4046 i->BPF_len = 0;
4047 i->Registered = mDNSNULL;
4048
4049 // Do this AFTER i->BSSID has been set up
4050 i->ifinfo.NetWake = NetWakeInterface(i);
4051 GetMAC(&i->ifinfo.MAC, scope_id);
4052 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
4053 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
4054
4055 *p = i;
4056 return(i);
4057 }
4058
4059 #if APPLE_OSX_mDNSResponder
4060
4061 #if COMPILER_LIKES_PRAGMA_MARK
4062 #pragma mark -
4063 #pragma mark - AutoTunnel
4064 #endif
4065
4066 #define kRacoonPort 4500
4067
4068 static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
4069
4070 #ifndef NO_SECURITYFRAMEWORK
4071
4072 static CFMutableDictionaryRef domainStatusDict = NULL;
4073
4074 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
4075 {
4076 if (q->LongLived)
4077 {
4078 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
4079 return mStatus_NoSuchRecord;
4080 else if (q->state == LLQ_Poll)
4081 return mStatus_PollingMode;
4082 else if (q->state != LLQ_Established && !q->DuplicateOf)
4083 return mStatus_TransientErr;
4084 }
4085
4086 return mStatus_NoError;
4087 }
4088
4089 mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4090 {
4091 mStatus status = mStatus_NoError;
4092 DNSQuestion* q, *worst_q = mDNSNULL;
4093 for (q = m->Questions; q; q=q->next)
4094 if (q->AuthInfo == info)
4095 {
4096 mStatus newStatus = CheckQuestionForStatus(q);
4097 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
4098 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
4099 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
4100 }
4101
4102 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
4103 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
4104 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
4105 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
4106 return status;
4107 }
4108
4109 mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
4110 {
4111 AuthRecord *r;
4112
4113 if (info->deltime) return mStatus_NoError;
4114 for (r = m->ResourceRecords; r; r = r->next)
4115 {
4116 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
4117 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
4118 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
4119 // has already checked
4120 const domainname *n = r->resrec.name;
4121 while (n->c[0])
4122 {
4123 DomainAuthInfo *ptr;
4124 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
4125 if (SameDomainName(&ptr->domain, n))
4126 {
4127 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
4128 {
4129 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
4130 return r->updateError;
4131 }
4132 }
4133 n = (const domainname *)(n->c + 1 + n->c[0]);
4134 }
4135 }
4136 return mStatus_NoError;
4137 }
4138
4139 #endif // ndef NO_SECURITYFRAMEWORK
4140
4141 // MUST be called with lock held
4142 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
4143 {
4144 #ifdef NO_SECURITYFRAMEWORK
4145 (void) m;
4146 (void)info;
4147 #else
4148 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
4149 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
4150 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
4151 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
4152 char buffer[1024];
4153 mDNSu32 buflen = 0;
4154 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4155 CFStringRef domain = NULL;
4156 CFStringRef tmp = NULL;
4157 CFNumberRef num = NULL;
4158 mStatus status = mStatus_NoError;
4159 mStatus llqStatus = mStatus_NoError;
4160 char llqBuffer[1024];
4161
4162 mDNS_CheckLock(m);
4163
4164 if (!domainStatusDict)
4165 {
4166 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4167 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
4168 }
4169
4170 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
4171
4172 buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
4173 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4174 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
4175
4176 if (info->deltime)
4177 {
4178 if (CFDictionaryContainsKey(domainStatusDict, domain))
4179 {
4180 CFDictionaryRemoveValue(domainStatusDict, domain);
4181 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4182 }
4183 CFRelease(domain);
4184 CFRelease(dict);
4185
4186 return;
4187 }
4188
4189 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
4190 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4191 if (!tmp)
4192 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
4193 else
4194 {
4195 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
4196 CFRelease(tmp);
4197 }
4198
4199 if (llq)
4200 {
4201 mDNSu32 port = mDNSVal16(llq->ExternalPort);
4202
4203 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4204 if (!num)
4205 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
4206 else
4207 {
4208 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
4209 CFRelease(num);
4210 }
4211
4212 if (llq->Result)
4213 {
4214 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
4215 if (!num)
4216 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
4217 else
4218 {
4219 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
4220 CFRelease(num);
4221 }
4222 }
4223 }
4224
4225 if (tun)
4226 {
4227 mDNSu32 port = mDNSVal16(tun->ExternalPort);
4228
4229 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
4230 if (!num)
4231 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
4232 else
4233 {
4234 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
4235 CFRelease(num);
4236 }
4237
4238 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
4239 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4240 if (!tmp)
4241 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
4242 else
4243 {
4244 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
4245 CFRelease(tmp);
4246 }
4247
4248 if (tun->Result)
4249 {
4250 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
4251 if (!num)
4252 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
4253 else
4254 {
4255 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
4256 CFRelease(num);
4257 }
4258 }
4259 }
4260 if (tun || llq)
4261 {
4262 mDNSu32 code = m->LastNATMapResultCode;
4263
4264 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
4265 if (!num)
4266 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
4267 else
4268 {
4269 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
4270 CFRelease(num);
4271 }
4272 }
4273
4274 mDNS_snprintf(buffer, sizeof(buffer), "Success");
4275 llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
4276 status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
4277
4278 // If we have a bad signature error updating a RR, it overrides any error as it needs to be
4279 // reported so that it can be fixed automatically (or the user needs to be notified)
4280 if (status != mStatus_NoError)
4281 {
4282 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
4283 }
4284 else if (m->Router.type == mDNSAddrType_None)
4285 {
4286 status = mStatus_NoRouter;
4287 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
4288 }
4289 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
4290 {
4291 status = mStatus_NoRouter;
4292 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
4293 }
4294 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
4295 {
4296 status = mStatus_ServiceNotRunning;
4297 mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
4298 }
4299 else if (!llq && !tun)
4300 {
4301 status = mStatus_NotInitializedErr;
4302 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
4303 }
4304 else if (llqStatus == mStatus_NoSuchRecord)
4305 {
4306 status = llqStatus;
4307 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4308 }
4309 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
4310 {
4311 status = mStatus_DoubleNAT;
4312 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
4313 }
4314 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
4315 (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
4316 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
4317 {
4318 status = mStatus_NATPortMappingDisabled;
4319 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
4320 }
4321 else if ((llq && llq->Result) || (tun && tun->Result))
4322 {
4323 status = mStatus_NATTraversal;
4324 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
4325 }
4326 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
4327 {
4328 status = mStatus_NATTraversal;
4329 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
4330 }
4331 else
4332 {
4333 status = llqStatus;
4334 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
4335 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
4336 }
4337
4338 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
4339 if (!num)
4340 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
4341 else
4342 {
4343 CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
4344 CFRelease(num);
4345 }
4346
4347 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
4348 if (!tmp)
4349 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
4350 else
4351 {
4352 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
4353 CFRelease(tmp);
4354 }
4355
4356 if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
4357 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
4358 {
4359 CFDictionarySetValue(domainStatusDict, domain, dict);
4360 if (!m->ShutdownTime)
4361 {
4362 static char statusBuf[16];
4363 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
4364 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
4365 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
4366 }
4367 }
4368
4369 CFRelease(domain);
4370 CFRelease(dict);
4371
4372 debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
4373 #endif // def NO_SECURITYFRAMEWORK
4374 }
4375
4376 // MUST be called with lock held
4377 mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
4378 {
4379 #ifdef NO_SECURITYFRAMEWORK
4380 (void) m;
4381 #else
4382 mDNS_CheckLock(m);
4383 DomainAuthInfo* info;
4384 for (info = m->AuthInfoList; info; info = info->next)
4385 if (info->AutoTunnel && !info->deltime)
4386 UpdateAutoTunnelDomainStatus(m, info);
4387 #endif // def NO_SECURITYFRAMEWORK
4388 }
4389
4390 mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
4391 {
4392 DomainAuthInfo *info;
4393
4394 for (info = m->AuthInfoList; info; info = info->next)
4395 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
4396 break;
4397
4398 if (info != AnonymousRacoonConfig)
4399 {
4400 AnonymousRacoonConfig = info;
4401 // Create or revert configuration file, and start (or SIGHUP) Racoon
4402 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
4403 }
4404 }
4405
4406 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
4407
4408 // Caller must hold the lock
4409 mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
4410 {
4411 mDNS_CheckLock(m);
4412
4413 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
4414
4415 if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
4416 {
4417 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
4418 if (err)
4419 {
4420 record->resrec.RecordType = kDNSRecordTypeUnregistered;
4421 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
4422 return mDNSfalse;
4423 }
4424 else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
4425 }
4426 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
4427
4428 return mDNStrue;
4429 }
4430
4431 // Caller must hold the lock
4432 mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4433 {
4434 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
4435 {
4436 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4437 m->NextSRVUpdate = NonZeroTime(m->timenow);
4438 }
4439 }
4440
4441 // Caller must hold the lock
4442 mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
4443 {
4444 mStatus err;
4445 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
4446
4447 mDNS_CheckLock(m);
4448
4449 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
4450 {
4451 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
4452 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
4453 DeregisterAutoTunnelHostRecord(m, info);
4454 }
4455 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
4456 {
4457 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4458 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4459 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
4460 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
4461 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
4462 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
4463 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
4464
4465 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
4466 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
4467 else
4468 {
4469 // Make sure we trigger the registration of all SRV records in regState_NoTarget again
4470 m->NextSRVUpdate = NonZeroTime(m->timenow);
4471 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
4472 }
4473 }
4474 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
4475 }
4476
4477 // Caller must hold the lock
4478 mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4479 {
4480 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
4481
4482 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
4483 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
4484 UpdateAutoTunnelHostRecord(m, info);
4485 }
4486
4487 // Caller must hold the lock
4488 mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
4489 {
4490 mDNS_CheckLock(m);
4491
4492 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
4493 {
4494 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);
4495 DeregisterAutoTunnelServiceRecords(m, info);
4496 }
4497 else
4498 {
4499 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
4500 {
4501 // 1. Set up our address record for the external tunnel address
4502 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
4503 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
4504 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4505 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
4506 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
4507 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
4508 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
4509 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
4510
4511 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
4512 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
4513 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
4514 }
4515 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
4516
4517 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
4518 {
4519 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
4520 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
4521 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4522 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
4523 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
4524 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
4525 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
4526 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
4527 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
4528 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
4529 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
4530
4531 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
4532 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
4533 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
4534 }
4535 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
4536
4537 UpdateAutoTunnelHostRecord(m, info);
4538
4539 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
4540 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
4541 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4542
4543 }
4544 }
4545
4546 // Caller must hold the lock
4547 mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4548 {
4549 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
4550 }
4551
4552 // Caller must hold the lock
4553 mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
4554 {
4555 mDNS_CheckLock(m);
4556
4557 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
4558 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4559 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
4560 {
4561 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4562 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
4563
4564 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
4565 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
4566
4567 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
4568 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
4569 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
4570 }
4571 else
4572 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
4573 }
4574
4575 // Caller must hold the lock
4576 mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4577 {
4578 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
4579
4580 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
4581 UpdateAutoTunnelHostRecord(m, info);
4582 UpdateAutoTunnelDomainStatus(m, info);
4583 }
4584
4585 // Caller must hold the lock
4586 mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
4587 {
4588 mDNS_CheckLock(m);
4589
4590 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
4591 DeregisterAutoTunnel6Record(m, info);
4592 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
4593 {
4594 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
4595 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
4596 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
4597 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
4598 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
4599 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
4600 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
4601
4602 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
4603 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
4604 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
4605
4606 UpdateAutoTunnelHostRecord(m, info);
4607
4608 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
4609 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
4610 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
4611
4612 }
4613 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
4614 }
4615
4616 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
4617 {
4618 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
4619 if (result == mStatus_MemFree)
4620 {
4621 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
4622
4623 mDNS_Lock(m);
4624
4625 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
4626 if (rr == &info->AutoTunnelHostRecord)
4627 {
4628 rr->namestorage.c[0] = 0;
4629 m->NextSRVUpdate = NonZeroTime(m->timenow);
4630 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4631 }
4632 if (m->ShutdownTime)
4633 {
4634 LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
4635 mDNS_Unlock(m);
4636 return;
4637 }
4638 if (rr == &info->AutoTunnelHostRecord)
4639 {
4640 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
4641 UpdateAutoTunnelHostRecord(m,info);
4642 }
4643 else if (rr == &info->AutoTunnelDeviceInfo)
4644 {
4645 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
4646 UpdateAutoTunnelDeviceInfoRecord(m,info);
4647 }
4648 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
4649 {
4650 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
4651 UpdateAutoTunnelServiceRecords(m,info);
4652 }
4653 else if (rr == &info->AutoTunnel6Record)
4654 {
4655 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
4656 UpdateAutoTunnel6Record(m,info);
4657 }
4658
4659 mDNS_Unlock(m);
4660 }
4661 }
4662
4663 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
4664 {
4665 DomainAuthInfo *info;
4666
4667 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
4668 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
4669
4670 mDNS_Lock(m);
4671
4672 m->NextSRVUpdate = NonZeroTime(m->timenow);
4673 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
4674
4675 for (info = m->AuthInfoList; info; info = info->next)
4676 if (info->AutoTunnel)
4677 UpdateAutoTunnelServiceRecords(m, info);
4678
4679 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
4680
4681 UpdateAutoTunnelDomainStatuses(m);
4682
4683 mDNS_Unlock(m);
4684 }
4685
4686 mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
4687 {
4688 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
4689
4690 mDNS_Lock(m);
4691 // We forcibly deregister the records that are based on the hostname.
4692 // When deregistration of each completes, the MemFree callback will make the
4693 // appropriate Update* call to use the new name to reregister.
4694 DeregisterAutoTunnelHostRecord(m, info);
4695 DeregisterAutoTunnelDeviceInfoRecord(m, info);
4696 DeregisterAutoTunnelServiceRecords(m, info);
4697 DeregisterAutoTunnel6Record(m, info);
4698 m->NextSRVUpdate = NonZeroTime(m->timenow);
4699 mDNS_Unlock(m);
4700 }
4701
4702 // Must be called with the lock held
4703 mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
4704 {
4705 if (info->deltime) return;
4706
4707 if (info->AutoTunnelServiceStarted)
4708 {
4709 // On wake from sleep, this function will be called when determining SRV targets,
4710 // and needs to re-register the host record for the target to be set correctly
4711 UpdateAutoTunnelHostRecord(m, info);
4712 return;
4713 }
4714
4715 info->AutoTunnelServiceStarted = mDNStrue;
4716
4717 // Now that we have a service in this domain, we need to try to register the
4718 // AutoTunnel records, because the relay connection & NAT-T may have already been
4719 // started for another domain. If the relay connection is not up or the NAT-T has not
4720 // yet succeeded, the Update* functions are smart enough to not register the records.
4721 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
4722 // decide whether to register the AutoTunnel records in the calls below.
4723 UpdateAutoTunnelServiceRecords(m, info);
4724 UpdateAutoTunnel6Record(m, info);
4725 UpdateAutoTunnelDeviceInfoRecord(m, info);
4726 UpdateAutoTunnelHostRecord(m, info);
4727
4728 // If the global AutoTunnel NAT-T is not yet started, start it.
4729 if (!m->AutoTunnelNAT.clientContext)
4730 {
4731 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
4732 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
4733 m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
4734 m->AutoTunnelNAT.IntPort = IPSECPort;
4735 m->AutoTunnelNAT.RequestedPort = IPSECPort;
4736 m->AutoTunnelNAT.NATLease = 0;
4737 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
4738 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
4739 }
4740 }
4741
4742 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
4743 {
4744 mDNSv6Addr loc_outer6;
4745 mDNSv6Addr rmt_outer6;
4746
4747 // When we are tunneling over IPv6 Relay address, the port number is zero
4748 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4749 {
4750 loc_outer6 = tun->loc_outer6;
4751 rmt_outer6 = tun->rmt_outer6;
4752 }
4753 else
4754 {
4755 loc_outer6 = zerov6Addr;
4756 loc_outer6.b[0] = tun->loc_outer.b[0];
4757 loc_outer6.b[1] = tun->loc_outer.b[1];
4758 loc_outer6.b[2] = tun->loc_outer.b[2];
4759 loc_outer6.b[3] = tun->loc_outer.b[3];
4760
4761 rmt_outer6 = zerov6Addr;
4762 rmt_outer6.b[0] = tun->rmt_outer.b[0];
4763 rmt_outer6.b[1] = tun->rmt_outer.b[1];
4764 rmt_outer6.b[2] = tun->rmt_outer.b[2];
4765 rmt_outer6.b[3] = tun->rmt_outer.b[3];
4766 }
4767
4768 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)));
4769 }
4770
4771 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
4772 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
4773
4774 mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
4775 {
4776 DNSQuestion *q = m->Questions;
4777 while (q)
4778 {
4779 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
4780 {
4781 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4782 mDNSQuestionCallback *tmp = q->QuestionCallback;
4783 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
4784 mDNS_StopQuery(m, q);
4785 mDNS_StartQuery(m, q);
4786 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
4787 if (!success) q->NoAnswer = NoAnswer_Fail;
4788 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
4789 // In general we have to assume that the question list might have changed in arbitrary ways.
4790 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
4791 // already in use. The safest solution is just to go back to the start of the list and start again.
4792 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
4793 // just one suspended question, so it's really a 2n algorithm.
4794 q = m->Questions;
4795 }
4796 else
4797 q = q->next;
4798 }
4799 }
4800
4801 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
4802 {
4803 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
4804 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
4805 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
4806 // 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.
4807 // 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.
4808 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
4809 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
4810 }
4811
4812 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
4813 {
4814 ClientTunnel **p = &m->TunnelClients;
4815 while (*p != tun && *p) p = &(*p)->next;
4816 if (*p) *p = tun->next;
4817 ReissueBlockedQuestions(m, &tun->dstname, success);
4818 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
4819 freeL("ClientTunnel", tun);
4820 }
4821
4822 mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4823 {
4824 ClientTunnel **p;
4825 mDNSBool needSetKeys = mDNStrue;
4826
4827 p = &tun->next;
4828 while (*p)
4829 {
4830 // Is this a tunnel to the same host that we are trying to setup now?
4831 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4832 else
4833 {
4834 ClientTunnel *old = *p;
4835 if (v6Tunnel)
4836 {
4837 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4838 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4839 if (old->q.ThisQInterval >= 0)
4840 {
4841 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4842 mDNS_StopQuery(m, &old->q);
4843 }
4844 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4845 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4846 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
4847 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
4848 {
4849 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4850 // the other parameters of the tunnel are different
4851 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4852 AutoTunnelSetKeys(old, mDNSfalse);
4853 }
4854 else
4855 {
4856 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4857 // as "tun" and "old" are identical
4858 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
4859 &old->rmt_inner);
4860 needSetKeys = mDNSfalse;
4861 }
4862 }
4863 else
4864 {
4865 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
4866 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4867 if (old->q.ThisQInterval >= 0)
4868 {
4869 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4870 mDNS_StopQuery(m, &old->q);
4871 }
4872 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
4873 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
4874 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
4875 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
4876 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
4877 {
4878 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
4879 // the other parameters of the tunnel are different
4880 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4881 AutoTunnelSetKeys(old, mDNSfalse);
4882 }
4883 else
4884 {
4885 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
4886 // as "tun" and "old" are identical
4887 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
4888 &old->rmt_inner);
4889 needSetKeys = mDNSfalse;
4890 }
4891 }
4892
4893 *p = old->next;
4894 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
4895 freeL("ClientTunnel", old);
4896 }
4897 }
4898 return needSetKeys;
4899 }
4900
4901 // v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
4902 // tunnel will be deleted
4903 mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
4904 {
4905 ClientTunnel **p;
4906
4907 p = &tun->next;
4908 while (*p)
4909 {
4910 // If there is more than one client tunnel to the same host, delete all of them.
4911 // We do this by just checking against the EUI64 rather than the full address
4912 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
4913 else
4914 {
4915 ClientTunnel *old = *p;
4916 if (v6Tunnel)
4917 {
4918 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4919 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4920 }
4921 else
4922 {
4923 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
4924 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4925 }
4926 if (old->q.ThisQInterval >= 0)
4927 {
4928 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4929 mDNS_StopQuery(m, &old->q);
4930 }
4931 else
4932 {
4933 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
4934 AutoTunnelSetKeys(old, mDNSfalse);
4935 }
4936 *p = old->next;
4937 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
4938 freeL("ClientTunnel", old);
4939 }
4940 }
4941 }
4942
4943 mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
4944 {
4945 mDNSBool needSetKeys = mDNStrue;
4946 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
4947 mDNSBool v6Tunnel = mDNSfalse;
4948 DomainAuthInfo *info;
4949
4950 // If the port is zero, then we have a relay address of the peer
4951 if (mDNSIPPortIsZero(tun->rmt_outer_port))
4952 v6Tunnel = mDNStrue;
4953
4954 if (v6Tunnel)
4955 {
4956 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
4957 tun->rmt_outer6 = answer->rdata->u.ipv6;
4958 tun->loc_outer6 = m->AutoTunnelRelayAddr;
4959 }
4960 else
4961 {
4962 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
4963 tun->rmt_outer = answer->rdata->u.ipv4;
4964 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
4965 tmpDst.ip.v4 = tun->rmt_outer;
4966 mDNSAddr tmpSrc = zeroAddr;
4967 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
4968 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
4969 else tun->loc_outer = m->AdvertisedV4.ip.v4;
4970 }
4971
4972 question->ThisQInterval = -1; // So we know this tunnel setup has completed
4973
4974 info = GetAuthInfoForName(m, &tun->dstname);
4975 if (!info)
4976 {
4977 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
4978 ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
4979 return;
4980 }
4981
4982 tun->loc_inner = info->AutoTunnelInnerAddress;
4983
4984 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
4985 // look for existing tunnels to see whether they have the same information for our peer.
4986 // If not, delete them and need to create a new tunnel. If they are same, just use the
4987 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
4988 TunnelClientDeleteAny(m, tun, !v6Tunnel);
4989 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
4990
4991 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4992 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
4993
4994 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
4995 static char msgbuf[32];
4996 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
4997 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
4998 // Kick off any questions that were held pending this tunnel setup
4999 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
5000 }
5001
5002 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5003 {
5004 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
5005 DomainAuthInfo *info;
5006
5007 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
5008
5009 if (!AddRecord) return;
5010 mDNS_StopQuery(m, question);
5011
5012 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
5013 // The code below will look for _autotunnel._udp SRV record followed by A record
5014 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
5015 {
5016 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5017 static char msgbuf[16];
5018 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
5019 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
5020 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
5021 return;
5022 }
5023
5024 switch (tun->tc_state)
5025 {
5026 case TC_STATE_AAAA_PEER:
5027 if (question->qtype != kDNSType_AAAA)
5028 {
5029 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
5030 }
5031 info = GetAuthInfoForName(m, &tun->dstname);
5032 if (!info)
5033 {
5034 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
5035 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5036 return;
5037 }
5038 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5039 {
5040 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
5041 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5042 return;
5043 }
5044 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
5045 {
5046 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
5047 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
5048 return;
5049 }
5050 tun->rmt_inner = answer->rdata->u.ipv6;
5051 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
5052 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
5053 {
5054 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
5055 tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
5056 question->qtype = kDNSType_AAAA;
5057 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
5058 }
5059 else
5060 {
5061 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
5062 tun->tc_state = TC_STATE_SRV_PEER;
5063 question->qtype = kDNSType_SRV;
5064 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5065 }
5066 AppendDomainName(&question->qname, &tun->dstname);
5067 mDNS_StartQuery(m, &tun->q);
5068 return;
5069 case TC_STATE_AAAA_PEER_RELAY:
5070 if (question->qtype != kDNSType_AAAA)
5071 {
5072 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
5073 }
5074 // If it failed, look for the SRV record.
5075 if (!answer->rdlength)
5076 {
5077 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
5078 tun->tc_state = TC_STATE_SRV_PEER;
5079 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
5080 AppendDomainName(&question->qname, &tun->dstname);
5081 question->qtype = kDNSType_SRV;
5082 mDNS_StartQuery(m, &tun->q);
5083 return;
5084 }
5085 TunnelClientFinish(m, question, answer);
5086 return;
5087 case TC_STATE_SRV_PEER:
5088 if (question->qtype != kDNSType_SRV)
5089 {
5090 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
5091 }
5092 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
5093 tun->tc_state = TC_STATE_ADDR_PEER;
5094 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
5095 tun->rmt_outer_port = answer->rdata->u.srv.port;
5096 question->qtype = kDNSType_A;
5097 mDNS_StartQuery(m, &tun->q);
5098 return;
5099 case TC_STATE_ADDR_PEER:
5100 if (question->qtype != kDNSType_A)
5101 {
5102 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
5103 }
5104 TunnelClientFinish(m, question, answer);
5105 return;
5106 default:
5107 LogMsg("AutoTunnelCallback: Unknown question %p", question);
5108 }
5109 }
5110
5111 // Must be called with the lock held
5112 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
5113 {
5114 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
5115 if (!p) return;
5116 AssignDomainName(&p->dstname, &q->qname);
5117 p->MarkedForDeletion = mDNSfalse;
5118 p->loc_inner = zerov6Addr;
5119 p->loc_outer = zerov4Addr;
5120 p->loc_outer6 = zerov6Addr;
5121 p->rmt_inner = zerov6Addr;
5122 p->rmt_outer = zerov4Addr;
5123 p->rmt_outer6 = zerov6Addr;
5124 p->rmt_outer_port = zeroIPPort;
5125 p->tc_state = TC_STATE_AAAA_PEER;
5126 p->next = m->TunnelClients;
5127 m->TunnelClients = p; // We intentionally build list in reverse order
5128
5129 p->q.InterfaceID = mDNSInterface_Any;
5130 p->q.flags = 0;
5131 p->q.Target = zeroAddr;
5132 AssignDomainName(&p->q.qname, &q->qname);
5133 p->q.qtype = kDNSType_AAAA;
5134 p->q.qclass = kDNSClass_IN;
5135 p->q.LongLived = mDNSfalse;
5136 p->q.ExpectUnique = mDNStrue;
5137 p->q.ForceMCast = mDNSfalse;
5138 p->q.ReturnIntermed = mDNStrue;
5139 p->q.SuppressUnusable = mDNSfalse;
5140 p->q.SearchListIndex = 0;
5141 p->q.AppendSearchDomains = 0;
5142 p->q.RetryWithSearchDomains = mDNSfalse;
5143 p->q.TimeoutQuestion = 0;
5144 p->q.WakeOnResolve = 0;
5145 p->q.UseBackgroundTrafficClass = mDNSfalse;
5146 p->q.ValidationRequired = 0;
5147 p->q.ValidatingResponse = 0;
5148 p->q.ProxyQuestion = 0;
5149 p->q.qnameOrig = mDNSNULL;
5150 p->q.AnonInfo = mDNSNULL;
5151 p->q.pid = mDNSPlatformGetPID();
5152 p->q.QuestionCallback = AutoTunnelCallback;
5153 p->q.QuestionContext = p;
5154
5155 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
5156 mDNS_StartQuery_internal(m, &p->q);
5157 }
5158
5159 #endif // APPLE_OSX_mDNSResponder
5160
5161 #if COMPILER_LIKES_PRAGMA_MARK
5162 #pragma mark -
5163 #pragma mark - Power State & Configuration Change Management
5164 #endif
5165
5166 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
5167 {
5168 mDNSBool foundav4 = mDNSfalse;
5169 mDNSBool foundav6 = mDNSfalse;
5170 struct ifaddrs *ifa = myGetIfAddrs(1);
5171 struct ifaddrs *v4Loopback = NULL;
5172 struct ifaddrs *v6Loopback = NULL;
5173 char defaultname[64];
5174 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
5175 if (InfoSocket < 3 && errno != EAFNOSUPPORT)
5176 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
5177
5178 while (ifa)
5179 {
5180 #if LIST_ALL_INTERFACES
5181 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
5182 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
5183 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5184 else if (ifa->ifa_addr->sa_family == AF_LINK)
5185 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
5186 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5187 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
5188 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
5189 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5190 if (!(ifa->ifa_flags & IFF_UP))
5191 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
5192 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5193 if (!(ifa->ifa_flags & IFF_MULTICAST))
5194 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
5195 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5196 if (ifa->ifa_flags & IFF_POINTOPOINT)
5197 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
5198 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5199 if (ifa->ifa_flags & IFF_LOOPBACK)
5200 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
5201 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
5202 #endif
5203
5204 if (ifa->ifa_addr->sa_family == AF_LINK)
5205 {
5206 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
5207 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
5208 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
5209 }
5210
5211 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
5212 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
5213 {
5214 if (!ifa->ifa_netmask)
5215 {
5216 mDNSAddr ip;
5217 SetupAddr(&ip, ifa->ifa_addr);
5218 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
5219 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
5220 }
5221 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
5222 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5223 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
5224 {
5225 mDNSAddr ip;
5226 SetupAddr(&ip, ifa->ifa_addr);
5227 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
5228 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
5229 }
5230 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
5231 else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
5232 {
5233 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
5234 }
5235 else
5236 {
5237 // Make sure ifa_netmask->sa_family is set correctly
5238 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
5239 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
5240 int ifru_flags6 = 0;
5241
5242 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
5243 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
5244 {
5245 struct in6_ifreq ifr6;
5246 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
5247 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
5248 ifr6.ifr_addr = *sin6;
5249 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
5250 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
5251 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
5252 }
5253
5254 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
5255 {
5256 if (ifa->ifa_flags & IFF_LOOPBACK)
5257 {
5258 if (ifa->ifa_addr->sa_family == AF_INET)
5259 v4Loopback = ifa;
5260 else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
5261 v6Loopback = ifa;
5262 }
5263 else
5264 {
5265 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
5266 if (i && MulticastInterface(i) && i->ifinfo.Advertise)
5267 {
5268 if (ifa->ifa_addr->sa_family == AF_INET)
5269 foundav4 = mDNStrue;
5270 else
5271 foundav6 = mDNStrue;
5272 }
5273 }
5274 }
5275 }
5276 }
5277 ifa = ifa->ifa_next;
5278 }
5279
5280 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
5281 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
5282 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
5283
5284 // Now the list is complete, set the McastTxRx setting for each interface.
5285 NetworkInterfaceInfoOSX *i;
5286 for (i = m->p->InterfaceList; i; i = i->next)
5287 if (i->Exists)
5288 {
5289 mDNSBool txrx = MulticastInterface(i);
5290 if (i->ifinfo.McastTxRx != txrx)
5291 {
5292 i->ifinfo.McastTxRx = txrx;
5293 i->Exists = 2; // State change; need to deregister and reregister this interface
5294 }
5295 }
5296
5297 if (InfoSocket >= 0)
5298 close(InfoSocket);
5299
5300 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
5301 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
5302
5303 // Set up the nice label
5304 domainlabel nicelabel;
5305 nicelabel.c[0] = 0;
5306 GetUserSpecifiedFriendlyComputerName(&nicelabel);
5307 if (nicelabel.c[0] == 0)
5308 {
5309 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
5310 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
5311 }
5312
5313 // Set up the RFC 1034-compliant label
5314 domainlabel hostlabel;
5315 hostlabel.c[0] = 0;
5316 GetUserSpecifiedLocalHostName(&hostlabel);
5317 if (hostlabel.c[0] == 0)
5318 {
5319 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
5320 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
5321 }
5322
5323 mDNSBool namechange = mDNSfalse;
5324
5325 // We use a case-sensitive comparison here because even though changing the capitalization
5326 // of the name alone is not significant to DNS, it's still a change from the user's point of view
5327 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
5328 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
5329 else
5330 {
5331 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5332 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
5333 m->p->usernicelabel = m->nicelabel = nicelabel;
5334 namechange = mDNStrue;
5335 }
5336
5337 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
5338 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
5339 else
5340 {
5341 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
5342 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
5343 m->p->userhostlabel = m->hostlabel = hostlabel;
5344 mDNS_SetFQDN(m);
5345 namechange = mDNStrue;
5346 }
5347
5348 #if APPLE_OSX_mDNSResponder
5349 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
5350 {
5351 DomainAuthInfo *info;
5352 for (info = m->AuthInfoList; info; info = info->next)
5353 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
5354 }
5355 #endif // APPLE_OSX_mDNSResponder
5356
5357 return(mStatus_NoError);
5358 }
5359
5360 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
5361 // Returns -1 if all the one-bits are not contiguous
5362 mDNSlocal int CountMaskBits(mDNSAddr *mask)
5363 {
5364 int i = 0, bits = 0;
5365 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
5366 while (i < bytes)
5367 {
5368 mDNSu8 b = mask->ip.v6.b[i++];
5369 while (b & 0x80) { bits++; b <<= 1; }
5370 if (b) return(-1);
5371 }
5372 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
5373 return(bits);
5374 }
5375
5376 // returns count of non-link local V4 addresses registered
5377 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
5378 {
5379 NetworkInterfaceInfoOSX *i;
5380 int count = 0;
5381 for (i = m->p->InterfaceList; i; i = i->next)
5382 if (i->Exists)
5383 {
5384 NetworkInterfaceInfo *const n = &i->ifinfo;
5385 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5386 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
5387
5388 if (i->Registered && i->Registered != primary) // Sanity check
5389 {
5390 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
5391 i->Registered = mDNSNULL;
5392 }
5393
5394 if (!i->Registered)
5395 {
5396 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5397 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5398 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
5399 //
5400
5401 i->Registered = primary;
5402
5403 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
5404 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
5405 // 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.
5406 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
5407
5408 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5409 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5410 // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
5411 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
5412 // logs a warning message to system.log noting frequent interface transitions.
5413 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5414 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->DirectLink)
5415 {
5416 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
5417 i->Flashing ? " (Flashing)" : "",
5418 i->Occulting ? " (Occulting)" : "");
5419 mDNS_RegisterInterface(m, n, 0);
5420 }
5421 else
5422 {
5423 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
5424 }
5425
5426 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
5427 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5428 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
5429 i->Flashing ? " (Flashing)" : "",
5430 i->Occulting ? " (Occulting)" : "",
5431 n->InterfaceActive ? " (Primary)" : "");
5432
5433 if (!n->McastTxRx)
5434 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);
5435 else
5436 {
5437 if (i->sa_family == AF_INET)
5438 {
5439 struct ip_mreq imr;
5440 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
5441 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
5442 imr.imr_interface = primary->ifa_v4addr;
5443
5444 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
5445 // before trying to join the group, to clear out stale kernel state which may be lingering.
5446 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
5447 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
5448 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
5449 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
5450 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
5451 // because by the time we get the configuration change notification, the interface is already gone,
5452 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
5453 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
5454 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
5455 {
5456 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);
5457 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
5458 if (err < 0 && (errno != EADDRNOTAVAIL))
5459 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
5460 }
5461
5462 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
5463 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
5464 // Joining same group twice can give "Address already in use" error -- no need to report that
5465 if (err < 0 && (errno != EADDRINUSE))
5466 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
5467 }
5468 if (i->sa_family == AF_INET6)
5469 {
5470 struct ipv6_mreq i6mr;
5471 i6mr.ipv6mr_interface = primary->scope_id;
5472 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
5473
5474 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
5475 {
5476 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);
5477 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
5478 if (err < 0 && (errno != EADDRNOTAVAIL))
5479 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5480 }
5481
5482 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5483 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
5484 // Joining same group twice can give "Address already in use" error -- no need to report that
5485 if (err < 0 && (errno != EADDRINUSE))
5486 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
5487 }
5488 }
5489 }
5490 }
5491
5492 return count;
5493 }
5494
5495 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
5496 {
5497 NetworkInterfaceInfoOSX *i;
5498 for (i = m->p->InterfaceList; i; i = i->next)
5499 {
5500 if (i->Exists) i->LastSeen = utc;
5501 i->Exists = mDNSfalse;
5502 }
5503 }
5504
5505 // returns count of non-link local V4 addresses deregistered
5506 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
5507 {
5508 // First pass:
5509 // If an interface is going away, then deregister this from the mDNSCore.
5510 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
5511 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
5512 // it refers to has gone away we'll crash.
5513 NetworkInterfaceInfoOSX *i;
5514 int count = 0;
5515 for (i = m->p->InterfaceList; i; i = i->next)
5516 {
5517 // If this interface is no longer active, or its InterfaceID is changing, deregister it
5518 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
5519 if (i->Registered)
5520 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
5521 {
5522 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
5523 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
5524 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
5525 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
5526 i->Flashing ? " (Flashing)" : "",
5527 i->Occulting ? " (Occulting)" : "",
5528 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5529
5530 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
5531 // everytime it creates a new interface. We think it is a duplicate and hence consider it
5532 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
5533 // stale data returned to the application even after the interface is removed. The application
5534 // then starts to send data but the new interface is not yet created.
5535 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
5536 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->DirectLink)
5537 {
5538 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
5539 i->Flashing ? " (Flashing)" : "",
5540 i->Occulting ? " (Occulting)" : "");
5541 mDNS_DeregisterInterface(m, &i->ifinfo, 0);
5542 }
5543 else
5544 {
5545 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
5546 }
5547 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
5548 i->Registered = mDNSNULL;
5549 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
5550 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
5551 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
5552
5553 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
5554 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
5555 }
5556 }
5557
5558 // Second pass:
5559 // Now that everything that's going to deregister has done so, we can clean up and free the memory
5560 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
5561 while (*p)
5562 {
5563 i = *p;
5564 // If no longer active, delete interface from list and free memory
5565 if (!i->Exists)
5566 {
5567 if (i->LastSeen == utc) i->LastSeen = utc - 1;
5568 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
5569 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
5570 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
5571 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
5572 i->ifinfo.InterfaceActive ? " (Primary)" : "");
5573 #if APPLE_OSX_mDNSResponder
5574 if (i->BPF_fd >= 0) CloseBPF(i);
5575 #endif // APPLE_OSX_mDNSResponder
5576 if (delete)
5577 {
5578 *p = i->next;
5579 freeL("NetworkInterfaceInfoOSX", i);
5580 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
5581 }
5582 }
5583 p = &i->next;
5584 }
5585 return count;
5586 }
5587
5588 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
5589 {
5590 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
5591 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
5592 else
5593 {
5594 dnle->next = mDNSNULL;
5595 dnle->uid = uid;
5596 AssignDomainName(&dnle->name, name);
5597 **List = dnle;
5598 *List = &dnle->next;
5599 }
5600 }
5601
5602 mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
5603 {
5604 dns_resolver_t *a = *(dns_resolver_t**)aa;
5605 dns_resolver_t *b = *(dns_resolver_t**)bb;
5606
5607 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
5608 }
5609
5610 mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
5611 {
5612 char *buf = ".";
5613 mDNSu32 scopeid = 0;
5614 char ifid_buf[16];
5615
5616 if (domain)
5617 buf = domain;
5618 //
5619 // Hash the search domain name followed by the InterfaceID.
5620 // As we have scoped search domains, we also included InterfaceID. If either of them change,
5621 // we will detect it. Even if the order of them change, we will detect it.
5622 //
5623 // Note: We have to handle a few of these tricky cases.
5624 //
5625 // 1) Current: com, apple.com Changing to: comapple.com
5626 // 2) Current: a.com,b.com Changing to a.comb.com
5627 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
5628 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
5629 //
5630 // There are more variants of the above. The key thing is if we include the null in each case
5631 // at the end of name and the InterfaceID, it will prevent a new name (which can't include
5632 // NULL as part of the name) to be mistakenly thought of as a old name.
5633
5634 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
5635 // mDNS_snprintf always null terminates
5636 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
5637 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
5638
5639 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
5640 MD5_Update(sdc, buf, strlen(buf) + 1);
5641 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
5642 }
5643
5644 mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
5645 {
5646 mDNSu8 md5_hash[MD5_LEN];
5647
5648 MD5_Final(md5_hash, sdc);
5649
5650 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
5651 {
5652 // If the hash is different, either the search domains have changed or
5653 // the ordering between them has changed. Restart the questions that
5654 // would be affected by this.
5655 LogInfo("FinalizeSearchDomains: The hash is different");
5656 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
5657 RetrySearchDomainQuestions(m);
5658 }
5659 else { LogInfo("FinalizeSearchDomains: The hash is same"); }
5660 }
5661
5662 mDNSexport const char *DNSScopeToString(mDNSu32 scope)
5663 {
5664 switch (scope)
5665 {
5666 case kScopeNone:
5667 return "Unscoped";
5668 case kScopeInterfaceID:
5669 return "InterfaceScoped";
5670 case kScopeServiceID:
5671 return "ServiceScoped";
5672 default:
5673 return "Unknown";
5674 }
5675 }
5676
5677 mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc)
5678 {
5679 const char *scopeString = DNSScopeToString(scope);
5680 int j;
5681
5682 if (scope != kScopeNone)
5683 {
5684 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface);
5685 return;
5686 }
5687 for (j = 0; j < resolver->n_search; j++)
5688 {
5689 LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]);
5690 UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL);
5691 mDNS_AddSearchDomain_CString(resolver->search[j], NULL);
5692 }
5693 }
5694
5695 mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
5696 {
5697 NetworkInterfaceInfoOSX *ni;
5698 mDNSInterfaceID interface;
5699
5700 for (ni = m->p->InterfaceList; ni; ni = ni->next)
5701 {
5702 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
5703 break;
5704 }
5705 if (ni != NULL)
5706 {
5707 interface = ni->ifinfo.InterfaceID;
5708 }
5709 else
5710 {
5711 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
5712 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
5713 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
5714 // As the caller is going to ack the configuration always, we have to add all the DNS servers
5715 // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
5716
5717 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
5718
5719 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
5720 interface = (mDNSInterfaceID)(unsigned long)ifindex;
5721 }
5722 return interface;
5723 }
5724
5725 mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
5726 {
5727 char *opt = r->options;
5728 domainname d;
5729
5730 if (opt && !strncmp(opt, "mdns", strlen(opt)))
5731 {
5732 if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5733 {
5734 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
5735 return;
5736 }
5737 mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
5738 }
5739 }
5740
5741 mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
5742 {
5743 int n;
5744 domainname d;
5745 int serviceID = 0;
5746 mDNSBool cellIntf = mDNSfalse;
5747 mDNSBool scopedDNS = mDNSfalse;
5748 mDNSBool reqA, reqAAAA;
5749
5750 if (!r->domain || !*r->domain)
5751 {
5752 d.c[0] = 0;
5753 }
5754 else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
5755 {
5756 LogMsg("ConfigDNSServers: bad domain %s", r->domain);
5757 return;
5758 }
5759 // Parse the resolver specific attributes that affects all the DNS servers.
5760 if (scope == kScopeInterfaceID)
5761 {
5762 scopedDNS = mDNStrue;
5763 }
5764 else if (scope == kScopeServiceID)
5765 {
5766 serviceID = r->service_identifier;
5767 }
5768
5769 #if TARGET_OS_IPHONE
5770 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
5771 #endif
5772 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
5773 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
5774
5775 for (n = 0; n < r->n_nameserver; n++)
5776 {
5777 mDNSAddr saddr;
5778 DNSServer *s;
5779
5780 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
5781 continue;
5782
5783 if (SetupAddr(&saddr, r->nameserver[n]))
5784 {
5785 LogMsg("ConfigDNSServers: Bad address");
5786 continue;
5787 }
5788
5789 // The timeout value is for all the DNS servers in a given resolver, hence we pass
5790 // the timeout value only for the first DNSServer. If we don't have a value in the
5791 // resolver, then use the core's default value
5792 //
5793 // Note: this assumes that when the core picks a list of DNSServers for a question,
5794 // it takes the sum of all the timeout values for all DNS servers. By doing this, it
5795 // tries all the DNS servers in a specified timeout
5796 s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
5797 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
5798 if (s)
5799 {
5800 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
5801 }
5802 }
5803 }
5804
5805 // ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
5806 // Service scope resolvers. This is indicated by the scope argument.
5807 //
5808 // "resolver" has entries that should only be used for unscoped questions.
5809 //
5810 // "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
5811 // interface index (q->InterfaceID)
5812 //
5813 // "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
5814 // a service identifier (q->ServiceID)
5815 //
5816 mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
5817 {
5818 int i;
5819 dns_resolver_t **resolver;
5820 int nresolvers;
5821 const char *scopeString = DNSScopeToString(scope);
5822 mDNSInterfaceID interface;
5823
5824 switch (scope)
5825 {
5826 case kScopeNone:
5827 resolver = config->resolver;
5828 nresolvers = config->n_resolver;
5829 break;
5830 case kScopeInterfaceID:
5831 resolver = config->scoped_resolver;
5832 nresolvers = config->n_scoped_resolver;
5833 break;
5834 case kScopeServiceID:
5835 resolver = config->service_specific_resolver;
5836 nresolvers = config->n_service_specific_resolver;
5837 break;
5838 default:
5839 return;
5840 }
5841 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
5842
5843 for (i = 0; i < nresolvers; i++)
5844 {
5845 dns_resolver_t *r = resolver[i];
5846
5847 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
5848
5849 interface = mDNSInterface_Any;
5850
5851 // Parse the interface index
5852 if (r->if_index != 0)
5853 {
5854 interface = ConfigParseInterfaceID(m, r->if_index);
5855 }
5856
5857 if (setsearch)
5858 {
5859 ConfigSearchDomains(m, resolver[i], interface, scope, sdc);
5860 // Parse other scoped resolvers for search lists
5861 if (!setservers)
5862 continue;
5863 }
5864
5865 if (r->port == 5353 || r->n_nameserver == 0)
5866 {
5867 ConfigNonUnicastResolver(m, r);
5868 }
5869 else
5870 {
5871 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
5872 // scoped resolver are not used by other non-scoped or scoped resolvers.
5873 if (scope != kScopeNone)
5874 resGroupID++;
5875
5876 ConfigDNSServers(m, r, interface, scope, resGroupID);
5877 }
5878 }
5879 }
5880
5881 #if APPLE_OSX_mDNSResponder
5882 mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
5883 {
5884 if (QuerySuppressed(q))
5885 {
5886 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5887 return mDNSfalse;
5888 }
5889 if (mDNSOpaque16IsZero(q->TargetQID))
5890 {
5891 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5892 return mDNSfalse;
5893 }
5894 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
5895 // for trigger.
5896 if (q->LOAddressAnswers)
5897 {
5898 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5899 return mDNSfalse;
5900 }
5901 return mDNStrue;
5902 }
5903 #endif
5904
5905 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
5906 // We set our state appropriately so that if we start receiving answers, trigger the
5907 // upper layer to retry DNS questions.
5908 #if APPLE_OSX_mDNSResponder
5909 mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
5910 {
5911 if (!QuestionValidForDNSTrigger(q))
5912 return;
5913
5914 // Ignore applications that start and stop queries for no reason before we ever talk
5915 // to any DNS server.
5916 if (!q->triedAllServersOnce)
5917 {
5918 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
5919 return;
5920 }
5921 if (q->qtype == kDNSType_A)
5922 m->p->v4answers = 0;
5923 if (q->qtype == kDNSType_AAAA)
5924 m->p->v6answers = 0;
5925 if (!m->p->v4answers || !m->p->v6answers)
5926 {
5927 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
5928 DNSTypeName(q->qtype));
5929 }
5930 }
5931 #endif
5932
5933 mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
5934 {
5935 mDNS_CheckLock(m);
5936
5937 // Acking the configuration triggers configd to reissue the reachability queries
5938 m->p->DNSTrigger = NonZeroTime(m->timenow);
5939 _dns_configuration_ack(config, "com.apple.mDNSResponder");
5940 }
5941
5942 // If v4q is non-NULL, it means we have received some answers for "A" type questions
5943 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
5944 #if APPLE_OSX_mDNSResponder
5945 mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
5946 {
5947 mDNSBool trigger = mDNSfalse;
5948 mDNSs32 timenow;
5949
5950 // Don't send triggers too often.
5951 // If we have started delivering answers to questions, we should send a trigger
5952 // if the time permits. If we are delivering answers, we should set the state
5953 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
5954 // whether the answers that are being delivered currently is for configd or some
5955 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
5956 // then we won't deliver the trigger later when it is okay to send one as the
5957 // "answers" are already set to 1. Hence, don't affect the state of v4answers and
5958 // v6answers if we are not delivering triggers.
5959 mDNS_Lock(m);
5960 timenow = m->timenow;
5961 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
5962 {
5963 if (!m->p->v4answers || !m->p->v6answers)
5964 {
5965 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
5966 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
5967 }
5968 mDNS_Unlock(m);
5969 return;
5970 }
5971 mDNS_Unlock(m);
5972 if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
5973 {
5974 int old = m->p->v4answers;
5975
5976 m->p->v4answers = 1;
5977
5978 // If there are IPv4 answers now and previously we did not have
5979 // any answers, trigger a DNS change so that reachability
5980 // can retry the queries again.
5981 if (!old)
5982 {
5983 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5984 v4q->qname.c, DNSTypeName(v4q->qtype));
5985 trigger = mDNStrue;
5986 }
5987 }
5988 if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
5989 {
5990 int old = m->p->v6answers;
5991
5992 m->p->v6answers = 1;
5993 // If there are IPv6 answers now and previously we did not have
5994 // any answers, trigger a DNS change so that reachability
5995 // can retry the queries again.
5996 if (!old)
5997 {
5998 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
5999 v6q->qname.c, DNSTypeName(v6q->qtype));
6000 trigger = mDNStrue;
6001 }
6002 }
6003 if (trigger)
6004 {
6005 dns_config_t *config = dns_configuration_copy();
6006 if (config)
6007 {
6008 mDNS_Lock(m);
6009 AckConfigd(m, config);
6010 mDNS_Unlock(m);
6011 dns_configuration_free(config);
6012 }
6013 else
6014 {
6015 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
6016 }
6017 }
6018 }
6019
6020 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
6021 {
6022 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
6023 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
6024 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
6025 config->resolver[0]->nameserver[0])
6026 {
6027 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
6028 }
6029 else
6030 {
6031 ActiveDirectoryPrimaryDomain.c[0] = 0;
6032 }
6033
6034 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
6035 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
6036 if (config->n_resolver && config->resolver[0]->n_nameserver &&
6037 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
6038 {
6039 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
6040 }
6041 else
6042 {
6043 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
6044 ActiveDirectoryPrimaryDomainLabelCount = 0;
6045 ActiveDirectoryPrimaryDomainServer = zeroAddr;
6046 }
6047 }
6048 #endif
6049
6050 mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
6051 {
6052 int i;
6053 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6054 domainname d;
6055
6056 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
6057 if (!store)
6058 {
6059 LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6060 }
6061 else
6062 {
6063 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
6064 if (ddnsdict)
6065 {
6066 if (fqdn)
6067 {
6068 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
6069 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
6070 {
6071 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
6072 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
6073 if (fqdnDict && DictionaryIsEnabled(fqdnDict))
6074 {
6075 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
6076 if (name)
6077 {
6078 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6079 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
6080 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
6081 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
6082 }
6083 }
6084 }
6085 }
6086
6087 if (RegDomains)
6088 {
6089 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
6090 if (regArray && CFArrayGetCount(regArray) > 0)
6091 {
6092 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
6093 if (regDict && DictionaryIsEnabled(regDict))
6094 {
6095 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
6096 if (name)
6097 {
6098 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6099 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6100 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
6101 else
6102 {
6103 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
6104 AppendDNameListElem(&RegDomains, 0, &d);
6105 }
6106 }
6107 }
6108 }
6109 }
6110
6111 if (BrowseDomains)
6112 {
6113 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
6114 if (browseArray)
6115 {
6116 for (i = 0; i < CFArrayGetCount(browseArray); i++)
6117 {
6118 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
6119 if (browseDict && DictionaryIsEnabled(browseDict))
6120 {
6121 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
6122 if (name)
6123 {
6124 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
6125 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
6126 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
6127 else
6128 {
6129 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
6130 AppendDNameListElem(&BrowseDomains, 0, &d);
6131 }
6132 }
6133 }
6134 }
6135 }
6136 }
6137 CFRelease(ddnsdict);
6138 }
6139
6140 if (RegDomains)
6141 {
6142 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6143 if (btmm)
6144 {
6145 CFIndex size = CFDictionaryGetCount(btmm);
6146 const void *key[size];
6147 const void *val[size];
6148 CFDictionaryGetKeysAndValues(btmm, key, val);
6149 for (i = 0; i < size; i++)
6150 {
6151 LogInfo("BackToMyMac %d", i);
6152 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6153 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
6154 else
6155 {
6156 mDNSu32 uid = atoi(buf);
6157 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6158 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
6159 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
6160 {
6161 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
6162 AppendDNameListElem(&RegDomains, uid, &d);
6163 }
6164 }
6165 }
6166 CFRelease(btmm);
6167 }
6168 }
6169 CFRelease(store);
6170 }
6171 }
6172
6173 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
6174 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
6175 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
6176 {
6177 MD5_CTX sdc; // search domain context
6178 static mDNSu16 resolverGroupID = 0;
6179
6180 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
6181 if (fqdn) fqdn->c[0] = 0;
6182 if (RegDomains ) *RegDomains = NULL;
6183 if (BrowseDomains) *BrowseDomains = NULL;
6184
6185 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
6186 setservers ? " setservers" : "",
6187 setsearch ? " setsearch" : "",
6188 fqdn ? " fqdn" : "",
6189 RegDomains ? " RegDomains" : "",
6190 BrowseDomains ? " BrowseDomains" : "");
6191
6192 if (setsearch) MD5_Init(&sdc);
6193
6194 // Add the inferred address-based configuration discovery domains
6195 // (should really be in core code I think, not platform-specific)
6196 if (setsearch)
6197 {
6198 struct ifaddrs *ifa = mDNSNULL;
6199 struct sockaddr_in saddr;
6200 mDNSPlatformMemZero(&saddr, sizeof(saddr));
6201 saddr.sin_len = sizeof(saddr);
6202 saddr.sin_family = AF_INET;
6203 saddr.sin_port = 0;
6204 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
6205
6206 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
6207 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
6208
6209 while (ifa)
6210 {
6211 mDNSAddr a, n;
6212 char buf[64];
6213
6214 if (ifa->ifa_addr->sa_family == AF_INET &&
6215 ifa->ifa_netmask &&
6216 !(ifa->ifa_flags & IFF_LOOPBACK) &&
6217 !SetupAddr(&a, ifa->ifa_addr) &&
6218 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
6219 {
6220 // 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
6221 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
6222 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
6223 SetupAddr(&n, ifa->ifa_netmask);
6224 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6225 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
6226 a.ip.v4.b[2] & n.ip.v4.b[2],
6227 a.ip.v4.b[1] & n.ip.v4.b[1],
6228 a.ip.v4.b[0] & n.ip.v4.b[0]);
6229 UpdateSearchDomainHash(m, &sdc, buf, NULL);
6230 mDNS_AddSearchDomain_CString(buf, mDNSNULL);
6231 }
6232 ifa = ifa->ifa_next;
6233 }
6234 }
6235
6236 #ifndef MDNS_NO_DNSINFO
6237 if (setservers || setsearch)
6238 {
6239 dns_config_t *config = dns_configuration_copy();
6240 if (!config)
6241 {
6242 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
6243 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
6244 // Apparently this is expected behaviour -- "not a bug".
6245 // Accordingly, we suppress syslog messages for the first three minutes after boot.
6246 // If we are still getting failures after three minutes, then we log them.
6247 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
6248 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
6249 }
6250 else
6251 {
6252 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation);
6253 if (m->p->LastConfigGeneration == config->generation)
6254 {
6255 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
6256 dns_configuration_free(config);
6257 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6258 return mDNSfalse;
6259 }
6260 #if APPLE_OSX_mDNSResponder
6261 SetupActiveDirectoryDomain(config);
6262 #endif
6263
6264 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
6265 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
6266 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
6267 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
6268 // same resolverGroupID.
6269 //
6270 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
6271 ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
6272 resolverGroupID += config->n_resolver;
6273
6274 ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
6275 resolverGroupID += config->n_scoped_resolver;
6276
6277 ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
6278
6279 // Acking provides a hint that we processed this current configuration and
6280 // we will use that from now on, assuming we don't get another one immediately
6281 // after we return from here.
6282 if (ackConfig)
6283 {
6284 // Note: We have to set the generation number here when we are acking.
6285 // For every DNS configuration change, we do the following:
6286 //
6287 // 1) Copy dns configuration, handle search domains change
6288 // 2) Copy dns configuration, handle dns server change
6289 //
6290 // If we update the generation number at step (1), we won't process the
6291 // DNS servers the second time because generation number would be the same.
6292 // As we ack only when we process dns servers, we set the generation number
6293 // during acking.
6294 m->p->LastConfigGeneration = config->generation;
6295 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
6296 AckConfigd(m, config);
6297 }
6298 dns_configuration_free(config);
6299 if (setsearch) FinalizeSearchDomainHash(m, &sdc);
6300 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
6301 setsearch = mDNSfalse;
6302 }
6303 }
6304 #endif // MDNS_NO_DNSINFO
6305 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
6306 return mDNStrue;
6307 }
6308
6309
6310 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
6311 {
6312 char buf[256];
6313 (void)m; // Unused
6314
6315 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
6316 if (!store)
6317 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6318 else
6319 {
6320 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
6321 if (dict)
6322 {
6323 r->type = mDNSAddrType_IPv4;
6324 r->ip.v4 = zerov4Addr;
6325 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
6326 if (string)
6327 {
6328 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
6329 LogMsg("Could not convert router to CString");
6330 else
6331 {
6332 struct sockaddr_in saddr;
6333 saddr.sin_len = sizeof(saddr);
6334 saddr.sin_family = AF_INET;
6335 saddr.sin_port = 0;
6336 inet_aton(buf, &saddr.sin_addr);
6337
6338 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
6339 }
6340 }
6341
6342 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
6343 if (string)
6344 {
6345 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
6346 struct ifaddrs *ifa = myGetIfAddrs(1);
6347
6348 *v4 = *v6 = zeroAddr;
6349
6350 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
6351
6352 // find primary interface in list
6353 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
6354 {
6355 mDNSAddr tmp6 = zeroAddr;
6356 if (!strcmp(buf, ifa->ifa_name))
6357 {
6358 if (ifa->ifa_addr->sa_family == AF_INET)
6359 {
6360 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
6361 }
6362 else if (ifa->ifa_addr->sa_family == AF_INET6)
6363 {
6364 SetupAddr(&tmp6, ifa->ifa_addr);
6365 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
6366 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
6367 }
6368 }
6369 else
6370 {
6371 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
6372 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
6373 {
6374 SetupAddr(&tmp6, ifa->ifa_addr);
6375 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
6376 }
6377 }
6378 ifa = ifa->ifa_next;
6379 }
6380
6381 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
6382 // V4 to communicate w/ our DNS server
6383 }
6384
6385 exit:
6386 CFRelease(dict);
6387 }
6388 CFRelease(store);
6389 }
6390 return mStatus_NoError;
6391 }
6392
6393 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
6394 {
6395 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
6396 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6397 ConvertDomainNameToCString(dname, uname);
6398
6399 char *p = uname;
6400 while (*p)
6401 {
6402 *p = tolower(*p);
6403 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
6404 p++;
6405 }
6406
6407 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
6408 // That single entity is a CFDictionary with name "HostNames".
6409 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
6410 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
6411 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
6412 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
6413 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
6414
6415 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
6416 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
6417 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
6418 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
6419 else
6420 {
6421 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
6422 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
6423 else
6424 {
6425 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6426 if (HostVals[0])
6427 {
6428 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
6429 if (StateVals[0])
6430 {
6431 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6432 if (StateDict)
6433 {
6434 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
6435 CFRelease(StateDict);
6436 }
6437 CFRelease(StateVals[0]);
6438 }
6439 CFRelease(HostVals[0]);
6440 }
6441 CFRelease(StatusVals[0]);
6442 }
6443 CFRelease(HostKeys[0]);
6444 }
6445 }
6446
6447 #if APPLE_OSX_mDNSResponder
6448 #if !NO_AWACS
6449
6450 // checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
6451 // keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
6452 // help catch it
6453 mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
6454 {
6455 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
6456 if (!store)
6457 {
6458 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6459 return mDNSfalse;
6460 }
6461 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
6462 if (btmm)
6463 {
6464 CFIndex size = CFDictionaryGetCount(btmm);
6465 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
6466 const void *key[size];
6467 const void *val[size];
6468 domainname dom;
6469 int i;
6470 CFDictionaryGetKeysAndValues(btmm, key, val);
6471 for (i = 0; i < size; i++)
6472 {
6473 LogInfo("BackToMyMac %d", i);
6474 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6475 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
6476 else
6477 {
6478 mDNSu32 uid = atoi(buf);
6479 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
6480 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
6481 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
6482 {
6483 if (SameDomainName(&dom, d))
6484 {
6485 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
6486 CFRelease(btmm);
6487 CFRelease(store);
6488 return mDNStrue;
6489 }
6490 }
6491 }
6492 }
6493 CFRelease(btmm);
6494 }
6495 CFRelease(store);
6496 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
6497 return mDNSfalse;
6498 }
6499
6500 // Appends data to the buffer
6501 mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
6502 {
6503 int len;
6504
6505 len = strlcpy(buf + *currlen, data, bufsz - *currlen);
6506 if (len >= (bufsz - *currlen))
6507 {
6508 // if we have exceeded the space in buf, it has already been NULL terminated
6509 // and we have nothing more to do. Set currlen to the last byte so that the caller
6510 // knows to do the right thing
6511 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
6512 *currlen = bufsz - 1;
6513 return -1;
6514 }
6515 else { (*currlen) += len; }
6516
6517 buf[*currlen] = ',';
6518 if (*currlen >= bufsz)
6519 {
6520 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
6521 *currlen = bufsz - 1;
6522 buf[*currlen] = 0;
6523 return -1;
6524 }
6525 // if we have filled up the buffer exactly, then there is no more work to do
6526 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
6527 (*currlen)++;
6528 return *currlen;
6529 }
6530
6531 // If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
6532 // BTMM domains, then bring down the connection to the relay.
6533 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6534 {
6535 DomainAuthInfo *BTMMDomain = mDNSNULL;
6536 DomainAuthInfo *FoundInList;
6537 static mDNSBool AWACSDConnected = mDNSfalse;
6538 char AllUsers[1024]; // maximum size of mach message
6539 char AllPass[1024]; // maximum size of mach message
6540 char username[MAX_DOMAIN_LABEL + 1];
6541 int currulen = 0;
6542 int currplen = 0;
6543
6544 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
6545 // we may not be able to send the dns queries over the relay connection which may be needed
6546 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
6547 // need to make sure that we send the disconnect before attempting the next connect as the
6548 // awacs connections are redirected based on usernames.
6549 //
6550 // For now we send a disconnect immediately. When we start sending dns queries over the relay
6551 // connection, we will need to fix this.
6552
6553 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6554 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
6555 {
6556 // We need the passwd from the first domain.
6557 BTMMDomain = FoundInList;
6558 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
6559 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
6560 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
6561 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
6562 }
6563
6564 if (BTMMDomain)
6565 {
6566 // In the normal case (where we neither exceed the buffer size nor write bytes that
6567 // fit exactly into the buffer), currulen/currplen should be a different size than
6568 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
6569
6570 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
6571 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
6572
6573 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
6574 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
6575 AWACSDConnected = mDNStrue;
6576 }
6577 else
6578 {
6579 // Disconnect only if we connected previously
6580 if (AWACSDConnected)
6581 {
6582 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
6583 AWACS_Disconnect();
6584 AWACSDConnected = mDNSfalse;
6585 }
6586 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
6587 }
6588 }
6589 #else
6590 mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
6591 {
6592 (void) m; // Unused
6593 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
6594 }
6595 #endif // ! NO_AWACS
6596
6597 mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
6598
6599 #endif // APPLE_OSX_mDNSResponder
6600
6601 // MUST be called holding the lock
6602 mDNSexport void SetDomainSecrets(mDNS *m)
6603 {
6604 #ifdef NO_SECURITYFRAMEWORK
6605 (void) m;
6606 LogMsg("Note: SetDomainSecrets: no keychain support");
6607 #else
6608 mDNSBool haveAutoTunnels = mDNSfalse;
6609
6610 LogInfo("SetDomainSecrets");
6611
6612 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
6613 // In the case where the user simultaneously removes their DDNS host name and the key
6614 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
6615 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
6616 // address records behind that we no longer have permission to delete.
6617 DomainAuthInfo *ptr;
6618 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
6619 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
6620
6621 #if APPLE_OSX_mDNSResponder
6622 {
6623 // Mark all TunnelClients for deletion
6624 ClientTunnel *client;
6625 for (client = m->TunnelClients; client; client = client->next)
6626 {
6627 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
6628 client->MarkedForDeletion = mDNStrue;
6629 }
6630 }
6631 #endif // APPLE_OSX_mDNSResponder
6632
6633 // String Array used to write list of private domains to Dynamic Store
6634 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6635 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
6636 CFIndex i;
6637 CFDataRef data = NULL;
6638 const int itemsPerEntry = 4; // domain name, key name, key value, Name value
6639 CFArrayRef secrets = NULL;
6640 int err = mDNSKeychainGetSecrets(&secrets);
6641 if (err || !secrets)
6642 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
6643 else
6644 {
6645 CFIndex ArrayCount = CFArrayGetCount(secrets);
6646 // Iterate through the secrets
6647 for (i = 0; i < ArrayCount; ++i)
6648 {
6649 mDNSBool AutoTunnel;
6650 int j, offset;
6651 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
6652 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
6653 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
6654 for (j = 0; j < CFArrayGetCount(entry); ++j)
6655 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
6656 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
6657
6658 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
6659
6660 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
6661 // Get DNS domain this key is for (kmDNSKcWhere)
6662 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
6663 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
6664 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6665 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
6666 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6667 stringbuf[CFDataGetLength(data)] = '\0';
6668
6669 AutoTunnel = mDNSfalse;
6670 offset = 0;
6671 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
6672 offset = strlen(dnsprefix);
6673 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
6674 {
6675 AutoTunnel = mDNStrue;
6676 offset = strlen(btmmprefix);
6677 }
6678 domainname domain;
6679 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
6680
6681 // Get key name (kmDNSKcAccount)
6682 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
6683 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6684 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
6685 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
6686 stringbuf[CFDataGetLength(data)] = '\0';
6687
6688 domainname keyname;
6689 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
6690
6691 // Get key data (kmDNSKcKey)
6692 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
6693 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
6694 {
6695 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
6696 continue;
6697 }
6698 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
6699 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
6700
6701 // Get the Name of the keychain entry (kmDNSKcName) host or host:port
6702 // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
6703 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
6704 data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
6705 if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
6706 {
6707 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
6708 continue;
6709 }
6710 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
6711 hostbuf[CFDataGetLength(data)] = '\0';
6712
6713 domainname hostname;
6714 mDNSIPPort port;
6715 char *hptr;
6716 hptr = strchr(hostbuf, ':');
6717
6718 port.NotAnInteger = 0;
6719 if (hptr)
6720 {
6721 mDNSu8 *p;
6722 mDNSu16 val = 0;
6723
6724 *hptr++ = '\0';
6725 while(hptr && *hptr != 0)
6726 {
6727 if (*hptr < '0' || *hptr > '9')
6728 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
6729 val = val * 10 + *hptr - '0';
6730 hptr++;
6731 }
6732 if (!val) continue;
6733 p = (mDNSu8 *)&val;
6734 port.NotAnInteger = p[0] << 8 | p[1];
6735 }
6736 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid.
6737 hptr = strchr(hostbuf, '@');
6738 if (hptr)
6739 hptr++;
6740 else
6741 hptr = hostbuf;
6742 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
6743
6744 DomainAuthInfo *FoundInList;
6745 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
6746 if (SameDomainName(&FoundInList->domain, &domain)) break;
6747
6748 #if APPLE_OSX_mDNSResponder
6749 if (FoundInList)
6750 {
6751 // If any client tunnel destination is in this domain, set deletion flag to false
6752 ClientTunnel *client;
6753 for (client = m->TunnelClients; client; client = client->next)
6754 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
6755 {
6756 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
6757 client->MarkedForDeletion = mDNSfalse;
6758 }
6759 }
6760
6761 #endif // APPLE_OSX_mDNSResponder
6762
6763 // Uncomment the line below to view the keys as they're read out of the system keychain
6764 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
6765 //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]));
6766 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
6767
6768 // If didn't find desired domain in the list, make a new entry
6769 ptr = FoundInList;
6770 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
6771 if (!FoundInList)
6772 {
6773 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
6774 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
6775 }
6776
6777 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
6778
6779 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
6780 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
6781 {
6782 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
6783 continue;
6784 }
6785
6786 ConvertDomainNameToCString(&domain, stringbuf);
6787 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
6788 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
6789 }
6790 CFRelease(secrets);
6791 }
6792
6793 if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
6794 {
6795 if (privateDnsArray)
6796 CFRelease(privateDnsArray);
6797
6798 privateDnsArray = sa;
6799 CFRetain(privateDnsArray);
6800 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
6801 }
6802 CFRelease(sa);
6803
6804 #if APPLE_OSX_mDNSResponder
6805 {
6806 // clean up ClientTunnels
6807 ClientTunnel **pp = &m->TunnelClients;
6808 while (*pp)
6809 {
6810 if ((*pp)->MarkedForDeletion)
6811 {
6812 ClientTunnel *cur = *pp;
6813 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
6814 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
6815 AutoTunnelSetKeys(cur, mDNSfalse);
6816 *pp = cur->next;
6817 freeL("ClientTunnel", cur);
6818 }
6819 else
6820 pp = &(*pp)->next;
6821 }
6822
6823 mDNSBool needAutoTunnelNAT = mDNSfalse;
6824 DomainAuthInfo *info;
6825 for (info = m->AuthInfoList; info; info = info->next)
6826 {
6827 if (info->AutoTunnel)
6828 {
6829 UpdateAutoTunnelDeviceInfoRecord(m, info);
6830 UpdateAutoTunnelHostRecord(m, info);
6831 UpdateAutoTunnelServiceRecords(m, info);
6832 UpdateAutoTunnel6Record(m, info);
6833 if (info->deltime)
6834 {
6835 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
6836 }
6837 else if (info->AutoTunnelServiceStarted)
6838 needAutoTunnelNAT = true;
6839
6840 UpdateAutoTunnelDomainStatus(m, info);
6841 }
6842 }
6843
6844 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
6845 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
6846 {
6847 // stop the NAT operation, reset port, cleanup state
6848 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
6849 m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
6850 m->AutoTunnelNAT.NewAddress = zerov4Addr;
6851 m->AutoTunnelNAT.ExternalPort = zeroIPPort;
6852 m->AutoTunnelNAT.RequestedPort = zeroIPPort;
6853 m->AutoTunnelNAT.Lifetime = 0;
6854 m->AutoTunnelNAT.Result = mStatus_NoError;
6855 m->AutoTunnelNAT.clientContext = mDNSNULL;
6856 }
6857
6858 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
6859 ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
6860 }
6861 #endif // APPLE_OSX_mDNSResponder
6862
6863 CheckSuppressUnusableQuestions(m);
6864
6865 #endif /* NO_SECURITYFRAMEWORK */
6866 }
6867
6868 mDNSlocal void SetLocalDomains(void)
6869 {
6870 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
6871 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
6872
6873 CFArrayAppendValue(sa, CFSTR("local"));
6874 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
6875 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
6876 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
6877 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
6878 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
6879
6880 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
6881 CFRelease(sa);
6882 }
6883
6884 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
6885 {
6886 #if USE_IOPMCOPYACTIVEPMPREFERENCES
6887 CFTypeRef blob = NULL;
6888 CFStringRef str = NULL;
6889 CFDictionaryRef odict = NULL;
6890 CFDictionaryRef idict = NULL;
6891 CFNumberRef number = NULL;
6892
6893 blob = IOPSCopyPowerSourcesInfo();
6894 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
6895
6896 odict = IOPMCopyActivePMPreferences();
6897 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
6898
6899 str = IOPSGetProvidingPowerSourceType(blob);
6900 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
6901
6902 idict = CFDictionaryGetValue(odict, str);
6903 if (!idict)
6904 {
6905 char buf[256];
6906 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
6907 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
6908 goto end;
6909 }
6910
6911 number = CFDictionaryGetValue(idict, name);
6912 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6913 *val = 0;
6914 end:
6915 if (blob) CFRelease(blob);
6916 if (odict) CFRelease(odict);
6917
6918 #else
6919
6920 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
6921 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
6922 else
6923 {
6924 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
6925 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
6926 else
6927 {
6928 CFNumberRef number = CFDictionaryGetValue(dict, name);
6929 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
6930 *val = 0;
6931 CFRelease(dict);
6932 }
6933 CFRelease(store);
6934 }
6935
6936 #endif
6937 }
6938
6939 #if APPLE_OSX_mDNSResponder
6940
6941 static CFMutableDictionaryRef spsStatusDict = NULL;
6942 static const CFStringRef kMetricRef = CFSTR("Metric");
6943
6944 mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
6945 {
6946 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
6947 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
6948 if (!num)
6949 LogMsg("SPSStatusPutNumber: Could not create CFNumber");
6950 else
6951 {
6952 CFDictionarySetValue(dict, key, num);
6953 CFRelease(num);
6954 }
6955 }
6956
6957 mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
6958 {
6959 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
6960 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
6961
6962 char buffer[1024];
6963 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
6964 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6965 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
6966 CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
6967 CFRelease(spsname);
6968
6969 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
6970 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
6971 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
6972 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
6973
6974 mDNSu32 tmp = SPSMetric(ptr);
6975 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
6976 if (!num)
6977 LogMsg("SPSCreateDict: Could not create CFNumber");
6978 else
6979 {
6980 CFDictionarySetValue(dict, kMetricRef, num);
6981 CFRelease(num);
6982 }
6983
6984 if (ptr[0] >= 12)
6985 {
6986 memcpy(buffer, ptr + 13, ptr[0] - 12);
6987 buffer[ptr[0] - 12] = 0;
6988 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
6989 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
6990 else
6991 {
6992 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
6993 CFRelease(spsname);
6994 }
6995 }
6996
6997 return dict;
6998 }
6999
7000 mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
7001 {
7002 (void)context;
7003 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
7004 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
7005 NULL);
7006 }
7007
7008 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7009 {
7010 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
7011 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
7012
7013 mDNS_Lock(m);
7014 mDNS_UpdateAllowSleep(m);
7015 mDNS_Unlock(m);
7016
7017 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
7018
7019 if (!spsStatusDict)
7020 {
7021 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
7022 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
7023 }
7024
7025 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
7026 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
7027
7028 CFMutableArrayRef array = NULL;
7029
7030 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
7031 {
7032 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7033 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
7034 CFDictionarySetValue(spsStatusDict, ifname, array);
7035 CFRelease(array); // let go of our reference, now that the dict has one
7036 }
7037 else
7038 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
7039
7040 if (!answer) // special call that means the question has been stopped (because the interface is going away)
7041 CFArrayRemoveAllValues(array);
7042 else
7043 {
7044 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
7045 if (!dict) { CFRelease(ifname); return; }
7046
7047 if (AddRecord)
7048 {
7049 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
7050 {
7051 int i=0;
7052 for (i=0; i<CFArrayGetCount(array); i++)
7053 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
7054 break;
7055 CFArrayInsertValueAtIndex(array, i, dict);
7056 }
7057 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
7058 }
7059 else
7060 {
7061 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
7062 if (i != -1) CFArrayRemoveValueAtIndex(array, i);
7063 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
7064 }
7065
7066 CFRelease(dict);
7067 }
7068
7069 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
7070
7071 CFRelease(ifname);
7072 }
7073
7074 mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
7075 {
7076 mDNSs32 val = -1;
7077 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
7078 if (!store)
7079 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7080 else
7081 {
7082 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
7083 if (dict)
7084 {
7085 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
7086 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
7087 CFRelease(dict);
7088 }
7089 CFRelease(store);
7090 }
7091 return val;
7092 }
7093
7094 mDNSlocal void SetSPS(mDNS *const m)
7095 {
7096
7097 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
7098 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
7099
7100 // For devices that are not running NAT, but are set to never sleep, we may choose to act
7101 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
7102 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
7103
7104 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
7105
7106 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
7107 // it makes sense for them to offer low-priority Sleep Proxy service on the network.
7108 // We rate such a device as metric 70 ("Incidentally Available Hardware")
7109 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
7110
7111 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
7112 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
7113 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
7114
7115 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
7116 }
7117
7118 // The definitions below should eventually come from some externally-supplied header file.
7119 // However, since these definitions can't really be changed without breaking binary compatibility,
7120 // they should never change, so in practice it should not be a big problem to have them defined here.
7121
7122 enum
7123 { // commands from the daemon to the driver
7124 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
7125 };
7126
7127 typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
7128
7129 typedef struct
7130 { // cmd_mDNSOffloadRR structure
7131 uint32_t command; // set to OffloadRR
7132 uint32_t rrBufferSize; // number of bytes of RR records
7133 uint32_t numUDPPorts; // number of SRV UDP ports
7134 uint32_t numTCPPorts; // number of SRV TCP ports
7135 uint32_t numRRRecords; // number of RR records
7136 uint32_t compression; // rrRecords - compression is base for compressed strings
7137 FatPtr rrRecords; // address of array of pointers to the rr records
7138 FatPtr udpPorts; // address of udp port list (SRV)
7139 FatPtr tcpPorts; // address of tcp port list (SRV)
7140 } mDNSOffloadCmd;
7141
7142 #include <IOKit/IOKitLib.h>
7143 #include <dns_util.h>
7144
7145 mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
7146 {
7147 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
7148 int count = 0;
7149 AuthRecord *rr;
7150 for (rr = m->ResourceRecords; rr; rr=rr->next)
7151 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
7152 {
7153 if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
7154 count++;
7155 }
7156
7157 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
7158 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
7159 {
7160 LogSPS("GetPortArray Back to My Mac at %d", count);
7161 if (portarray) portarray[count] = IPSECPort;
7162 count++;
7163 }
7164 return(count);
7165 }
7166
7167 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7168 mDNSlocal mDNSBool SupportsTCPKeepAlive()
7169 {
7170 IOReturn ret = kIOReturnSuccess;
7171 CFTypeRef obj = NULL;
7172 mDNSBool supports = mDNSfalse;
7173
7174 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
7175 if ((kIOReturnSuccess == ret) && (obj != NULL))
7176 {
7177 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
7178 CFRelease(obj);
7179 }
7180 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
7181 return supports;
7182 }
7183
7184 mDNSlocal mDNSBool OnBattery(void)
7185 {
7186 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
7187 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
7188 mDNSBool result = mDNSfalse;
7189
7190 if (powerInfo != NULL)
7191 {
7192 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
7193 CFRelease(powerInfo);
7194 }
7195 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
7196 return result;
7197 }
7198
7199 #endif // !TARGET_OS_EMBEDDED
7200
7201 #define TfrRecordToNIC(RR) \
7202 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
7203
7204 mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7205 {
7206 *numbytes = 0;
7207 int count = 0;
7208
7209 AuthRecord *rr;
7210
7211 for (rr = m->ResourceRecords; rr; rr=rr->next)
7212 {
7213 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7214 {
7215 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7216 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7217 // Skip over all other records if we are registering TCP KeepAlive records only
7218 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
7219 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7220 continue;
7221
7222 // Update the record before calculating the number of bytes required
7223 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
7224 // attempt to update the record again.
7225 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
7226 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
7227 #else
7228 (void) TCPKAOnly; // unused
7229 (void) supportsTCPKA; // unused
7230 (void) intf; // unused
7231 #endif // APPLE_OSX_mDNSResponder
7232 if (TfrRecordToNIC(rr))
7233 {
7234 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
7235 LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
7236 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
7237 count++;
7238 }
7239 }
7240 }
7241 return(count);
7242 }
7243
7244 mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
7245 {
7246 mDNSu8 *p = msg->data;
7247 const mDNSu8 *const limit = p + *numbytes;
7248 InitializeDNSMessage(&msg->h, zeroID, zeroID);
7249
7250 int count = 0;
7251 AuthRecord *rr;
7252
7253 for (rr = m->ResourceRecords; rr; rr=rr->next)
7254 {
7255 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
7256 {
7257 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7258 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
7259
7260 // Skip over all other records if we are registering TCP KeepAlive records only
7261 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
7262 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
7263 continue;
7264 #else
7265 (void) TCPKAOnly; // unused
7266 (void) supportsTCPKA; // unused
7267 #endif // APPLE_OSX_mDNSResponder
7268
7269 if (TfrRecordToNIC(rr))
7270 {
7271 records[count].sixtyfourbits = zeroOpaque64;
7272 records[count].ptr = p;
7273 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7274 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
7275 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
7276 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
7277 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
7278 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
7279 count++;
7280 }
7281 }
7282 }
7283 *numbytes = p - msg->data;
7284 }
7285
7286 // If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
7287 // then we declare a dummy version here so that the code at least compiles
7288 #ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
7289 static kern_return_t
7290 IOConnectCallStructMethod(
7291 mach_port_t connection, // In
7292 uint32_t selector, // In
7293 const void *inputStruct, // In
7294 size_t inputStructCnt, // In
7295 void *outputStruct, // Out
7296 size_t *outputStructCnt) // In/Out
7297 {
7298 (void)connection;
7299 (void)selector;
7300 (void)inputStruct;
7301 (void)inputStructCnt;
7302 (void)outputStruct;
7303 (void)outputStructCnt;
7304 LogMsg("Compiled without IOConnectCallStructMethod");
7305 return(KERN_FAILURE);
7306 }
7307 #endif
7308
7309 mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
7310 {
7311 if(!UseInternalSleepProxy)
7312 {
7313 LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled");
7314 return mDNSfalse;
7315 }
7316 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
7317 }
7318
7319 mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held
7320 {
7321 mStatus result = mStatus_UnknownErr;
7322 mDNSBool TCPKAOnly = mDNSfalse;
7323 mDNSBool supportsTCPKA = mDNSfalse;
7324 mDNSBool onbattery = mDNSfalse;
7325 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
7326
7327 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7328 onbattery = OnBattery();
7329 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
7330 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
7331
7332 // Only TCP Keepalive records are to be offloaded if
7333 // - The system is on battery
7334 // - OR wake for network access is not set but powernap is enabled
7335 TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
7336 #else
7337 (void) onbattery; // unused;
7338 #endif
7339 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
7340
7341 io_name_t n1, n2;
7342 IOObjectGetClass(service, n1);
7343 io_object_t parent;
7344 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
7345 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
7346 else
7347 {
7348 IOObjectGetClass(parent, n2);
7349 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
7350 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
7351 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
7352 else
7353 {
7354 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
7355 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
7356 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
7357 else if (!UseInternalSleepProxy)
7358 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
7359 else
7360 {
7361 io_connect_t conObj;
7362 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
7363 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
7364 else
7365 {
7366 mDNSOffloadCmd cmd;
7367 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
7368 cmd.command = cmd_mDNSOffloadRR;
7369 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
7370 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
7371 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
7372 cmd.compression = sizeof(DNSMessageHeader);
7373
7374 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
7375 cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
7376 cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
7377 cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
7378
7379 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7380 msg, cmd.rrBufferSize,
7381 cmd.rrRecords.ptr, cmd.numRRRecords,
7382 cmd.udpPorts.ptr, cmd.numUDPPorts,
7383 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7384
7385 if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
7386 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
7387 msg, cmd.rrBufferSize,
7388 cmd.rrRecords.ptr, cmd.numRRRecords,
7389 cmd.udpPorts.ptr, cmd.numUDPPorts,
7390 cmd.tcpPorts.ptr, cmd.numTCPPorts);
7391 else
7392 {
7393 GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
7394 GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
7395 GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
7396 char outputData[2];
7397 size_t outputDataSize = sizeof(outputData);
7398 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
7399 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
7400 if (kr == KERN_SUCCESS) result = mStatus_NoError;
7401 }
7402
7403 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
7404 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
7405 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
7406 if (msg) freeL("mDNSOffloadCmd msg", msg);
7407 IOServiceClose(conObj);
7408 }
7409 }
7410 CFRelease(ref);
7411 }
7412 IOObjectRelease(parent);
7413 }
7414 IOObjectRelease(service);
7415 return result;
7416 }
7417
7418 #endif // APPLE_OSX_mDNSResponder
7419
7420 mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
7421 {
7422 mDNSs32 val = 0;
7423 mDNSu8 ret = (mDNSu8)mDNS_NoWake;
7424
7425 if (DisableSleepProxyClient)
7426 {
7427 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
7428 return mDNSfalse;
7429 }
7430
7431 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
7432
7433 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
7434
7435 #if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
7436 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
7437 // Further policy decisions on whether to offload the records is handled during sleep processing.
7438 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
7439 ret = (mDNSu8)mDNS_WakeOnBattery;
7440 #endif // APPLE_OSX_mDNSResponder
7441
7442 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
7443 return ret;
7444 }
7445
7446 mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
7447 {
7448 mDNSs32 val = 0;
7449 GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
7450 return val != 0 ? mDNStrue : mDNSfalse;
7451 }
7452
7453 #if APPLE_OSX_mDNSResponder
7454 // When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
7455 // gets deregistered, so that older peers are forced to connect over direct UDP instead of
7456 // the RR relay.
7457 //
7458 // When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
7459 // service records are deregistered, so they do not appear in peers' Finder sidebars.
7460 // We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
7461 // depend on their associated SRV record and therefore will be deregistered together in a
7462 // single update with the SRV record.
7463 //
7464 // Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
7465 // its presence shouldn't delay sleep.
7466 //
7467 // Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
7468 // relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
7469 //
7470 // Also note that returning false here will not delay sleep past the maximum of 10 seconds.
7471 mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
7472 {
7473 if (!AuthRecord_uDNS(rr)) return mDNStrue;
7474
7475 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
7476 {
7477 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7478 return mDNSfalse;
7479 }
7480
7481 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
7482 {
7483 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
7484 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
7485 {
7486 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
7487 if (info && info->AutoTunnel)
7488 {
7489 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
7490 return mDNSfalse;
7491 }
7492 }
7493 }
7494
7495 return mDNStrue;
7496 }
7497
7498 // Caller must hold the lock
7499 mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
7500 {
7501 DomainAuthInfo *info;
7502 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
7503 // deregister the record, and the MemFree callback won't re-register.
7504 m->AutoTunnelRelayAddr = zerov6Addr;
7505 for (info = m->AuthInfoList; info; info = info->next)
7506 if (info->AutoTunnel)
7507 UpdateAutoTunnel6Record(m, info);
7508 }
7509
7510 mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
7511 {
7512 struct ifaddrs *ifa;
7513 struct ifaddrs *ifaddrs;
7514 mDNSAddr addr;
7515
7516 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
7517
7518 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
7519
7520 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
7521 {
7522 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
7523 continue;
7524 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
7525 continue;
7526 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
7527 {
7528 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
7529 continue;
7530 }
7531 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
7532 {
7533 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
7534 break;
7535 }
7536 }
7537 freeifaddrs(ifaddrs);
7538 return ifa != NULL;
7539 }
7540
7541 mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
7542 {
7543 mDNSv6Addr retVal;
7544 struct addrinfo hints;
7545 struct addrinfo *res0;
7546
7547 memset(&hints, 0, sizeof(hints));
7548 hints.ai_family = AF_INET6;
7549 hints.ai_flags = AI_NUMERICHOST;
7550
7551 int err = getaddrinfo(buf, NULL, &hints, &res0);
7552 if (err)
7553 return zerov6Addr;
7554
7555 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
7556
7557 freeaddrinfo(res0);
7558
7559 return retVal;
7560 }
7561
7562 mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
7563 {
7564 SCDynamicStoreRef store = NULL;
7565 CFDictionaryRef connd = NULL;
7566 CFDictionaryRef BTMMDict = NULL;
7567
7568 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL);
7569 if (!store)
7570 {
7571 LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
7572 goto end;
7573 }
7574
7575 connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
7576 if (!connd)
7577 {
7578 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
7579 goto end;
7580 }
7581
7582 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
7583 if (!BTMMDict)
7584 {
7585 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
7586 goto end;
7587 }
7588
7589 // Non-dictionary is treated as non-existent dictionary
7590 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
7591 {
7592 BTMMDict = NULL;
7593 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
7594 goto end;
7595 }
7596
7597 CFRetain(BTMMDict);
7598
7599 end:
7600 if (connd) CFRelease(connd);
7601 if (store) CFRelease(store);
7602
7603 return BTMMDict;
7604 }
7605
7606 #define MAX_IPV6_TEXTUAL 40
7607
7608 mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
7609 {
7610 mDNSv6Addr retVal = zerov6Addr;
7611 CFTypeRef string = NULL;
7612 char ifname[IFNAMSIZ];
7613 char address[MAX_IPV6_TEXTUAL];
7614
7615 if (!BTMMDict)
7616 return zerov6Addr;
7617
7618 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
7619 {
7620 LogInfo("ParseBackToMyMacAddr: interface key does not exist");
7621 return zerov6Addr;
7622 }
7623
7624 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
7625 {
7626 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
7627 return zerov6Addr;
7628 }
7629
7630 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
7631 {
7632 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
7633 return zerov6Addr;
7634 }
7635
7636 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
7637 {
7638 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
7639 return zerov6Addr;
7640 }
7641
7642 retVal = IPv6AddressFromString(address);
7643 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
7644
7645 if (mDNSIPv6AddressIsZero(retVal))
7646 return zerov6Addr;
7647
7648 if (!IPv6AddressIsOnInterface(retVal, ifname))
7649 {
7650 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
7651 return zerov6Addr;
7652 }
7653
7654 return retVal;
7655 }
7656
7657 mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
7658 {
7659 CFTypeRef zones = NULL;
7660
7661 if (!BTMMDict)
7662 return NULL;
7663
7664 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
7665 {
7666 LogInfo("CopyBTMMZones: Zones key does not exist");
7667 return NULL;
7668 }
7669
7670 return zones;
7671 }
7672
7673 mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
7674 {
7675 mDNSv6Addr addr = zerov6Addr;
7676 char buffer[MAX_ESCAPED_DOMAIN_NAME];
7677 CFStringRef domain = NULL;
7678 CFTypeRef theZone = NULL;
7679
7680 if (!zones)
7681 return addr;
7682
7683 ConvertDomainNameToCString(&info->domain, buffer);
7684 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
7685 if (!domain)
7686 return addr;
7687
7688 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
7689 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
7690
7691 CFRelease(domain);
7692
7693 return addr;
7694 }
7695
7696 mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
7697 {
7698 DomainAuthInfo* info;
7699 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
7700 mDNSv6Addr newAddr;
7701
7702 for (info = m->AuthInfoList; info; info = info->next)
7703 {
7704 if (!info->AutoTunnel)
7705 continue;
7706
7707 newAddr = ParseBackToMyMacZone(zones, info);
7708
7709 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
7710 continue;
7711
7712 info->AutoTunnelInnerAddress = newAddr;
7713 DeregisterAutoTunnelHostRecord(m, info);
7714 UpdateAutoTunnelHostRecord(m, info);
7715 UpdateAutoTunnelDomainStatus(m, info);
7716 }
7717 }
7718
7719 // MUST be called holding the lock
7720 mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
7721 {
7722 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
7723 if (!dict)
7724 LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
7725 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
7726
7727 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
7728
7729 SetupBackToMyMacInnerAddresses(m, dict);
7730
7731 if (dict) CFRelease(dict);
7732
7733 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
7734 {
7735 m->AutoTunnelRelayAddr = relayAddr;
7736
7737 DomainAuthInfo* info;
7738 for (info = m->AuthInfoList; info; info = info->next)
7739 if (info->AutoTunnel)
7740 {
7741 DeregisterAutoTunnel6Record(m, info);
7742 UpdateAutoTunnel6Record(m, info);
7743 UpdateAutoTunnelDomainStatus(m, info);
7744 }
7745
7746 // Determine whether we need racoon to accept incoming connections
7747 UpdateAnonymousRacoonConfig(m);
7748 }
7749
7750 // If awacsd crashes or exits for some reason, restart it
7751 UpdateBTMMRelayConnection(m);
7752 }
7753 #endif /* APPLE_OSX_mDNSResponder */
7754
7755 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
7756 {
7757 DNSServer *s;
7758 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
7759 for (s = m->DNSServers; s; s = s->next)
7760 {
7761 if (s->addr.ip.v4.b[0] == 17)
7762 {
7763 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
7764 return mDNStrue;
7765 }
7766 }
7767 return mDNSfalse;
7768 }
7769
7770 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
7771 {
7772 LogInfo("*** Network Configuration Change *** (%d)%s",
7773 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
7774 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
7775 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
7776 mDNSs32 utc = mDNSPlatformUTC();
7777 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
7778 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
7779 MarkAllInterfacesInactive(m, utc);
7780 UpdateInterfaceList(m, utc);
7781 ClearInactiveInterfaces(m, utc);
7782 SetupActiveInterfaces(m, utc);
7783
7784 #if APPLE_OSX_mDNSResponder
7785
7786 mDNS_Lock(m);
7787 ProcessConndConfigChanges(m);
7788 mDNS_Unlock(m);
7789
7790 // Scan to find client tunnels whose questions have completed,
7791 // but whose local inner/outer addresses have changed since the tunnel was set up
7792 ClientTunnel *p;
7793 for (p = m->TunnelClients; p; p = p->next)
7794 if (p->q.ThisQInterval < 0)
7795 {
7796 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
7797 if (!info)
7798 {
7799 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
7800 AutoTunnelSetKeys(p, mDNSfalse);
7801 }
7802 else
7803 {
7804 mDNSv6Addr inner = info->AutoTunnelInnerAddress;
7805
7806 if (!mDNSIPPortIsZero(p->rmt_outer_port))
7807 {
7808 mDNSAddr tmpSrc = zeroAddr;
7809 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
7810 tmpDst.ip.v4 = p->rmt_outer;
7811 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
7812 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7813 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
7814 {
7815 AutoTunnelSetKeys(p, mDNSfalse);
7816 p->loc_inner = inner;
7817 p->loc_outer = tmpSrc.ip.v4;
7818 AutoTunnelSetKeys(p, mDNStrue);
7819 }
7820 }
7821 else
7822 {
7823 if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
7824 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
7825 {
7826 AutoTunnelSetKeys(p, mDNSfalse);
7827 p->loc_inner = inner;
7828 p->loc_outer6 = m->AutoTunnelRelayAddr;
7829 AutoTunnelSetKeys(p, mDNStrue);
7830 }
7831 }
7832 }
7833 }
7834
7835 SetSPS(m);
7836
7837 NetworkInterfaceInfoOSX *i;
7838 for (i = m->p->InterfaceList; i; i = i->next)
7839 {
7840 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
7841 {
7842 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
7843 }
7844 else // else, we're Sleep Proxy Server; open BPF fds
7845 {
7846 if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
7847 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
7848 }
7849 }
7850
7851 #endif // APPLE_OSX_mDNSResponder
7852
7853 uDNS_SetupDNSConfig(m);
7854 mDNS_ConfigChanged(m);
7855
7856 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
7857 {
7858 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
7859 LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
7860 UpdateDebugState();
7861 }
7862
7863 }
7864
7865 // Called with KQueueLock & mDNS lock
7866 mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
7867 {
7868 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
7869 {
7870 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
7871 LogInfo("SetNetworkChanged: scheduling in %d msec", delay);
7872 }
7873 }
7874
7875 // Called with KQueueLock & mDNS lock
7876 mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
7877 {
7878 // If it's not set or it needs to happen sooner than when it's currently set
7879 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
7880 {
7881 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
7882 LogInfo("SetKeyChainTimer: %d", delay);
7883 }
7884 }
7885
7886 // Copy the fourth slash-delimited element from either:
7887 // State:/Network/Interface/<bsdname>/IPv4
7888 // or
7889 // Setup:/Network/Service/<servicename>/Interface
7890 mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
7891 {
7892 CFArrayRef a;
7893 CFStringRef name = NULL;
7894
7895 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
7896 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
7897 if (a != NULL) CFRelease(a);
7898
7899 return name;
7900 }
7901
7902 // Whether a key from a network change notification corresponds to
7903 // an IP service that is explicitly configured for IPv4 Link Local
7904 mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
7905 {
7906 SCDynamicStoreRef store = NULL;
7907 CFDictionaryRef dict = NULL;
7908 CFMutableArrayRef a;
7909 const void **keys = NULL, **vals = NULL;
7910 CFStringRef pattern = NULL;
7911 int i, ic, j, jc;
7912 mDNSBool found = mDNSfalse;
7913
7914 jc = CFArrayGetCount(inkeys);
7915 if (!jc) goto done;
7916
7917 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
7918 if (store == NULL) goto done;
7919
7920 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
7921 if (a == NULL) goto done;
7922
7923 // Setup:/Network/Service/[^/]+/Interface
7924 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
7925 if (pattern == NULL) goto done;
7926 CFArrayAppendValue(a, pattern);
7927 CFRelease(pattern);
7928
7929 // Setup:/Network/Service/[^/]+/IPv4
7930 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
7931 if (pattern == NULL) goto done;
7932 CFArrayAppendValue(a, pattern);
7933 CFRelease(pattern);
7934
7935 dict = SCDynamicStoreCopyMultiple(store, NULL, a);
7936 CFRelease(a);
7937
7938 if (!dict)
7939 {
7940 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
7941 goto done;
7942 }
7943
7944 ic = CFDictionaryGetCount(dict);
7945 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7946 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
7947 CFDictionaryGetKeysAndValues(dict, keys, vals);
7948
7949 for (j = 0; j < jc && !found; j++)
7950 {
7951 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
7952 CFStringRef ifname = NULL;
7953
7954 char buf[256];
7955
7956 // It would be nice to use a regex here
7957 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
7958
7959 if ((ifname = CopyNameFromKey(key)) == NULL) continue;
7960 if (mDNS_LoggingEnabled)
7961 {
7962 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7963 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
7964 }
7965
7966 for (i = 0; i < ic; i++)
7967 {
7968 CFDictionaryRef ipv4dict;
7969 CFStringRef name;
7970 CFStringRef serviceid;
7971 CFStringRef configmethod;
7972
7973 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
7974
7975 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
7976
7977 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
7978
7979 if (!CFEqual(ifname, name)) continue;
7980
7981 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
7982 if (mDNS_LoggingEnabled)
7983 {
7984 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
7985 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
7986 }
7987
7988 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
7989 CFRelease(serviceid);
7990 if (pattern == NULL) continue;
7991
7992 ipv4dict = CFDictionaryGetValue(dict, pattern);
7993 CFRelease(pattern);
7994 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
7995
7996 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
7997 if (!configmethod) continue;
7998
7999 if (mDNS_LoggingEnabled)
8000 {
8001 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8002 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
8003 }
8004
8005 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
8006 }
8007
8008 CFRelease(ifname);
8009 }
8010
8011 done:
8012 if (vals != NULL) mDNSPlatformMemFree(vals);
8013 if (keys != NULL) mDNSPlatformMemFree(keys);
8014 if (dict != NULL) CFRelease(dict);
8015 if (store != NULL) CFRelease(store);
8016
8017 return found;
8018 }
8019
8020 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
8021 {
8022 (void)store; // Parameter not used
8023 mDNSBool changeNow = mDNSfalse;
8024 mDNS *const m = (mDNS *const)context;
8025 KQueueLock(m);
8026 mDNS_Lock(m);
8027
8028 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
8029
8030 int c = CFArrayGetCount(changedKeys); // Count changes
8031 CFRange range = { 0, c };
8032 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
8033 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
8034 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
8035 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
8036 if (c && c - c1 - c2 - c3 - c4 == 0)
8037 delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
8038
8039 // Do immediate network changed processing for "p2p*" interfaces and
8040 // for interfaces with the IFEF_DIRECTLINK flag set.
8041 {
8042 CFArrayRef labels;
8043 CFIndex n;
8044 for (int i = 0; i < c; i++)
8045 {
8046 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
8047
8048 // Only look at keys with prefix "State:/Network/Interface/"
8049 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
8050 continue;
8051
8052 // And suffix "IPv6" or "IPv4".
8053 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
8054 continue;
8055
8056 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
8057 if (labels == NULL)
8058 break;
8059 n = CFArrayGetCount(labels);
8060
8061 // Interface changes will have keys of the form:
8062 // State:/Network/Interface/<interfaceName>/IPv6
8063 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
8064 if (n == 5)
8065 {
8066 char buf[256];
8067
8068 // The 4th label (index = 3) should be the interface name.
8069 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
8070 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK)))
8071 {
8072 LogInfo("NetworkChanged: interface %s, not delaying network change", buf);
8073 changeNow = mDNStrue;
8074 CFRelease(labels);
8075 break;
8076 }
8077 }
8078 CFRelease(labels);
8079 }
8080 }
8081
8082 mDNSBool btmmChanged = CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac);
8083 if (btmmChanged) delay = 0;
8084
8085 if (mDNS_LoggingEnabled)
8086 {
8087 int i;
8088 for (i=0; i<c; i++)
8089 {
8090 char buf[256];
8091 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
8092 LogInfo("*** NetworkChanged SC key: %s", buf);
8093 }
8094 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
8095 c, c>1 ? "s" : "",
8096 c1 ? "(Local Hostname) " : "",
8097 c2 ? "(Computer Name) " : "",
8098 c3 ? "(DynamicDNS) " : "",
8099 c4 ? "(DNS) " : "",
8100 changeNow ? 0 : delay);
8101 }
8102
8103 if (!changeNow)
8104 SetNetworkChanged(m, delay);
8105
8106 // Other software might pick up these changes to register or browse in WAB or BTMM domains,
8107 // so in order for secure updates to be made to the server, make sure to read the keychain and
8108 // setup the DomainAuthInfo before handing the network change.
8109 // If we don't, then we will first try to register services in the clear, then later setup the
8110 // DomainAuthInfo, which is incorrect.
8111 if (c3 || btmmChanged)
8112 SetKeyChainTimer(m, delay);
8113
8114 mDNS_Unlock(m);
8115
8116 // If DNS settings changed, immediately force a reconfig (esp. cache flush)
8117 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
8118 if (c4 || ChangedKeysHaveIPv4LL(changedKeys) || changeNow) mDNSMacOSXNetworkChanged(m);
8119
8120 KQueueUnlock(m, "NetworkChanged");
8121 }
8122
8123 #if APPLE_OSX_mDNSResponder
8124 mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
8125 {
8126 (void)context;
8127 char buf[IFNAMSIZ];
8128
8129 CFStringRef ifnameStr = (CFStringRef)key;
8130 CFArrayRef array = (CFArrayRef)value;
8131 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
8132 buf[0] = 0;
8133
8134 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
8135 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
8136 }
8137 #endif
8138
8139 mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
8140 {
8141 mDNS *const m = (mDNS *const)info;
8142 (void)store;
8143
8144 LogInfo("DynamicStoreReconnected: Reconnected");
8145
8146 // State:/Network/MulticastDNS
8147 SetLocalDomains();
8148
8149 // State:/Network/DynamicDNS
8150 if (m->FQDN.c[0])
8151 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
8152
8153 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
8154 // as we receive network change notifications and thus not necessary. But we leave it here
8155 // so that if things are done differently in the future, this code still works.
8156
8157 // State:/Network/PrivateDNS
8158 if (privateDnsArray)
8159 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
8160
8161 #if APPLE_OSX_mDNSResponder
8162 mDNS_Lock(m);
8163 // State:/Network/BackToMyMac
8164 UpdateAutoTunnelDomainStatuses(m);
8165 mDNS_Unlock(m);
8166
8167 // State:/Network/Interface/en0/SleepProxyServers
8168 if (spsStatusDict)
8169 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
8170 #endif
8171 }
8172
8173 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
8174 {
8175 mStatus err = -1;
8176 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
8177 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
8178 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8179 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
8180 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
8181 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8182
8183 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
8184 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
8185
8186 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
8187 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
8188 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
8189 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
8190 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
8191 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
8192 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
8193 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
8194 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
8195 CFArrayAppendValue(patterns, pattern1);
8196 CFArrayAppendValue(patterns, pattern2);
8197 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
8198 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
8199 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
8200
8201 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
8202 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
8203 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8204 #else
8205 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
8206 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
8207 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
8208 #endif
8209 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
8210 m->p->Store = store;
8211 err = 0;
8212 goto exit;
8213
8214 error:
8215 if (store) CFRelease(store);
8216
8217 exit:
8218 if (patterns) CFRelease(patterns);
8219 if (pattern2) CFRelease(pattern2);
8220 if (pattern1) CFRelease(pattern1);
8221 if (keys) CFRelease(keys);
8222
8223 return(err);
8224 }
8225
8226 #if 0 // <rdar://problem/6751656>
8227 mDNSlocal void PMChanged(void *context)
8228 {
8229 mDNS *const m = (mDNS *const)context;
8230
8231 KQueueLock(m);
8232 mDNS_Lock(m);
8233
8234 LogSPS("PMChanged");
8235
8236 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8237
8238 mDNS_Unlock(m);
8239 KQueueUnlock(m, "PMChanged");
8240 }
8241
8242 mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
8243 {
8244 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
8245 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
8246
8247 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
8248
8249 return mStatus_NoError;
8250 }
8251 #endif
8252
8253 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8254
8255 mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
8256 {
8257 AuthRecord *rr;
8258 pfArray_t portArray;
8259 pfArray_t protocolArray;
8260 uint32_t count = 0;
8261
8262 for (rr = m->ResourceRecords; rr; rr=rr->next)
8263 {
8264 if ((rr->resrec.rrtype == kDNSServiceType_SRV)
8265 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
8266 {
8267 const mDNSu8 *p;
8268
8269 if (count >= PFPortArraySize)
8270 {
8271 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
8272 continue;
8273 }
8274
8275 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
8276 {
8277 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
8278 continue;
8279 }
8280
8281 LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
8282
8283 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
8284
8285 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
8286 p = rr->resrec.name->c;
8287
8288 // Skip to App Protocol
8289 if (p[0]) p += 1 + p[0];
8290
8291 // Skip to Transport Protocol
8292 if (p[0]) p += 1 + p[0];
8293
8294 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP;
8295 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP;
8296 else
8297 {
8298 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
8299 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
8300 return;
8301 }
8302 count++;
8303 }
8304 }
8305 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
8306 }
8307
8308 // If the p2p interface already exists, update the Bonjour packet filter rules for it.
8309 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8310 {
8311 mDNS *const m = &mDNSStorage;
8312
8313 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
8314 while (intf)
8315 {
8316 if (strncmp(intf->ifname, "p2p", 3) == 0)
8317 {
8318 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
8319 mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
8320 break;
8321 }
8322 intf = GetFirstActiveInterface(intf->next);
8323 }
8324 }
8325
8326 #else // !TARGET_OS_EMBEDDED
8327
8328 // Currently no packet filter setup required on embedded platforms.
8329 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
8330 {
8331 (void) excludeRecord; // unused
8332 }
8333
8334 #endif // !TARGET_OS_EMBEDDED
8335
8336 // Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
8337 // marked to include the AWDL interface.
8338 mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
8339 {
8340 char ifname[IFNAMSIZ];
8341 mDNSu32 interfaceIndex;
8342 DNSQuestion *q;
8343 AuthRecord *rr;
8344 NetworkInterfaceInfoOSX *infoOSX;
8345 mDNSInterfaceID InterfaceID;
8346
8347 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
8348 interfaceIndex = if_nametoindex(ifname);
8349
8350 if (!interfaceIndex)
8351 {
8352 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
8353 return;
8354 }
8355
8356 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
8357 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
8358
8359 // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing
8360 // when it is first brought up.
8361 if (!infoOSX)
8362 {
8363 LogInfo("newMasterElected: interface not yet active");
8364 return;
8365 }
8366 InterfaceID = infoOSX->ifinfo.InterfaceID;
8367
8368 for (q = m->Questions; q; q=q->next)
8369 {
8370 if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
8371 || q->InterfaceID == InterfaceID)
8372 {
8373 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
8374 mDNSCoreRestartQuestion(m, q);
8375 }
8376 }
8377
8378 for (rr = m->ResourceRecords; rr; rr=rr->next)
8379 {
8380 if ((!rr->resrec.InterfaceID
8381 && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
8382 || rr->resrec.InterfaceID == InterfaceID)
8383 {
8384 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
8385 mDNSCoreRestartRegistration(m, rr, -1);
8386 }
8387 }
8388 }
8389
8390 // An ssth array of all zeroes indicates the peer has no services registered.
8391 mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
8392 {
8393 int i;
8394 int *intp = (int *) op->ssth;
8395
8396 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
8397 // it's not, print an error message and return false so that
8398 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
8399 // is received.
8400 if (MAX_SSTH_SIZE % sizeof(int))
8401 {
8402 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
8403 return mDNSfalse;
8404 }
8405
8406 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
8407 {
8408 if (*intp)
8409 return mDNSfalse;
8410 }
8411 return mDNStrue;
8412 }
8413
8414 // mDNS_Reconfirm_internal() adds 33% to this interval, so the records should
8415 // be removed in 4 seconds.
8416 #define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3)
8417
8418 // Mark records from this peer for deletion from the cache.
8419 mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap)
8420 {
8421 mDNSu32 slot;
8422 CacheGroup *cg;
8423 CacheRecord *cr;
8424 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex);
8425
8426 if (!InterfaceID)
8427 {
8428 LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex);
8429 return;
8430 }
8431
8432 FORALL_CACHERECORDS(slot, cg, cr)
8433 {
8434 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
8435 {
8436 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
8437 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
8438 mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime);
8439 }
8440 }
8441 }
8442
8443 // Handle KEV_DL_NODE_PRESENCE event.
8444 mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
8445 {
8446 char buf[INET6_ADDRSTRLEN];
8447 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
8448
8449 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8450 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
8451 else
8452 LogInfo("nodePresence: inet_ntop() error");
8453
8454 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
8455 // all zeroes when a node is present and has no services registered.
8456 if (allZeroSSTH(op))
8457 {
8458 mDNSAddr peerAddr;
8459
8460 peerAddr.type = mDNSAddrType_IPv6;
8461 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8462
8463 LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer");
8464 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8465 }
8466 }
8467
8468 // Handle KEV_DL_NODE_ABSENCE event.
8469 mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
8470 {
8471 mDNSAddr peerAddr;
8472 char buf[INET6_ADDRSTRLEN];
8473
8474 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
8475 LogInfo("nodeAbsence: IPv6 address: %s", buf);
8476 else
8477 LogInfo("nodeAbsence: inet_ntop() error");
8478
8479 peerAddr.type = mDNSAddrType_IPv6;
8480 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
8481
8482 LogInfo("nodeAbsence: delete cached records from this peer");
8483 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
8484 }
8485
8486 mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
8487 {
8488 mDNS *const m = (mDNS *const)context;
8489
8490 mDNS_Lock(m);
8491
8492 struct { struct kern_event_msg k; char extra[256]; } msg;
8493 int bytes = recv(s1, &msg, sizeof(msg), 0);
8494 if (bytes < 0)
8495 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
8496 else
8497 {
8498 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
8499 bytes, msg.k.total_size,
8500 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
8501 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
8502 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
8503 msg.k.id, msg.k.event_code,
8504 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
8505 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
8506 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
8507 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
8508 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
8509 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
8510 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
8511 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
8512 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
8513 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
8514 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
8515 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
8516 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
8517 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
8518 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
8519 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
8520 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
8521 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
8522 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
8523 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
8524 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
8525 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
8526 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
8527 "?");
8528
8529 if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
8530 nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
8531
8532 if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
8533 nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
8534
8535 if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
8536 newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
8537
8538 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
8539 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
8540 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
8541 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
8542 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
8543
8544 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
8545 SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
8546
8547 #if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
8548
8549 // For p2p interfaces, need to open the advertised service port in the firewall.
8550 if (msg.k.event_code == KEV_DL_IF_ATTACHED)
8551 {
8552 struct net_event_data * p;
8553 p = (struct net_event_data *) &msg.k.event_data;
8554
8555 if (strncmp(p->if_name, "p2p", 3) == 0)
8556 {
8557 char ifname[IFNAMSIZ];
8558 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8559
8560 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8561
8562 mDNSSetPacketFilterRules(m, ifname, NULL);
8563 }
8564 }
8565
8566 // For p2p interfaces, need to clear the firewall rules on interface detach
8567 if (msg.k.event_code == KEV_DL_IF_DETACHED)
8568 {
8569 struct net_event_data * p;
8570 p = (struct net_event_data *) &msg.k.event_data;
8571
8572 if (strncmp(p->if_name, "p2p", 3) == 0)
8573 {
8574 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
8575 char ifname[IFNAMSIZ];
8576 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
8577
8578 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
8579
8580 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
8581 }
8582 }
8583 #endif // !TARGET_OS_EMBEDDED
8584
8585 }
8586
8587 mDNS_Unlock(m);
8588 }
8589
8590 mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
8591 {
8592 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
8593 if (m->p->SysEventNotifier < 0)
8594 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
8595
8596 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
8597 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
8598 if (err < 0)
8599 {
8600 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
8601 close(m->p->SysEventNotifier);
8602 m->p->SysEventNotifier = -1;
8603 return(mStatus_UnknownErr);
8604 }
8605
8606 m->p->SysEventKQueue.KQcallback = SysEventCallBack;
8607 m->p->SysEventKQueue.KQcontext = m;
8608 m->p->SysEventKQueue.KQtask = "System Event Notifier";
8609 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
8610
8611 return(mStatus_NoError);
8612 }
8613
8614 #ifndef NO_SECURITYFRAMEWORK
8615 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
8616 {
8617 LogInfo("*** Keychain Changed ***");
8618 mDNS *const m = (mDNS *const)context;
8619 SecKeychainRef skc;
8620 OSStatus err = SecKeychainCopyDefault(&skc);
8621 if (!err)
8622 {
8623 if (info->keychain == skc)
8624 {
8625 // 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
8626 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
8627 if (!relevant)
8628 {
8629 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
8630 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
8631 SecKeychainAttributeList *a = NULL;
8632 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
8633 if (!err)
8634 {
8635 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
8636 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
8637 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
8638 SecKeychainItemFreeAttributesAndData(a, NULL);
8639 }
8640 }
8641 if (relevant)
8642 {
8643 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
8644 keychainEvent,
8645 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
8646 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
8647 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
8648 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
8649 KQueueLock(m);
8650 mDNS_Lock(m);
8651
8652 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
8653 // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
8654 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
8655 //
8656 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
8657 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
8658 // a one second delay is ok, as we'll still converge to correctness, and there's no race
8659 // condition between the RegistrationDomain and the DomainAuthInfo.
8660 //
8661 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
8662 // the timer here, as it will not get set by NetworkChanged().
8663 SetKeyChainTimer(m, mDNSPlatformOneSecond);
8664
8665 mDNS_Unlock(m);
8666 KQueueUnlock(m, "KeychainChanged");
8667 }
8668 }
8669 CFRelease(skc);
8670 }
8671
8672 return 0;
8673 }
8674 #endif
8675
8676 mDNSlocal void PowerOn(mDNS *const m)
8677 {
8678 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
8679 if (m->p->WakeAtUTC)
8680 {
8681 long utc = mDNSPlatformUTC();
8682 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
8683 if (m->p->WakeAtUTC - utc > 30)
8684 {
8685 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
8686 }
8687 else if (utc - m->p->WakeAtUTC > 30)
8688 {
8689 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
8690 }
8691 else if (IsAppleTV())
8692 {
8693 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
8694 }
8695 else
8696 {
8697 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
8698 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
8699 }
8700 }
8701 }
8702
8703 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
8704 {
8705 mDNS *const m = (mDNS *const)refcon;
8706 KQueueLock(m);
8707 (void)service; // Parameter not used
8708 debugf("PowerChanged %X %lX", messageType, messageArgument);
8709
8710 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8711 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8712
8713 switch(messageType)
8714 {
8715 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
8716 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
8717 mDNSCoreMachineSleep(m, true);
8718 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8719 break;
8720 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
8721 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
8722 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
8723 mDNSCoreMachineSleep(m, true);
8724 break;
8725 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
8726 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
8727 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
8728 if (m->SleepState)
8729 {
8730 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
8731 PowerOn(m);
8732 }
8733 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
8734 // the System Configuration Framework "network changed" event that we expect
8735 // to receive some time shortly after the kIOMessageSystemWillPowerOn message
8736 mDNS_Lock(m);
8737 if (!m->p->NetworkChanged ||
8738 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
8739 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
8740 mDNS_Unlock(m);
8741
8742 break;
8743 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
8744 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
8745
8746 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
8747 if (m->SleepState != SleepState_Sleeping)
8748 {
8749 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
8750 m->SleepState = SleepState_Sleeping;
8751 mDNSMacOSXNetworkChanged(m);
8752 }
8753 PowerOn(m);
8754 break;
8755 default: LogSPS("PowerChanged unknown message %X", messageType); break;
8756 }
8757
8758 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
8759 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
8760
8761 KQueueUnlock(m, "PowerChanged Sleep/Wake");
8762 }
8763
8764 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
8765 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
8766 #if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
8767 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
8768 {
8769 mDNS *const m = (mDNS *const)refcon;
8770 KQueueLock(m);
8771 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
8772 connection, token, eventDescriptor,
8773 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
8774 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
8775 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
8776 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
8777 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
8778
8779 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
8780 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
8781
8782 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
8783 {
8784 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
8785 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
8786 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
8787 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
8788 if (m->SleepLimit)
8789 {
8790 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8791 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
8792 m->SleepLimit = 0;
8793 }
8794 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
8795 // If the network notifications have already come before we got the wakeup, we ignored them and
8796 // in case we get no more, we need to trigger one.
8797 mDNS_Lock(m);
8798 SetNetworkChanged(m, 2 * mDNSPlatformOneSecond);
8799 mDNS_Unlock(m);
8800 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
8801 if (m->SleepState != SleepState_Awake) PowerOn(m);
8802 IOPMConnectionAcknowledgeEvent(connection, token);
8803 }
8804 else
8805 {
8806 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
8807 // we should hear nothing more until we're told that the CPU has started executing again.
8808 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
8809 //sleep(5);
8810 //mDNSMacOSXNetworkChanged(m);
8811 mDNSCoreMachineSleep(m, true);
8812 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
8813 m->p->SleepCookie = token;
8814 }
8815
8816 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
8817 }
8818 #endif
8819
8820 #if COMPILER_LIKES_PRAGMA_MARK
8821 #pragma mark -
8822 #pragma mark - /etc/hosts support
8823 #endif
8824
8825 // Implementation Notes
8826 //
8827 // As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
8828 // 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
8829 // them into a hash table. The implementation need to be able to do the following things efficiently
8830 //
8831 // 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
8832 // 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
8833 // 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
8834 // need to be able set the RRSet of a resource record to the first one in the list and also update when
8835 // one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
8836 // not a duplicate
8837 // 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
8838 //
8839 // CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
8840 // "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
8841 // of the core layer which does all of the above very efficiently
8842
8843 #define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
8844
8845 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
8846 {
8847 (void)m; // unused
8848 (void)rr;
8849 (void)result;
8850 if (result == mStatus_MemFree)
8851 {
8852 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
8853 freeL("etchosts", rr);
8854 }
8855 }
8856
8857 // Returns true on success and false on failure
8858 mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
8859 {
8860 AuthRecord *rr;
8861 mDNSu32 slot;
8862 mDNSu32 namehash;
8863 AuthGroup *ag;
8864 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
8865 mDNSu16 rrtype;
8866
8867 if (!domain)
8868 {
8869 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
8870 return mDNSfalse;
8871 }
8872 if (!sa && !cname)
8873 {
8874 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
8875 return mDNSfalse;
8876 }
8877
8878 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
8879 {
8880 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
8881 return mDNSfalse;
8882 }
8883
8884
8885 if (ifname)
8886 {
8887 mDNSu32 ifindex = if_nametoindex(ifname);
8888 if (!ifindex)
8889 {
8890 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
8891 return mDNSfalse;
8892 }
8893 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
8894 }
8895
8896 if (sa)
8897 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
8898 else
8899 rrtype = kDNSType_CNAME;
8900
8901 // Check for duplicates. See whether we parsed an entry before like this ?
8902 slot = AuthHashSlot(domain);
8903 namehash = DomainNameHashValue(domain);
8904 ag = AuthGroupForName(auth, slot, namehash, domain);
8905 if (ag)
8906 {
8907 rr = ag->members;
8908 while (rr)
8909 {
8910 if (rr->resrec.rrtype == rrtype)
8911 {
8912 if (rrtype == kDNSType_A)
8913 {
8914 mDNSv4Addr ip;
8915 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8916 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
8917 {
8918 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
8919 return mDNSfalse;
8920 }
8921 }
8922 else if (rrtype == kDNSType_AAAA)
8923 {
8924 mDNSv6Addr ip6;
8925 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8926 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8927 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8928 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8929 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
8930 {
8931 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
8932 return mDNSfalse;
8933 }
8934 }
8935 else if (rrtype == kDNSType_CNAME)
8936 {
8937 if (SameDomainName(&rr->resrec.rdata->u.name, cname))
8938 {
8939 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
8940 return mDNSfalse;
8941 }
8942 }
8943 }
8944 rr = rr->next;
8945 }
8946 }
8947 rr= mallocL("etchosts", sizeof(*rr));
8948 if (rr == NULL) return mDNSfalse;
8949 mDNSPlatformMemZero(rr, sizeof(*rr));
8950 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
8951 AssignDomainName(&rr->namestorage, domain);
8952
8953 if (sa)
8954 {
8955 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
8956 if (sa->sa_family == AF_INET)
8957 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
8958 else
8959 {
8960 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
8961 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
8962 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
8963 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
8964 }
8965 }
8966 else
8967 {
8968 rr->resrec.rdlength = DomainNameLength(cname);
8969 rr->resrec.rdata->u.name.c[0] = 0;
8970 AssignDomainName(&rr->resrec.rdata->u.name, cname);
8971 }
8972 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
8973 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
8974 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
8975 InsertAuthRecord(m, auth, rr);
8976 return mDNStrue;
8977 }
8978
8979 mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
8980 {
8981 int i;
8982
8983 *name = NULL;
8984 for (i = start; i < length; i++)
8985 {
8986 if (buffer[i] == '#')
8987 return -1;
8988 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
8989 {
8990 *name = &buffer[i];
8991
8992 // Found the start of a name, find the end and null terminate
8993 for (i++; i < length; i++)
8994 {
8995 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
8996 {
8997 buffer[i] = 0;
8998 break;
8999 }
9000 }
9001 return i;
9002 }
9003 }
9004 return -1;
9005 }
9006
9007 mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
9008 {
9009 int i;
9010 int ifStart = 0;
9011 char *ifname = NULL;
9012 domainname name1d;
9013 domainname name2d;
9014 char *name1;
9015 char *name2;
9016 int aliasIndex;
9017
9018 //Ignore leading whitespaces and tabs
9019 while (*buffer == ' ' || *buffer == '\t')
9020 {
9021 buffer++;
9022 length--;
9023 }
9024
9025 // Find the end of the address string
9026 for (i = 0; i < length; i++)
9027 {
9028 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
9029 {
9030 if (buffer[i] == '%')
9031 ifStart = i + 1;
9032 buffer[i] = 0;
9033 break;
9034 }
9035 }
9036
9037 // Convert the address string to an address
9038 struct addrinfo hints;
9039 bzero(&hints, sizeof(hints));
9040 hints.ai_flags = AI_NUMERICHOST;
9041 struct addrinfo *gairesults = NULL;
9042 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
9043 {
9044 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
9045 return;
9046 }
9047
9048 if (ifStart)
9049 {
9050 // Parse the interface
9051 ifname = &buffer[ifStart];
9052 for (i = ifStart + 1; i < length; i++)
9053 {
9054 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
9055 {
9056 buffer[i] = 0;
9057 break;
9058 }
9059 }
9060 }
9061
9062 i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
9063 if (i == length)
9064 {
9065 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
9066 if (!MakeDomainNameFromDNSNameString(&name1d, name1))
9067 {
9068 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9069 freeaddrinfo(gairesults);
9070 return;
9071 }
9072 mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
9073 }
9074 else if (i != -1)
9075 {
9076 domainname first;
9077 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
9078 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
9079 // doing the right thing.
9080 if (!MakeDomainNameFromDNSNameString(&first, name1))
9081 {
9082 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
9083 freeaddrinfo(gairesults);
9084 return;
9085 }
9086 // If the /etc/hosts has an entry like this
9087 //
9088 // 1.2.3.4 sun star bright
9089 //
9090 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
9091 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
9092 //
9093 // To achieve this, we need to add the entry like this:
9094 //
9095 // star CNAME bright
9096 // bright CNAME sun
9097 // sun A 1.2.3.4
9098 //
9099 // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
9100 // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
9101 // entry and the first entry. Finally, we add the Address (A/AAAA) record.
9102 aliasIndex = 0;
9103 while (i <= length)
9104 {
9105 // Parse a name. If there are no names, we need to know whether we
9106 // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
9107 // add a CNAME with the last name and the first name. Otherwise, this
9108 // is same as the common case above where the line has just one name
9109 // but with trailing white spaces.
9110 i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
9111 if (name2)
9112 {
9113 if (!MakeDomainNameFromDNSNameString(&name2d, name2))
9114 {
9115 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
9116 freeaddrinfo(gairesults);
9117 return;
9118 }
9119 aliasIndex++;
9120 }
9121 else if (!aliasIndex)
9122 {
9123 // We have never parsed any aliases. This case happens if there
9124 // is just one name and some extra white spaces at the end.
9125 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
9126 break;
9127 }
9128 else
9129 {
9130 // We have parsed at least one alias before and we reached the end of the line.
9131 // Setup a CNAME for the last name with "first" name as its RDATA
9132 name2d.c[0] = 0;
9133 AssignDomainName(&name2d, &first);
9134 }
9135
9136 // Don't add a CNAME for the first alias we parse (see the example above).
9137 // As we parse more, we might discover that there are no more aliases, in
9138 // which case we would have set "name2d" to "first" above. We need to add
9139 // the CNAME in that case.
9140
9141 if (aliasIndex > 1 || SameDomainName(&name2d, &first))
9142 {
9143 // Ignore if it points to itself
9144 if (!SameDomainName(&name1d, &name2d))
9145 {
9146 if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth))
9147 {
9148 freeaddrinfo(gairesults);
9149 return;
9150 }
9151 }
9152 else
9153 LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c);
9154 }
9155
9156 // If we have already wrapped around, we just need to add the A/AAAA record alone
9157 // which is done below
9158 if (SameDomainName(&name2d, &first)) break;
9159
9160 // Remember the current name so that we can set the CNAME record if we parse one
9161 // more name
9162 name1d.c[0] = 0;
9163 AssignDomainName(&name1d, &name2d);
9164 }
9165 // Added all the CNAMEs if any, add the "A/AAAA" record
9166 mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
9167 }
9168 freeaddrinfo(gairesults);
9169 }
9170
9171 mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
9172 {
9173 mDNSBool good;
9174 char buf[ETCHOSTS_BUFSIZE];
9175 ssize_t len;
9176 FILE *fp;
9177
9178 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
9179
9180 fp = fopen("/etc/hosts", "r");
9181 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
9182
9183 while (1)
9184 {
9185 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
9186 if (!good) break;
9187
9188 // skip comment and empty lines
9189 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
9190 continue;
9191
9192 len = strlen(buf);
9193 if (!len) break; // sanity check
9194 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
9195 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9196 {
9197 buf[len - 1] = '\0';
9198 len = len - 1;
9199 }
9200 // fgets always null terminates and hence even if we have no
9201 // newline at the end, it is null terminated. The callee
9202 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
9203 // buf[length] is zero and hence we decrement len to reflect that.
9204 if (len)
9205 {
9206 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
9207 //here we need to check for just \r but taking extra caution.
9208 if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
9209 {
9210 buf[len - 1] = '\0';
9211 len = len - 1;
9212 }
9213 }
9214 if (!len) //Sanity Check: len should never be zero
9215 {
9216 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
9217 continue;
9218 }
9219 mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
9220 }
9221 fclose(fp);
9222 }
9223
9224 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
9225
9226 mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
9227 {
9228 #ifdef __DISPATCH_GROUP__
9229 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9230 static dispatch_queue_t etcq = 0;
9231 static dispatch_source_t etcsrc = 0;
9232 static dispatch_source_t hostssrc = 0;
9233
9234 // First time through? just schedule ourselves on the main queue and we'll do the work later
9235 if (!etcq)
9236 {
9237 etcq = dispatch_get_main_queue();
9238 if (etcq)
9239 {
9240 // Do this work on the queue, not here - solves potential synchronization issues
9241 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9242 }
9243 return -1;
9244 }
9245
9246 if (hostssrc) return dispatch_source_get_handle(hostssrc);
9247 #endif
9248
9249 int fd = open("/etc/hosts", O_RDONLY);
9250
9251 #ifdef __DISPATCH_GROUP__
9252 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
9253 if (fd == -1)
9254 {
9255 // If the open failed and we're already watching /etc, we're done
9256 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
9257
9258 // we aren't watching /etc, we should be
9259 fd = open("/etc", O_RDONLY);
9260 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
9261 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
9262 if (etcsrc == NULL)
9263 {
9264 close(fd);
9265 return -1;
9266 }
9267 dispatch_source_set_event_handler(etcsrc,
9268 ^{
9269 u_int32_t flags = dispatch_source_get_data(etcsrc);
9270 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
9271 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9272 {
9273 dispatch_source_cancel(etcsrc);
9274 dispatch_release(etcsrc);
9275 etcsrc = NULL;
9276 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9277 return;
9278 }
9279 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
9280 {
9281 mDNSMacOSXUpdateEtcHosts(m);
9282 }
9283 });
9284 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
9285 dispatch_resume(etcsrc);
9286
9287 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
9288 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
9289 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
9290 }
9291
9292 // create a dispatch source to watch for changes to hosts file
9293 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
9294 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
9295 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
9296 if (hostssrc == NULL)
9297 {
9298 close(fd);
9299 return -1;
9300 }
9301 dispatch_source_set_event_handler(hostssrc,
9302 ^{
9303 u_int32_t flags = dispatch_source_get_data(hostssrc);
9304 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
9305 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
9306 {
9307 dispatch_source_cancel(hostssrc);
9308 dispatch_release(hostssrc);
9309 hostssrc = NULL;
9310 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
9311 // the block immediately, we try to open the file and the file may not exist and may
9312 // fail to get a notification in the future. When the file does not exist and
9313 // we start to monitor the directory, on "dispatch_resume" of that source, there
9314 // is no guarantee that the file creation will be notified always because when
9315 // the dispatch_resume returns, the kevent manager may not have registered the
9316 // kevent yet but the file may have been created
9317 usleep(1000000);
9318 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
9319 return;
9320 }
9321 if ((flags & DISPATCH_VNODE_WRITE) != 0)
9322 {
9323 mDNSMacOSXUpdateEtcHosts(m);
9324 }
9325 });
9326 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
9327 dispatch_resume(hostssrc);
9328
9329 // Cleanup /etc source, no need to watch it if we already have /etc/hosts
9330 if (etcsrc)
9331 {
9332 dispatch_source_cancel(etcsrc);
9333 dispatch_release(etcsrc);
9334 etcsrc = NULL;
9335 }
9336
9337 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
9338 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
9339 #else
9340 (void)m;
9341 return fd;
9342 #endif
9343 }
9344
9345 // When /etc/hosts is modified, flush all the cache records as there may be local
9346 // authoritative answers now
9347 mDNSlocal void FlushAllCacheRecords(mDNS *const m)
9348 {
9349 CacheRecord *cr;
9350 mDNSu32 slot;
9351 CacheGroup *cg;
9352
9353 FORALL_CACHERECORDS(slot, cg, cr)
9354 {
9355 // Skip multicast.
9356 if (cr->resrec.InterfaceID) continue;
9357
9358 // If a resource record can answer A or AAAA, they need to be flushed so that we will
9359 // never used to deliver an ADD or RMV
9360 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
9361 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
9362 {
9363 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
9364 mDNS_PurgeCacheResourceRecord(m, cr);
9365 }
9366 }
9367 }
9368
9369 // Add new entries to the core. If justCheck is set, this function does not add, just returns true
9370 mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9371 {
9372 AuthGroup *ag;
9373 mDNSu32 slot;
9374 AuthRecord *rr, *primary, *rrnext;
9375 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9376 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
9377 {
9378 primary = NULL;
9379 for (rr = ag->members; rr; rr = rrnext)
9380 {
9381 rrnext = rr->next;
9382 AuthGroup *ag1;
9383 AuthRecord *rr1;
9384 mDNSBool found = mDNSfalse;
9385 ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
9386 if (ag1 && ag1->members)
9387 {
9388 if (!primary) primary = ag1->members;
9389 rr1 = ag1->members;
9390 while (rr1)
9391 {
9392 // We are not using InterfaceID in checking for duplicates. This means,
9393 // if there are two addresses for a given name e.g., fe80::1%en0 and
9394 // fe80::1%en1, we only add the first one. It is not clear whether
9395 // this is a common case. To fix this, we also need to modify
9396 // mDNS_Register_internal in how it handles duplicates. If it becomes a
9397 // common case, we will fix it then.
9398 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9399 {
9400 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
9401 found = mDNStrue;
9402 break;
9403 }
9404 rr1 = rr1->next;
9405 }
9406 }
9407 if (!found)
9408 {
9409 if (justCheck)
9410 {
9411 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
9412 return mDNStrue;
9413 }
9414 RemoveAuthRecord(m, newhosts, rr);
9415 // if there is no primary, point to self
9416 rr->RRSet = (primary ? primary : rr);
9417 rr->next = NULL;
9418 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
9419 if (mDNS_Register_internal(m, rr) != mStatus_NoError)
9420 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
9421 }
9422 }
9423 }
9424 return mDNSfalse;
9425 }
9426
9427 // Delete entries from the core that are no longer needed. If justCheck is set, this function
9428 // does not delete, just returns true
9429 mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
9430 {
9431 AuthGroup *ag;
9432 mDNSu32 slot;
9433 AuthRecord *rr, *primary, *rrnext;
9434 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9435 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
9436 for (rr = ag->members; rr; rr = rrnext)
9437 {
9438 mDNSBool found = mDNSfalse;
9439 AuthGroup *ag1;
9440 AuthRecord *rr1;
9441 rrnext = rr->next;
9442 if (rr->RecordCallback != FreeEtcHosts) continue;
9443 ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
9444 if (ag1)
9445 {
9446 primary = rr1 = ag1->members;
9447 while (rr1)
9448 {
9449 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
9450 {
9451 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
9452 found = mDNStrue;
9453 break;
9454 }
9455 rr1 = rr1->next;
9456 }
9457 }
9458 // there is no corresponding record in newhosts for the same name. This means
9459 // we should delete this from the core.
9460 if (!found)
9461 {
9462 if (justCheck)
9463 {
9464 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
9465 return mDNStrue;
9466 }
9467 // if primary is going away, make sure that the rest of the records
9468 // point to the new primary
9469 if (rr == ag->members)
9470 {
9471 AuthRecord *new_primary = rr->next;
9472 AuthRecord *r = new_primary;
9473 while (r)
9474 {
9475 if (r->RRSet == rr)
9476 {
9477 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
9478 r->RRSet = new_primary;
9479 }
9480 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
9481 r = r->next;
9482 }
9483 }
9484 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
9485 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9486 }
9487 }
9488 return mDNSfalse;
9489 }
9490
9491 mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
9492 {
9493 AuthHash *newhosts = (AuthHash *)context;
9494
9495 mDNS_CheckLock(m);
9496
9497 //Delete old entries from the core if they are not present in the newhosts
9498 EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
9499 // Add the new entries to the core if not already present in the core
9500 EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
9501 }
9502
9503 mDNSlocal void FreeNewHosts(AuthHash *newhosts)
9504 {
9505 mDNSu32 slot;
9506 AuthGroup *ag, *agnext;
9507 AuthRecord *rr, *rrnext;
9508
9509 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
9510 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
9511 {
9512 agnext = ag->next;
9513 for (rr = ag->members; rr; rr = rrnext)
9514 {
9515 rrnext = rr->next;
9516 freeL("etchosts", rr);
9517 }
9518 freeL("AuthGroups", ag);
9519 }
9520 }
9521
9522 mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
9523 {
9524 AuthHash newhosts;
9525
9526 // As we will be modifying the core, we can only have one thread running at
9527 // any point in time.
9528 KQueueLock(m);
9529
9530 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
9531
9532 // Get the file desecriptor (will trigger us to start watching for changes)
9533 int fd = mDNSMacOSXGetEtcHostsFD(m);
9534 if (fd != -1)
9535 {
9536 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
9537 mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
9538 }
9539 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
9540
9541 // Optimization: Detect whether /etc/hosts changed or not.
9542 //
9543 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
9544 // newhosts is already registered with core. If we find at least one entry that is not
9545 // registered with core, then it means we have work to do.
9546 //
9547 // 2. Next, we check to see if any of the entries that are registered with core is not present
9548 // in newhosts. If we find at least one entry that is not present, it means we have work to
9549 // do.
9550 //
9551 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
9552 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
9553 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
9554 // in the future and this code does not have to change.
9555 mDNS_Lock(m);
9556 // Add the new entries to the core if not already present in the core
9557 if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
9558 {
9559 // No new entries to add, check to see if we need to delete any old entries from the
9560 // core if they are not present in the newhosts
9561 if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
9562 {
9563 LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
9564 mDNS_Unlock(m);
9565 KQueueUnlock(m, "/etc/hosts changed");
9566 FreeNewHosts(&newhosts);
9567 return;
9568 }
9569 }
9570
9571 // This will flush the cache, stop and start the query so that the queries
9572 // can look at the /etc/hosts again
9573 //
9574 // Notes:
9575 //
9576 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
9577 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
9578 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
9579 // delivers these events in the right order and then calls us back to delete them.
9580 //
9581 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
9582 // is a common function that looks at all local auth records and delivers a RMV including
9583 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
9584 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
9585 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
9586 // is called back where we do the Registration of the record. This results in RMV followed by ADD which
9587 // looks normal.
9588 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
9589 mDNS_Unlock(m);
9590
9591 KQueueUnlock(m, "/etc/hosts changed");
9592 FreeNewHosts(&newhosts);
9593 }
9594
9595 #if COMPILER_LIKES_PRAGMA_MARK
9596 #pragma mark -
9597 #pragma mark - Initialization & Teardown
9598 #endif
9599
9600 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
9601 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
9602 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
9603 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
9604
9605 // Major version 13 is 10.9.x
9606 mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
9607 {
9608 int major = 0, minor = 0;
9609 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
9610 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
9611 if (vers)
9612 {
9613 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
9614 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
9615 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
9616 if (cfprodname)
9617 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
9618 if (cfprodvers)
9619 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
9620 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
9621 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
9622 CFRelease(vers);
9623 }
9624 if (!major)
9625 {
9626 major = 13;
9627 LogMsg("Note: No Major Build Version number found; assuming 13");
9628 }
9629 if (HINFO_SWstring)
9630 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
9631 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
9632
9633 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
9634 if ((prodname[0] & 0xDF) == 'M')
9635 OSXVers = major;
9636 else
9637 iOSVers = major;
9638 }
9639
9640 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
9641 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
9642 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
9643 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
9644 {
9645 int err = -1;
9646 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
9647 if (s < 3)
9648 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
9649 else
9650 {
9651 struct sockaddr_in s5353;
9652 s5353.sin_family = AF_INET;
9653 s5353.sin_port = MulticastDNSPort.NotAnInteger;
9654 s5353.sin_addr.s_addr = 0;
9655 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
9656 close(s);
9657 }
9658
9659 if (err) LogMsg("No unicast UDP responses");
9660 else debugf("Unicast UDP responses okay");
9661 return(err == 0);
9662 }
9663
9664 mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
9665 {
9666 AuthRecord *rr;
9667 const domainname *pname = (domainname *)"\x9" "localhost";
9668
9669 rr= mallocL("localhosts", sizeof(*rr));
9670 if (rr == NULL) return;
9671 mDNSPlatformMemZero(rr, sizeof(*rr));
9672
9673 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
9674 AssignDomainName(&rr->namestorage, domain);
9675
9676 rr->resrec.rdlength = DomainNameLength(pname);
9677 rr->resrec.rdata->u.name.c[0] = 0;
9678 AssignDomainName(&rr->resrec.rdata->u.name, pname);
9679
9680 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
9681 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
9682 mDNS_Register(m, rr);
9683 }
9684
9685 // Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
9686 // on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
9687 // fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
9688 // a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
9689 //
9690 // Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
9691 // intentionally to avoid adding to the complexity of code handling /etc/hosts.
9692 mDNSlocal void SetupLocalHostRecords(mDNS *const m)
9693 {
9694 char buffer[MAX_REVERSE_MAPPING_NAME];
9695 domainname name;
9696 int i;
9697 struct in6_addr addr;
9698 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
9699
9700 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
9701 {
9702 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
9703 ptr[3], ptr[2], ptr[1], ptr[0]);
9704 MakeDomainNameFromDNSNameString(&name, buffer);
9705 CreatePTRRecord(m, &name);
9706 }
9707 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
9708
9709 if (inet_pton(AF_INET6, "::1", &addr) == 1)
9710 {
9711 for (i = 0; i < 16; i++)
9712 {
9713 static const char hexValues[] = "0123456789ABCDEF";
9714 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
9715 buffer[i * 4 + 1] = '.';
9716 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
9717 buffer[i * 4 + 3] = '.';
9718 }
9719 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
9720 MakeDomainNameFromDNSNameString(&name, buffer);
9721 CreatePTRRecord(m, &name);
9722 }
9723 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
9724 }
9725
9726 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
9727 // 1) query for b._dns-sd._udp.local on LocalOnly interface
9728 // (.local manually generated via explicit callback)
9729 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
9730 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
9731 // 4) result above should generate a callback from question in (1). result added to global list
9732 // 5) global list delivered to client via GetSearchDomainList()
9733 // 6) client calls to enumerate domains now go over LocalOnly interface
9734 // (!!!KRS may add outgoing interface in addition)
9735
9736 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
9737 {
9738 mStatus err;
9739 m->p->CFRunLoop = CFRunLoopGetCurrent();
9740
9741 char HINFO_SWstring[256] = "";
9742 mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
9743
9744 err = mDNSHelperInit();
9745 if (err)
9746 return err;
9747
9748 DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL);
9749 if (DynamicStoreQueue == NULL)
9750 {
9751 LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!");
9752 return mStatus_NoMemoryErr;
9753 }
9754
9755 // Store mDNSResponder Platform
9756 if (OSXVers)
9757 {
9758 m->mDNS_plat = platform_OSX;
9759 }
9760 else if (iOSVers)
9761 {
9762 if (IsAppleTV())
9763 m->mDNS_plat = platform_Atv;
9764 else
9765 m->mDNS_plat = platform_iOS;
9766 }
9767 else
9768 {
9769 m->mDNS_plat = platform_NonApple;
9770 }
9771
9772 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
9773 // 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.
9774 int i;
9775 for (i=0; i<100; i++)
9776 {
9777 domainlabel testlabel;
9778 testlabel.c[0] = 0;
9779 GetUserSpecifiedLocalHostName(&testlabel);
9780 if (testlabel.c[0]) break;
9781 usleep(50000);
9782 }
9783
9784 m->hostlabel.c[0] = 0;
9785
9786 int get_model[2] = { CTL_HW, HW_MODEL };
9787 size_t len_model = sizeof(HINFO_HWstring_buffer);
9788
9789 // Normal Apple model names are of the form "iPhone2,1", and
9790 // internal code names are strings containing no commas, e.g. "N88AP".
9791 // We used to ignore internal code names, but Apple now uses these internal code names
9792 // even in released shipping products, so we no longer ignore strings containing no commas.
9793 // if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
9794 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
9795 HINFO_HWstring = HINFO_HWstring_buffer;
9796
9797 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
9798 // For names of the form "N88AP" containg no comma, we use the entire string.
9799 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
9800
9801 if (mDNSPlatformInit_CanReceiveUnicast())
9802 m->CanReceiveUnicastOn5353 = mDNStrue;
9803
9804 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
9805 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
9806 if (hlen + slen < 254)
9807 {
9808 m->HIHardware.c[0] = hlen;
9809 m->HISoftware.c[0] = slen;
9810 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
9811 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
9812 }
9813
9814 m->p->permanentsockets.port = MulticastDNSPort;
9815 m->p->permanentsockets.m = m;
9816 m->p->permanentsockets.sktv4 = -1;
9817 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
9818 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
9819 m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
9820 m->p->permanentsockets.sktv6 = -1;
9821 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
9822 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
9823 m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
9824
9825 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
9826 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
9827
9828 struct sockaddr_in s4;
9829 socklen_t n4 = sizeof(s4);
9830 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
9831 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
9832 else
9833 m->UnicastPort4.NotAnInteger = s4.sin_port;
9834
9835 if (m->p->permanentsockets.sktv6 >= 0)
9836 {
9837 struct sockaddr_in6 s6;
9838 socklen_t n6 = sizeof(s6);
9839 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
9840 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
9841 }
9842
9843 m->p->InterfaceList = mDNSNULL;
9844 m->p->userhostlabel.c[0] = 0;
9845 m->p->usernicelabel.c[0] = 0;
9846 m->p->prevoldnicelabel.c[0] = 0;
9847 m->p->prevnewnicelabel.c[0] = 0;
9848 m->p->prevoldhostlabel.c[0] = 0;
9849 m->p->prevnewhostlabel.c[0] = 0;
9850 m->p->NotifyUser = 0;
9851 m->p->KeyChainTimer = 0;
9852 m->p->WakeAtUTC = 0;
9853 m->p->RequestReSleep = 0;
9854 // Assume that everything is good to begin with. If something is not working,
9855 // we will detect that when we start sending questions.
9856 m->p->v4answers = 1;
9857 m->p->v6answers = 1;
9858 m->p->DNSTrigger = 0;
9859 m->p->LastConfigGeneration = 0;
9860
9861 #if APPLE_OSX_mDNSResponder
9862 uuid_generate(m->asl_uuid);
9863 #endif
9864
9865 m->AutoTunnelRelayAddr = zerov6Addr;
9866
9867 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
9868 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
9869 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
9870 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
9871 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
9872 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
9873 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
9874 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
9875
9876 err = WatchForNetworkChanges(m);
9877 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
9878
9879 #if 0 // <rdar://problem/6751656>
9880 err = WatchForPMChanges(m);
9881 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
9882 #endif
9883
9884 err = WatchForSysEvents(m);
9885 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
9886
9887 mDNSs32 utc = mDNSPlatformUTC();
9888 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
9889 UpdateInterfaceList(m, utc);
9890 SetupActiveInterfaces(m, utc);
9891
9892 // Explicitly ensure that our Keychain operations utilize the system domain.
9893 #ifndef NO_SECURITYFRAMEWORK
9894 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
9895 #endif
9896
9897 mDNS_Lock(m);
9898 SetDomainSecrets(m);
9899 SetLocalDomains();
9900 mDNS_Unlock(m);
9901
9902 #ifndef NO_SECURITYFRAMEWORK
9903 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
9904 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
9905 #endif
9906
9907 #if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
9908 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
9909 #else
9910 IOPMConnection c;
9911 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
9912 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
9913 else
9914 {
9915 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
9916 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
9917 else
9918 {
9919 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9920 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
9921 LogInfo("IOPMConnectionSetDispatchQueue is now running");
9922 #else
9923 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
9924 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
9925 LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
9926 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9927 }
9928 }
9929 m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
9930 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
9931 #endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
9932 {
9933 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
9934 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
9935 else
9936 {
9937 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
9938 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
9939 #else
9940 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
9941 #endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
9942 }
9943 }
9944
9945 #if APPLE_OSX_mDNSResponder
9946 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
9947 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
9948 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
9949 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
9950 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9951 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9952 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
9953 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
9954 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
9955 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
9956 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
9957 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
9958 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
9959 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9960 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
9961 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
9962 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
9963 #endif // APPLE_OSX_mDNSResponder
9964
9965 // Currently this is not defined. SSL code will eventually fix this. If it becomes
9966 // critical, we will define this to workaround the bug in SSL.
9967 #ifdef __SSL_NEEDS_SERIALIZATION__
9968 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
9969 #else
9970 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
9971 #endif
9972 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
9973
9974 mDNSMacOSXUpdateEtcHosts(m);
9975 SetupLocalHostRecords(m);
9976 CUPInit(m);
9977
9978 return(mStatus_NoError);
9979 }
9980
9981 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
9982 {
9983 #if MDNS_NO_DNSINFO
9984 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
9985 #endif
9986
9987 // Adding interfaces will use this flag, so set it now.
9988 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
9989
9990 #if APPLE_OSX_mDNSResponder
9991 m->SPSBrowseCallback = UpdateSPSStatus;
9992 #endif // APPLE_OSX_mDNSResponder
9993
9994 mStatus result = mDNSPlatformInit_setup(m);
9995
9996 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
9997 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
9998 if (result == mStatus_NoError)
9999 {
10000 mDNSCoreInitComplete(m, mStatus_NoError);
10001
10002 #if !NO_D2D
10003 // We only initialize if mDNSCore successfully initialized.
10004 if (D2DInitialize)
10005 {
10006 D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
10007 if (ds != kD2DSuccess)
10008 LogMsg("D2DInitialiize failed: %d", ds);
10009 else
10010 LogMsg("D2DInitialize succeeded");
10011 }
10012 #endif // ! NO_D2D
10013
10014 }
10015 result = DNSSECCryptoInit(m);
10016 return(result);
10017 }
10018
10019 mDNSexport void mDNSPlatformClose(mDNS *const m)
10020 {
10021 if (m->p->PowerConnection)
10022 {
10023 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10024 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
10025 #else
10026 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
10027 #endif
10028 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
10029 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
10030 IODeregisterForSystemPower(&m->p->PowerNotifier);
10031 IOServiceClose ( m->p->PowerConnection);
10032 IONotificationPortDestroy ( m->p->PowerPortRef);
10033 m->p->PowerConnection = 0;
10034 }
10035
10036 if (m->p->Store)
10037 {
10038 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10039 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
10040 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
10041 #else
10042 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
10043 CFRunLoopSourceInvalidate(m->p->StoreRLS);
10044 CFRelease(m->p->StoreRLS);
10045 m->p->StoreRLS = NULL;
10046 #endif
10047 CFRelease(m->p->Store);
10048 m->p->Store = NULL;
10049 }
10050
10051 if (m->p->PMRLS)
10052 {
10053 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
10054 CFRunLoopSourceInvalidate(m->p->PMRLS);
10055 CFRelease(m->p->PMRLS);
10056 m->p->PMRLS = NULL;
10057 }
10058
10059 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
10060
10061 #if !NO_D2D
10062 if (D2DTerminate)
10063 {
10064 D2DStatus ds = D2DTerminate();
10065 if (ds != kD2DSuccess)
10066 LogMsg("D2DTerminate failed: %d", ds);
10067 else
10068 LogMsg("D2DTerminate succeeded");
10069 }
10070 #endif // ! NO_D2D
10071
10072 mDNSs32 utc = mDNSPlatformUTC();
10073 MarkAllInterfacesInactive(m, utc);
10074 ClearInactiveInterfaces(m, utc);
10075 CloseSocketSet(&m->p->permanentsockets);
10076
10077 #if APPLE_OSX_mDNSResponder
10078 // clean up tunnels
10079 while (m->TunnelClients)
10080 {
10081 ClientTunnel *cur = m->TunnelClients;
10082 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
10083 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
10084 AutoTunnelSetKeys(cur, mDNSfalse);
10085 m->TunnelClients = cur->next;
10086 freeL("ClientTunnel", cur);
10087 }
10088
10089 if (AnonymousRacoonConfig)
10090 {
10091 AnonymousRacoonConfig = mDNSNULL;
10092 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
10093 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL);
10094 }
10095 #endif // APPLE_OSX_mDNSResponder
10096 }
10097
10098 #if COMPILER_LIKES_PRAGMA_MARK
10099 #pragma mark -
10100 #pragma mark - General Platform Support Layer functions
10101 #endif
10102
10103 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
10104 {
10105 return(arc4random());
10106 }
10107
10108 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
10109 mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
10110
10111 mDNSexport mStatus mDNSPlatformTimeInit(void)
10112 {
10113 // Notes: Typical values for mach_timebase_info:
10114 // tbi.numer = 1000 million
10115 // tbi.denom = 33 million
10116 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
10117 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
10118 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
10119 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
10120 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
10121 //
10122 // Arithmetic notes:
10123 // tbi.denom is at least 1, and not more than 2^32-1.
10124 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
10125 // tbi.denom is at least 1, and not more than 2^32-1.
10126 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
10127 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
10128 // which is unlikely on any current or future Macintosh.
10129 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
10130 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
10131 struct mach_timebase_info tbi;
10132 kern_return_t result = mach_timebase_info(&tbi);
10133 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
10134 return(result);
10135 }
10136
10137 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
10138 {
10139 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
10140
10141 static uint64_t last_mach_absolute_time = 0;
10142 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
10143 uint64_t this_mach_absolute_time = mach_absolute_time();
10144 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
10145 {
10146 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
10147 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
10148 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
10149 last_mach_absolute_time = this_mach_absolute_time;
10150 // Note: This bug happens all the time on 10.3
10151 NotifyOfElusiveBug("mach_absolute_time went backwards!",
10152 "This error occurs from time to time, often on newly released hardware, "
10153 "and usually the exact cause is different in each instance.\r\r"
10154 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
10155 "and assign it to Radar Component “Kernel” Version “X”.");
10156 }
10157 last_mach_absolute_time = this_mach_absolute_time;
10158
10159 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
10160 }
10161
10162 mDNSexport mDNSs32 mDNSPlatformUTC(void)
10163 {
10164 return time(NULL);
10165 }
10166
10167 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
10168 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
10169 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
10170 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
10171 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
10172 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
10173 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
10174 mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
10175 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
10176 mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
10177 {
10178 return (qsort(base, nel, width, compar));
10179 }
10180 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
10181 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
10182 #endif
10183 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
10184
10185 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
10186 {
10187 if (allowSleep && m->p->IOPMAssertion)
10188 {
10189 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
10190 IOPMAssertionRelease(m->p->IOPMAssertion);
10191 m->p->IOPMAssertion = 0;
10192 }
10193 else if (!allowSleep)
10194 {
10195 #ifdef kIOPMAssertionTypeNoIdleSleep
10196 if (m->p->IOPMAssertion)
10197 {
10198 IOPMAssertionRelease(m->p->IOPMAssertion);
10199 m->p->IOPMAssertion = 0;
10200 }
10201
10202 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
10203 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
10204 if (assertionName) CFRelease(assertionName);
10205 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
10206 #endif
10207 }
10208 }
10209
10210 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
10211 {
10212 mDNSu32 ifindex;
10213
10214 // Sanity check
10215 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
10216 if (ifindex <= 0)
10217 {
10218 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
10219 return;
10220 }
10221 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
10222 }
10223
10224 mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
10225 {
10226 NetworkInterfaceInfoOSX *info;
10227
10228 if (InterfaceID == mDNSInterface_P2P)
10229 return mDNStrue;
10230
10231 if ( (InterfaceID == mDNSInterface_Any)
10232 || (InterfaceID == mDNSInterfaceMark)
10233 || (InterfaceID == mDNSInterface_LocalOnly)
10234 || (InterfaceID == mDNSInterface_Unicast))
10235 return mDNSfalse;
10236
10237 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
10238 if (info == NULL)
10239 {
10240 // this log message can print when operations are stopped on an interface that has gone away
10241 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
10242 return mDNSfalse;
10243 }
10244
10245 return (mDNSBool) info->D2DInterface;
10246 }
10247
10248 // Filter records send over P2P (D2D) type interfaces
10249 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
10250 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
10251 {
10252 // For an explicit match to a valid interface ID, return true.
10253 if (rr->resrec.InterfaceID == intf->InterfaceID)
10254 return mDNStrue;
10255
10256 // Only filtering records for D2D type interfaces, return true for all other interface types.
10257 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10258 return mDNStrue;
10259
10260 // If it's an AWDL interface the record must be explicitly marked to include AWDL.
10261 if (intf->InterfaceID == AWDLInterfaceID)
10262 {
10263 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10264 return mDNStrue;
10265 else
10266 return mDNSfalse;
10267 }
10268
10269 // Send record if it is explicitly marked to include all other P2P type interfaces.
10270 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
10271 return mDNStrue;
10272
10273 // Don't send the record over this interface.
10274 return mDNSfalse;
10275 }
10276
10277 // Filter questions send over P2P (D2D) type interfaces.
10278 mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
10279 {
10280 // For an explicit match to a valid interface ID, return true.
10281 if (q->InterfaceID == intf->InterfaceID)
10282 return mDNStrue;
10283
10284 // Only filtering questions for D2D type interfaces
10285 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
10286 return mDNStrue;
10287
10288 // If it's an AWDL interface the question must be explicitly marked to include AWDL.
10289 if (intf->InterfaceID == AWDLInterfaceID)
10290 {
10291 if (q->flags & kDNSServiceFlagsIncludeAWDL)
10292 return mDNStrue;
10293 else
10294 return mDNSfalse;
10295 }
10296
10297 // Sent question if it is explicitly marked to include all other P2P type interfaces.
10298 if (q->flags & kDNSServiceFlagsIncludeP2P)
10299 return mDNStrue;
10300
10301 // Don't send the question over this interface.
10302 return mDNSfalse;
10303 }
10304
10305 // Returns true unless record was received over the AWDL interface and
10306 // the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
10307 // with the kDNSServiceFlagsIncludeAWDL flag set.
10308 mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
10309 {
10310 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
10311 return mDNStrue;
10312
10313 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
10314 {
10315 LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query",
10316 DNSTypeName(q->qtype), q->qname.c);
10317 return mDNSfalse;
10318 }
10319
10320 return mDNStrue;
10321 }
10322
10323 // formating time to RFC 4034 format
10324 mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
10325 {
10326 struct tm tmTime;
10327 time_t t = (time_t)te;
10328 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
10329 // gmtime_r first and then use strftime
10330 gmtime_r(&t, &tmTime);
10331 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
10332 }
10333
10334 mDNSexport mDNSs32 mDNSPlatformGetPID()
10335 {
10336 return getpid();
10337 }
10338
10339 // Schedule a function asynchronously on the main queue
10340 mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
10341 {
10342 // KQueueLock/Unlock is used for two purposes
10343 //
10344 // 1. We can't be running along with the KQueue thread and hence acquiring the lock
10345 // serializes the access to the "core"
10346 //
10347 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
10348 // up and calls udsserver_idle which schedules the messages across the uds socket.
10349 // If "func" delivers something to the uds socket from the dispatch thread, it will
10350 // not be delivered immediately if not for the Unlock.
10351 dispatch_async(dispatch_get_main_queue(), ^{
10352 KQueueLock(m);
10353 func(m, context);
10354 KQueueUnlock(m, "mDNSPlatformDispatchAsync");
10355 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
10356 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
10357 // to handle any message that "func" might deliver.
10358 TriggerEventCompletion();
10359 #endif
10360 });
10361 }
10362
10363 // definitions for device-info record construction
10364 #define DEVINFO_MODEL "model="
10365 #define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL)
10366
10367 #define OSX_VER "osxvers="
10368 #define OSX_VER_LEN strlen(OSX_VER)
10369 #define VER_NUM_LEN 2 // 2 digits of version number added to base string
10370
10371 // Bytes available in TXT record for model name after subtracting space for other
10372 // fixed size strings and their length bytes.
10373 #define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1))
10374
10375 // Initialize device-info TXT record contents and return total length of record data.
10376 mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
10377 {
10378 mDNSu8 *bufferStart = ptr;
10379 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
10380
10381 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
10382 ptr++;
10383 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
10384 ptr += DEVINFO_MODEL_LEN;
10385 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
10386 ptr += len;
10387
10388 // only include this string for OSX
10389 if (OSXVers)
10390 {
10391 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
10392 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
10393 ptr++;
10394 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
10395 ptr += OSX_VER_LEN;
10396 // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
10397 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
10398 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
10399 ptr += VER_NUM_LEN;
10400 }
10401
10402 return (ptr - bufferStart);
10403 }