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