1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18// *************************************************************************** 19// mDNSMacOSX.c: 20// Supporting routines to run mDNS on a CFRunLoop platform 21// *************************************************************************** 22 23// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces, 24// including ones that mDNSResponder chooses not to use. 25#define LIST_ALL_INTERFACES 0 26 27#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above 28#include "DNSCommon.h" 29#include "uDNS.h" 30#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform 31#include "dns_sd.h" // For mDNSInterface_LocalOnly etc. 32#include "PlatformCommon.h" 33#include "uds_daemon.h" 34#include "CryptoSupport.h" 35 36#include <stdio.h> 37#include <stdarg.h> // For va_list support 38#include <stdlib.h> // For arc4random 39#include <net/if.h> 40#include <net/if_types.h> // For IFT_ETHER 41#include <net/if_dl.h> 42#include <net/bpf.h> // For BIOCSETIF etc. 43#include <sys/uio.h> 44#include <sys/param.h> 45#include <sys/socket.h> 46#include <sys/sysctl.h> 47#include <sys/event.h> 48#include <fcntl.h> 49#include <sys/ioctl.h> 50#include <time.h> // platform support for UTC time 51#include <arpa/inet.h> // for inet_aton 52#include <pthread.h> 53#include <netdb.h> // for getaddrinfo 54#include <sys/sockio.h> // for SIOCGIFEFLAGS 55#include <notify.h> 56#include <netinet/in.h> // For IP_RECVTTL 57#ifndef IP_RECVTTL 58#define IP_RECVTTL 24 // bool; receive reception TTL w/dgram 59#endif 60 61#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below 62#include <netinet/ip.h> // For IPTOS_LOWDELAY etc. 63#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc. 64#include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc. 65 66#include <netinet/tcp.h> 67 68#include <DebugServices.h> 69#include "dnsinfo.h" 70 71#include <ifaddrs.h> 72 73#include <IOKit/IOKitLib.h> 74#include <IOKit/IOMessage.h> 75 76#include <IOKit/ps/IOPowerSources.h> 77#include <IOKit/ps/IOPowerSourcesPrivate.h> 78#include <IOKit/ps/IOPSKeys.h> 79 80#include <mach/mach_error.h> 81#include <mach/mach_port.h> 82#include <mach/mach_time.h> 83#include "helper.h" 84#include "P2PPacketFilter.h" 85 86#include <asl.h> 87#include <SystemConfiguration/SCPrivate.h> 88 89// Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic. 90#include <Kernel/IOKit/apple80211/apple80211_var.h> 91 92#if APPLE_OSX_mDNSResponder 93#include <DeviceToDeviceManager/DeviceToDeviceManager.h> 94#include <AWACS.h> 95#if !NO_D2D 96D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import)); 97D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import)); 98D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); 99D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import)); 100D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); 101D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import)); 102D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import)); 103void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); 104void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import)); 105D2DStatus D2DTerminate() __attribute__((weak_import)); 106 107#endif // ! NO_D2D 108 109#else 110#define NO_D2D 1 111#define NO_AWACS 1 112#endif // APPLE_OSX_mDNSResponder 113 114#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 115#include <IOKit/platform/IOPlatformSupportPrivate.h> 116#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 117 118 119#define kInterfaceSpecificOption "interface=" 120 121#define mDNS_IOREG_KEY "mDNS_KEY" 122#define mDNS_IOREG_VALUE "2009-07-30" 123#define mDNS_IOREG_KA_KEY "mDNS_Keepalive" 124#define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS' 125 126// cache the InterfaceID of the AWDL interface 127static mDNSInterfaceID AWDLInterfaceID; 128 129// *************************************************************************** 130// Globals 131 132#if COMPILER_LIKES_PRAGMA_MARK 133#pragma mark - Globals 134#endif 135 136// By default we don't offer sleep proxy service 137// If OfferSleepProxyService is set non-zero (typically via command-line switch), 138// then we'll offer sleep proxy service on desktop Macs that are set to never sleep. 139// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep. 140mDNSexport int OfferSleepProxyService = 0; 141mDNSexport int DisableSleepProxyClient = 0; 142mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy 143 144mDNSexport int OSXVers, iOSVers; 145mDNSexport int KQueueFD; 146 147#ifndef NO_SECURITYFRAMEWORK 148static CFArrayRef ServerCerts; 149OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable); 150#endif /* NO_SECURITYFRAMEWORK */ 151 152static CFStringRef NetworkChangedKey_IPv4; 153static CFStringRef NetworkChangedKey_IPv6; 154static CFStringRef NetworkChangedKey_Hostnames; 155static CFStringRef NetworkChangedKey_Computername; 156static CFStringRef NetworkChangedKey_DNS; 157static CFStringRef NetworkChangedKey_StateInterfacePrefix; 158static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS"); 159static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac"); 160static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity"); 161static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings"); 162 163static char HINFO_HWstring_buffer[32]; 164static char *HINFO_HWstring = "Device"; 165static int HINFO_HWstring_prefixlen = 6; 166 167mDNSexport int WatchDogReportingThreshold = 250; 168 169dispatch_queue_t SSLqueue; 170 171//To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue 172static dispatch_queue_t DynamicStoreQueue; 173 174#if TARGET_OS_EMBEDDED 175#define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist") 176#endif 177 178#if APPLE_OSX_mDNSResponder 179static mDNSu8 SPMetricPortability = 99; 180static mDNSu8 SPMetricMarginalPower = 99; 181static mDNSu8 SPMetricTotalPower = 99; 182static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */ 183mDNSexport domainname ActiveDirectoryPrimaryDomain; 184mDNSexport int ActiveDirectoryPrimaryDomainLabelCount; 185mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer; 186#endif // APPLE_OSX_mDNSResponder 187 188// Don't send triggers too often. We arbitrarily limit it to three minutes. 189#define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond) 190 191// Used by AutoTunnel 192const char btmmprefix[] = "btmmdns:"; 193const char dnsprefix[] = "dns:"; 194 195// String Array used to write list of private domains to Dynamic Store 196static CFArrayRef privateDnsArray = NULL; 197 198// *************************************************************************** 199#if COMPILER_LIKES_PRAGMA_MARK 200#pragma mark - 201#pragma mark - D2D Support 202#endif 203 204#if !NO_D2D 205 206mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface) 207{ 208 // AWDL wants the address and reverse address PTR record communicated 209 // via the D2D interface layer. 210 if (interface->InterfaceID == AWDLInterfaceID) 211 { 212 // only log if we have a valid record to start advertising 213 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType) 214 LogInfo("D2D_start_advertising_interface: %s", interface->ifname); 215 216 if (interface->RR_A.resrec.RecordType) 217 external_start_advertising_service(&interface->RR_A.resrec, NULL); 218 if (interface->RR_PTR.resrec.RecordType) 219 external_start_advertising_service(&interface->RR_PTR.resrec, NULL); 220 } 221} 222 223mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface) 224{ 225 if (interface->InterfaceID == AWDLInterfaceID) 226 { 227 // only log if we have a valid record to stop advertising 228 if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType) 229 LogInfo("D2D_stop_advertising_interface: %s", interface->ifname); 230 231 if (interface->RR_A.resrec.RecordType) 232 external_stop_advertising_service(&interface->RR_A.resrec, NULL); 233 if (interface->RR_PTR.resrec.RecordType) 234 external_stop_advertising_service(&interface->RR_PTR.resrec, NULL); 235 } 236} 237 238// Name compression items for fake packet version number 1 239static const mDNSu8 compression_packet_v1 = 0x01; 240 241static 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" }; 242static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage); 243static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27; 244 245mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result); 246mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len); 247 248typedef struct D2DRecordListElem 249{ 250 struct D2DRecordListElem *next; 251 D2DServiceInstance instanceHandle; 252 D2DTransportType transportType; 253 AuthRecord ar; // must be last in the structure to accomodate extra space 254 // allocated for large records. 255} D2DRecordListElem; 256 257static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events 258 259typedef struct D2DBrowseListElem 260{ 261 struct D2DBrowseListElem *next; 262 domainname name; 263 mDNSu16 type; 264 unsigned int refCount; 265} D2DBrowseListElem; 266 267D2DBrowseListElem* D2DBrowseList = NULL; 268 269mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val) 270{ 271 ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF); 272 ptr[1] = (mDNSu8)((val ) & 0xFF); 273 return ptr + sizeof(mDNSu16); 274} 275 276mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val) 277{ 278 ptr[0] = (mDNSu8)((val >> 24) & 0xFF); 279 ptr[1] = (mDNSu8)((val >> 16) & 0xFF); 280 ptr[2] = (mDNSu8)((val >> 8) & 0xFF); 281 ptr[3] = (mDNSu8)((val ) & 0xFF); 282 return ptr + sizeof(mDNSu32); 283} 284 285mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out) 286{ 287 const mDNSu8 * const start = (const mDNSu8 * const)in; 288 mDNSu8 *ptr = (mDNSu8*)start; 289 while(*ptr) 290 { 291 mDNSu8 c = *ptr; 292 out->c[ptr-start] = *ptr; 293 ptr++; 294 for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr; 295 } 296 out->c[ptr-start] = *ptr; 297} 298 299mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr) 300{ 301 if (mDNS_LoggingEnabled) 302 { 303 LogInfo("%s", __func__); 304 LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg); 305 PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg); 306 } 307 308 mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet 309 310 // Check to make sure we're not going to go past the end of the DNSMessage data 311 // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH 312 if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr; 313 314 // Copy the LHS onto our fake wire packet 315 mDNSPlatformMemCopy(ptr, lhs, lhs_len); 316 ptr += lhs_len - 1; 317 318 // Check the 'fake packet' version number, to ensure that we know how to decompress this data 319 if (*ptr != compression_packet_v1) return mStatus_Incompatible; 320 321 // two bytes of CLASS 322 ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet); 323 324 // four bytes of TTL 325 ptr = putVal32(ptr, 120); 326 327 // Copy the RHS length into the RDLENGTH of our fake wire packet 328 ptr = putVal16(ptr, rhs_len); 329 330 // Copy the RHS onto our fake wire packet 331 mDNSPlatformMemCopy(ptr, rhs, rhs_len); 332 ptr += rhs_len; 333 334 if (mDNS_LoggingEnabled) 335 { 336 LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs); 337 PrintHex(compression_lhs, ptr - compression_lhs); 338 } 339 340 ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec); 341 if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) 342 { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; } 343 else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r)); 344 345 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL); 346 AssignDomainName(&rr->namestorage, &m->rec.namestorage); 347 rr->resrec.rdlength = m->rec.r.resrec.rdlength; 348 rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; 349 mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength); 350 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 351 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us 352 353 m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use 354 355 return mStatus_NoError; 356} 357 358mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype) 359{ 360 mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain); 361 if (!ptr) return ptr; 362 *ptr = (qtype >> 8) & 0xff; 363 ptr += 1; 364 *ptr = qtype & 0xff; 365 ptr += 1; 366 *ptr = compression_packet_v1; 367 return ptr + 1; 368} 369 370mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord) 371{ 372 return putRData(&compression_base_msg, start, compression_limit, resourceRecord); 373} 374 375#define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging 376 377mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len) 378{ 379 mDNSu8 *end; 380 char buffer[49] = {0}; 381 char *bufend = buffer + sizeof(buffer); 382 383 if (len > PRINT_DEBUG_BYTES_LIMIT) 384 { 385 LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT); 386 len = PRINT_DEBUG_BYTES_LIMIT; 387 } 388 end = data + len; 389 390 while(data < end) 391 { 392 char *ptr = buffer; 393 for(; data < end && ptr < bufend-1; ptr+=3,data++) 394 mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data); 395 LogInfo(" %s", buffer); 396 } 397} 398 399mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len) 400{ 401 if (!mDNS_LoggingEnabled) return; 402 403 LogInfo("%s:", tag); 404 LogInfo(" LHS: (%d bytes)", lhs_len); 405 PrintHex(lhs, lhs_len); 406 407 if (!rhs) return; 408 409 LogInfo(" RHS: (%d bytes)", rhs_len); 410 PrintHex(rhs, rhs_len); 411} 412 413mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 414{ 415 (void)m; // unused 416 if (result == mStatus_MemFree) 417 { 418 D2DRecordListElem **ptr = &D2DRecords; 419 D2DRecordListElem *tmp; 420 while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next; 421 if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; } 422 LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr)); 423 tmp = *ptr; 424 *ptr = (*ptr)->next; 425 // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection. 426 mDNSPlatformMemFree(tmp); 427 } 428} 429 430mDNSexport void external_connection_release(const domainname *instance) 431{ 432 (void) instance; 433 D2DRecordListElem *ptr = D2DRecords; 434 435 for ( ; ptr ; ptr = ptr->next) 436 { 437 if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) && 438 SameDomainName(&ptr->ar.rdatastorage.u.name, instance)) 439 { 440 LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d", 441 ptr->instanceHandle, ptr->transportType); 442 if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType); 443 } 444 } 445} 446 447mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype) 448{ 449 D2DRecordListElem *ptr = D2DRecords; 450 for ( ; ptr ; ptr = ptr->next) 451 { 452 if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType)) 453 { 454 mDNS_Deregister(&mDNSStorage, &ptr->ar); 455 LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar)); 456 } 457 } 458} 459 460mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type) 461{ 462 D2DBrowseListElem **ptr = &D2DBrowseList; 463 464 for ( ; *ptr; ptr = &(*ptr)->next) 465 if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name)) 466 break; 467 468 return ptr; 469} 470 471mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type) 472{ 473 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type); 474 return *ptr ? (*ptr)->refCount : 0; 475} 476 477mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type) 478{ 479 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type); 480 481 if (!*ptr) 482 { 483 *ptr = mDNSPlatformMemAllocate(sizeof(**ptr)); 484 mDNSPlatformMemZero(*ptr, sizeof(**ptr)); 485 (*ptr)->type = type; 486 AssignDomainName(&(*ptr)->name, name); 487 } 488 (*ptr)->refCount += 1; 489 490 LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); 491} 492 493mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type) 494{ 495 D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type); 496 497 if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; } 498 499 (*ptr)->refCount -= 1; 500 501 LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount); 502 503 if (!(*ptr)->refCount) 504 { 505 D2DBrowseListElem *tmp = *ptr; 506 *ptr = (*ptr)->next; 507 mDNSPlatformMemFree(tmp); 508 } 509} 510 511mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr) 512{ 513 if (*(lhs + (lhs_len - 1)) == compression_packet_v1) 514 return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr); 515 else 516 return mStatus_Incompatible; 517} 518 519mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) 520{ 521 if (result == kD2DSuccess) 522 { 523 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; } 524 525 mStatus err; 526 D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); 527 528 if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; } 529 530 err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar); 531 if (err) 532 { 533 LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err); 534 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); 535 mDNSPlatformMemFree(ptr); 536 return; 537 } 538 err = mDNS_Register(m, &ptr->ar); 539 if (err) 540 { 541 LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar)); 542 mDNSPlatformMemFree(ptr); 543 return; 544 } 545 546 LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar)); 547 ptr->instanceHandle = instanceHandle; 548 ptr->transportType = transportType; 549 ptr->next = D2DRecords; 550 D2DRecords = ptr; 551 } 552 else 553 LogMsg("xD2DAddToCache: Unexpected result %d", result); 554} 555 556mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize) 557{ 558 D2DRecordListElem *ptr = D2DRecords; 559 D2DRecordListElem *arptr; 560 561 if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; } 562 563 arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData))); 564 if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; } 565 566 if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError) 567 { 568 LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize); 569 mDNSPlatformMemFree(arptr); 570 return NULL; 571 } 572 573 while (ptr) 574 { 575 if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break; 576 ptr = ptr->next; 577 } 578 579 if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar)); 580 mDNSPlatformMemFree(arptr); 581 return ptr; 582} 583 584mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) 585{ 586 (void)transportType; // We don't care about this, yet. 587 (void)instanceHandle; // We don't care about this, yet. 588 589 if (result == kD2DSuccess) 590 { 591 D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize); 592 if (ptr) 593 { 594 LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar)); 595 mDNS_Deregister(m, &ptr->ar); 596 } 597 } 598 else 599 LogMsg("xD2DRemoveFromCache: Unexpected result %d", result); 600} 601 602mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) 603{ 604 (void)m; 605 (void)key; 606 (void)keySize; 607 (void)value; 608 (void)valueSize; 609 610 if (result == kD2DSuccess) 611 { 612 LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle); 613 if (D2DRetain) D2DRetain(instanceHandle, transportType); 614 } 615 else LogMsg("xD2DServiceResolved: Unexpected result %d", result); 616} 617 618mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) 619{ 620 (void)m; 621 (void)instanceHandle; 622 (void)transportType; 623 (void)key; 624 (void)keySize; 625 (void)value; 626 (void)valueSize; 627 628 if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle); 629 else LogMsg("xD2DRetainHappened: Unexpected result %d", result); 630} 631 632mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize) 633{ 634 (void)m; 635 (void)instanceHandle; 636 (void)transportType; 637 (void)key; 638 (void)keySize; 639 (void)value; 640 (void)valueSize; 641 642 if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle); 643 else LogMsg("xD2DReleaseHappened: Unexpected result %d", result); 644} 645 646mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData) 647{ 648 mDNS *m = (mDNS *) userData; 649 const char *eventString = "unknown"; 650 651 KQueueLock(m); 652 653 if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize); 654 if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize); 655 656 switch (event) 657 { 658 case D2DServiceFound: 659 eventString = "D2DServiceFound"; 660 break; 661 case D2DServiceLost: 662 eventString = "D2DServiceLost"; 663 break; 664 case D2DServiceResolved: 665 eventString = "D2DServiceResolved"; 666 break; 667 case D2DServiceRetained: 668 eventString = "D2DServiceRetained"; 669 break; 670 case D2DServiceReleased: 671 eventString = "D2DServiceReleased"; 672 break; 673 default: 674 break; 675 } 676 677 LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData); 678 PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize); 679 680 switch (event) 681 { 682 case D2DServiceFound: 683 xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize); 684 break; 685 case D2DServiceLost: 686 xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize); 687 break; 688 case D2DServiceResolved: 689 xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize); 690 break; 691 case D2DServiceRetained: 692 xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize); 693 break; 694 case D2DServiceReleased: 695 xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize); 696 break; 697 default: 698 break; 699 } 700 701 // Need to tickle the main kqueue loop to potentially handle records we removed or added. 702 KQueueUnlock(m, "xD2DServiceCallback"); 703} 704 705// Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins 706// should be called. 707// When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType 708// will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax. 709// If the return value is not D2DTransportMax, excludedTransportType is undefined. 710 711mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType) 712{ 713 NetworkInterfaceInfoOSX *info; 714 715 // Default exludes the D2DAWDLTransport when D2DTransportMax is returned. 716 *excludedTransportType = D2DAWDLTransport; 717 718 // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set. 719 if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL)) 720 { 721 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set"); 722 *excludedTransportType = D2DTransportMax; 723 return D2DTransportMax; 724 } 725 // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set. 726 else if (flags & kDNSServiceFlagsIncludeP2P) 727 { 728 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set"); 729 return D2DTransportMax; 730 } 731 // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set. 732 else if (flags & kDNSServiceFlagsIncludeAWDL) 733 { 734 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set"); 735 return D2DAWDLTransport; 736 } 737 738 if (InterfaceID == mDNSInterface_P2P) 739 { 740 LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P"); 741 return D2DTransportMax; 742 } 743 744 // Compare to cached AWDL interface ID. 745 if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID)) 746 { 747 LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID); 748 return D2DAWDLTransport; 749 } 750 751 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID); 752 if (info == NULL) 753 { 754 LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID); 755 return D2DTransportMax; 756 } 757 758 // Recognize AirDrop specific p2p* interface based on interface name. 759 if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0) 760 { 761 LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID); 762 return D2DWifiPeerToPeerTransport; 763 } 764 765 // Currently there is no way to identify Bluetooth interface by name, 766 // since they use "en*" based name strings. 767 768 LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID); 769 return D2DTransportMax; 770} 771 772mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) 773{ 774 domainname lower; 775 776 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) 777 { 778 LogInfo("external_start_browsing_for_service: ignoring address record"); 779 return; 780 } 781 782 DomainnameToLower(typeDomain, &lower); 783 784 if (!D2DBrowseListRefCount(&lower, qtype)) 785 { 786 D2DTransportType transportType, excludedTransport; 787 788 LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype)); 789 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); 790 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); 791 792 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport); 793 if (transportType == D2DTransportMax) 794 { 795 D2DTransportType i; 796 for (i = 0; i < D2DTransportMax; i++) 797 { 798 if (i == excludedTransport) continue; 799 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i); 800 } 801 } 802 else 803 { 804 if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType); 805 } 806 } 807 D2DBrowseListRetain(&lower, qtype); 808} 809 810mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags) 811{ 812 domainname lower; 813 814 if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA) 815 { 816 LogInfo("external_stop_browsing_for_service: ignoring address record"); 817 return; 818 } 819 820 DomainnameToLower(typeDomain, &lower); 821 822 D2DBrowseListRelease(&lower, qtype); 823 if (!D2DBrowseListRefCount(&lower, qtype)) 824 { 825 D2DTransportType transportType, excludedTransport; 826 827 LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype)); 828 mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype); 829 PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0); 830 831 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport); 832 if (transportType == D2DTransportMax) 833 { 834 D2DTransportType i; 835 for (i = 0; i < D2DTransportMax; i++) 836 { 837 if (i == excludedTransport) continue; 838 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i); 839 } 840 } 841 else 842 { 843 if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType); 844 } 845 846 // The D2D driver may not generate the D2DServiceLost event for this key after 847 // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D 848 // record cache now. 849 xD2DClearCache(&lower, qtype); 850 } 851} 852 853mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) 854{ 855 domainname lower; 856 mDNSu8 *rhs = NULL; 857 mDNSu8 *end = NULL; 858 D2DTransportType transportType, excludedTransport; 859 DomainnameToLower(resourceRecord->name, &lower); 860 861 LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); 862 // For SRV records, update packet filter if p2p interface already exists, otherwise, 863 // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface. 864 if (resourceRecord->rrtype == kDNSType_SRV) 865 mDNSUpdatePacketFilter(NULL); 866 867 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype); 868 end = DNSNameCompressionBuildRHS(rhs, resourceRecord); 869 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs); 870 871 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport); 872 if (transportType == D2DTransportMax) 873 { 874 D2DTransportType i; 875 for (i = 0; i < D2DTransportMax; i++) 876 { 877 if (i == excludedTransport) continue; 878 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i); 879 } 880 } 881 else 882 { 883 if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType); 884 } 885} 886 887mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) 888{ 889 domainname lower; 890 mDNSu8 *rhs = NULL; 891 mDNSu8 *end = NULL; 892 D2DTransportType transportType, excludedTransport; 893 DomainnameToLower(resourceRecord->name, &lower); 894 895 LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord)); 896 897 // For SRV records, update packet filter to to remove this port from list 898 if (resourceRecord->rrtype == kDNSType_SRV) 899 mDNSUpdatePacketFilter(resourceRecord); 900 901 rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype); 902 end = DNSNameCompressionBuildRHS(rhs, resourceRecord); 903 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs); 904 905 transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport); 906 if (transportType == D2DTransportMax) 907 { 908 D2DTransportType i; 909 for (i = 0; i < D2DTransportMax; i++) 910 { 911 if (i == excludedTransport) continue; 912 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i); 913 } 914 } 915 else 916 { 917 if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType); 918 } 919} 920 921mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags) 922{ 923 domainname lower; 924 mDNSu8 *rhs = NULL; 925 mDNSu8 *end = NULL; 926 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve 927 D2DTransportType transportType, excludedTransport; 928 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower); 929 930 LogInfo("external_start_resolving_service: %##s", fqdn->c); 931 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR); 932 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn); 933 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs); 934 935 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport); 936 if (transportType == D2DTransportMax) 937 { 938 // Resolving over all the transports, except for excludedTransport if set. 939 D2DTransportType i; 940 for (i = 0; i < D2DTransportMax; i++) 941 { 942 if (i == excludedTransport) continue; 943 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i); 944 945 if (i == D2DAWDLTransport) 946 AWDL_used = true; 947 } 948 } 949 else 950 { 951 // Resolving over one specific transport. 952 if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType); 953 954 if (transportType == D2DAWDLTransport) 955 AWDL_used = true; 956 } 957 958 // AWDL wants the SRV and TXT record queries communicated over the D2D interface. 959 // We only want these records going to AWDL, so use AWDLInterfaceID as the 960 // interface and don't set any other flags. 961 if (AWDL_used && AWDLInterfaceID) 962 { 963 LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL"); 964 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL); 965 external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL); 966 } 967} 968 969mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags) 970{ 971 domainname lower; 972 mDNSu8 *rhs = NULL; 973 mDNSu8 *end = NULL; 974 mDNSBool AWDL_used = false; // whether AWDL was used for this resolve 975 D2DTransportType transportType, excludedTransport; 976 DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower); 977 978 LogInfo("external_stop_resolving_service: %##s", fqdn->c); 979 rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR); 980 end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn); 981 PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs); 982 983 transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport); 984 if (transportType == D2DTransportMax) 985 { 986 D2DTransportType i; 987 for (i = 0; i < D2DTransportMax; i++) 988 { 989 if (i == excludedTransport) continue; 990 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i); 991 992 if (i == D2DAWDLTransport) 993 AWDL_used = true; 994 } 995 } 996 else 997 { 998 if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType); 999 1000 if (transportType == D2DAWDLTransport) 1001 AWDL_used = true; 1002 } 1003 1004 // AWDL wants the SRV and TXT record queries communicated over the D2D interface. 1005 // We only want these records going to AWDL, so use AWDLInterfaceID as the 1006 // interface and don't set any other flags. 1007 if (AWDL_used && AWDLInterfaceID) 1008 { 1009 LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL"); 1010 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL); 1011 external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL); 1012 } 1013} 1014 1015#elif APPLE_OSX_mDNSResponder 1016 1017mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} 1018mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;} 1019mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} 1020mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;} 1021mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;} 1022mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;} 1023 1024#endif // ! NO_D2D 1025 1026// *************************************************************************** 1027// Functions 1028 1029#if COMPILER_LIKES_PRAGMA_MARK 1030#pragma mark - 1031#pragma mark - Utility Functions 1032#endif 1033 1034// We only attempt to send and receive multicast packets on interfaces that are 1035// (a) flagged as multicast-capable 1036// (b) *not* flagged as point-to-point (e.g. modem) 1037// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want 1038// to run up the user's bill sending multicast traffic over a link where there's only a single device at the 1039// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway. 1040#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) 1041 1042mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text 1043{ 1044 static int notifyCount = 0; 1045 if (notifyCount) return; 1046 1047 // If we display our alert early in the boot process, then it vanishes once the desktop appears. 1048 // To avoid this, we don't try to display alerts in the first three minutes after boot. 1049 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return; 1050 1051 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address 1052 #if !ForceAlerts 1053 { 1054 // Determine if we're at Apple (17.*.*.*) 1055 NetworkInterfaceInfoOSX *i; 1056 for (i = mDNSStorage.p->InterfaceList; i; i = i->next) 1057 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17) 1058 break; 1059 if (!i) return; // If not at Apple, don't show the alert 1060 } 1061 #endif 1062 1063 LogMsg("%s", title); 1064 LogMsg("%s", msg); 1065 // Display a notification to the user 1066 notifyCount++; 1067 1068#ifndef NO_CFUSERNOTIFICATION 1069 mDNSNotify(title, msg); 1070#endif /* NO_CFUSERNOTIFICATION */ 1071} 1072 1073// Returns true if it is an AppleTV based hardware running iOS, false otherwise 1074mDNSlocal mDNSBool IsAppleTV(void) 1075{ 1076#if TARGET_OS_EMBEDDED 1077 static mDNSBool sInitialized = mDNSfalse; 1078 static mDNSBool sIsAppleTV = mDNSfalse; 1079 CFStringRef deviceClass = NULL; 1080 1081 if(!sInitialized) 1082 { 1083 deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL); 1084 if(deviceClass) 1085 { 1086 if(CFEqual(deviceClass, kMGDeviceClassAppleTV)) 1087 sIsAppleTV = mDNStrue; 1088 CFRelease(deviceClass); 1089 } 1090 sInitialized = mDNStrue; 1091 } 1092 return(sIsAppleTV); 1093#else 1094 return mDNSfalse; 1095#endif // TARGET_OS_EMBEDDED 1096} 1097 1098mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh) 1099{ 1100 static struct ifaddrs *ifa = NULL; 1101 1102 if (refresh && ifa) 1103 { 1104 freeifaddrs(ifa); 1105 ifa = NULL; 1106 } 1107 1108 if (ifa == NULL) 1109 getifaddrs(&ifa); 1110 return ifa; 1111} 1112 1113mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt) 1114{ 1115 CFStringRef sckey = NULL; 1116 Boolean release_sckey = FALSE; 1117 CFDataRef bytes = NULL; 1118 CFPropertyListRef plist = NULL; 1119 SCDynamicStoreRef store = NULL; 1120 1121 switch ((enum mDNSDynamicStoreSetConfigKey)key) 1122 { 1123 case kmDNSMulticastConfig: 1124 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS); 1125 break; 1126 case kmDNSDynamicConfig: 1127 sckey = CFSTR("State:/Network/DynamicDNS"); 1128 break; 1129 case kmDNSPrivateConfig: 1130 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS); 1131 break; 1132 case kmDNSBackToMyMacConfig: 1133 sckey = CFSTR("State:/Network/BackToMyMac"); 1134 break; 1135 case kmDNSSleepProxyServersState: 1136 { 1137 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0); 1138 CFStringAppend(tmp, CFSTR("State:/Network/Interface/")); 1139 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8); 1140 CFStringAppend(tmp, CFSTR("/SleepProxyServers")); 1141 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp); 1142 release_sckey = TRUE; 1143 CFRelease(tmp); 1144 break; 1145 } 1146 case kmDNSDebugState: 1147 sckey = CFSTR("State:/Network/mDNSResponder/DebugState"); 1148 break; 1149 default: 1150 LogMsg("unrecognized key %d", key); 1151 goto fin; 1152 } 1153 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value, 1154 valueCnt, kCFAllocatorNull))) 1155 { 1156 LogMsg("CFDataCreateWithBytesNoCopy of value failed"); 1157 goto fin; 1158 } 1159 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes, 1160 kCFPropertyListImmutable, NULL))) 1161 { 1162 LogMsg("CFPropertyListCreateFromXMLData of bytes failed"); 1163 goto fin; 1164 } 1165 CFRelease(bytes); 1166 bytes = NULL; 1167 if (NULL == (store = SCDynamicStoreCreate(NULL, 1168 CFSTR(kmDNSResponderServName), NULL, NULL))) 1169 { 1170 LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 1171 goto fin; 1172 } 1173 SCDynamicStoreSetValue(store, sckey, plist); 1174 1175fin: 1176 if (NULL != bytes) 1177 CFRelease(bytes); 1178 if (NULL != plist) 1179 CFRelease(plist); 1180 if (NULL != store) 1181 CFRelease(store); 1182 if (release_sckey && sckey) 1183 CFRelease(sckey); 1184} 1185 1186mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value) 1187{ 1188 CFPropertyListRef valueCopy; 1189 char *subkeyCopy = NULL; 1190 if (!value) 1191 return; 1192 1193 // We need to copy the key and value before we dispatch off the block below as the 1194 // caller will free the memory once we return from this function. 1195 valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable); 1196 if (!valueCopy) 1197 { 1198 LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL"); 1199 return; 1200 } 1201 if (subkey) 1202 { 1203 int len = strlen(subkey); 1204 subkeyCopy = mDNSPlatformMemAllocate(len + 1); 1205 if (!subkeyCopy) 1206 { 1207 LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL"); 1208 return; 1209 } 1210 mDNSPlatformMemCopy(subkeyCopy, subkey, len); 1211 subkeyCopy[len] = 0; 1212 } 1213 1214 dispatch_async(DynamicStoreQueue, ^{ 1215 CFWriteStreamRef stream = NULL; 1216 CFDataRef bytes = NULL; 1217 CFStringRef error; 1218 CFIndex ret; 1219 1220 if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL))) 1221 { 1222 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)"); 1223 goto END; 1224 } 1225 CFWriteStreamOpen(stream); 1226 ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error); 1227 if (ret == 0) 1228 { 1229 LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)"); 1230 goto END; 1231 } 1232 if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten))) 1233 { 1234 LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) "); 1235 goto END; 1236 } 1237 CFWriteStreamClose(stream); 1238 CFRelease(stream); 1239 stream = NULL; 1240 LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy); 1241 DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes)); 1242 1243 END: 1244 CFRelease(valueCopy); 1245 if (NULL != stream) 1246 { 1247 CFWriteStreamClose(stream); 1248 CFRelease(stream); 1249 } 1250 if (NULL != bytes) 1251 CFRelease(bytes); 1252 if (subkeyCopy) 1253 mDNSPlatformMemFree(subkeyCopy); 1254 }); 1255} 1256 1257// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type 1258mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type) 1259{ 1260 NetworkInterfaceInfoOSX *i; 1261 for (i = m->p->InterfaceList; i; i = i->next) 1262 if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) && 1263 ((type == AF_UNSPEC ) || 1264 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) || 1265 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i); 1266 return(NULL); 1267} 1268 1269#if TARGET_OS_EMBEDDED 1270mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void) 1271{ 1272 SCPreferencesRef smDNSManagedPrefs = NULL; 1273 smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID); 1274 1275 return (smDNSManagedPrefs); 1276} 1277 1278mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key) 1279{ 1280 mDNSBool val = mDNSfalse; 1281 CFBooleanRef val_cf = NULL; 1282 1283 if (prefs != NULL) 1284 { 1285 val_cf = SCPreferencesGetValue(prefs, key); 1286 if (isA_CFBoolean(val_cf) != NULL) 1287 val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed 1288 else 1289 val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled 1290 } 1291 else 1292 { 1293 LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!"); 1294 val = mDNSfalse; 1295 } 1296 if (val_cf) 1297 CFRelease(val_cf); 1298 return (val); 1299} 1300 1301mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key) 1302{ 1303 SCPreferencesRef managed = NULL; 1304 mDNSBool ret_value; 1305 1306 managed = mDNSManagedPrefsGet(); 1307 ret_value = GetmDNSManagedPrefKeyVal(managed, key); 1308 1309 if (managed) 1310 CFRelease(managed); 1311 return (ret_value); 1312} 1313#endif //TARGET_OS_EMBEDDED 1314 1315mDNSlocal int myIfIndexToName(u_short ifindex, char *name) 1316{ 1317 struct ifaddrs *ifa; 1318 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next) 1319 if (ifa->ifa_addr->sa_family == AF_LINK) 1320 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex) 1321 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; } 1322 return -1; 1323} 1324 1325mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex) 1326{ 1327 mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex; 1328 NetworkInterfaceInfoOSX *i; 1329 1330 // Don't get tricked by inactive interfaces 1331 for (i = m->p->InterfaceList; i; i = i->next) 1332 if (i->Registered && i->scope_id == scope_id) return(i); 1333 1334 return mDNSNULL; 1335} 1336 1337mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex) 1338{ 1339 if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); 1340 if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P); 1341 if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); 1342 1343 NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex); 1344 if (!ifi) 1345 { 1346 // Not found. Make sure our interface list is up to date, then try again. 1347 LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex); 1348 mDNSMacOSXNetworkChanged(m); 1349 ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex); 1350 } 1351 1352 if (!ifi) return(mDNSNULL); 1353 1354 return(ifi->ifinfo.InterfaceID); 1355} 1356 1357 1358mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange) 1359{ 1360 NetworkInterfaceInfoOSX *i; 1361 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); 1362 if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P); 1363 if (id == mDNSInterface_Any ) return(0); 1364 1365 mDNSu32 scope_id = (mDNSu32)(uintptr_t)id; 1366 1367 // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set 1368 for (i = m->p->InterfaceList; i; i = i->next) 1369 if (i->scope_id == scope_id) return(i->scope_id); 1370 1371 // If we are supposed to suppress network change, return "id" back 1372 if (suppressNetworkChange) return scope_id; 1373 1374 // Not found. Make sure our interface list is up to date, then try again. 1375 LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id); 1376 mDNSMacOSXNetworkChanged(m); 1377 for (i = m->p->InterfaceList; i; i = i->next) 1378 if (i->scope_id == scope_id) return(i->scope_id); 1379 1380 return(0); 1381} 1382 1383#if APPLE_OSX_mDNSResponder 1384mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...) 1385{ 1386 if (iOSVers) 1387 return; // No ASL on iOS 1388 1389 static char buffer[512]; 1390 aslmsg asl_msg = asl_new(ASL_TYPE_MSG); 1391 1392 if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; } 1393 if (uuid) 1394 { 1395 char uuidStr[37]; 1396 uuid_unparse(*uuid, uuidStr); 1397 asl_set (asl_msg, "com.apple.message.uuid", uuidStr); 1398 } 1399 1400 static char domainBase[] = "com.apple.mDNSResponder.%s"; 1401 mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain); 1402 asl_set (asl_msg, "com.apple.message.domain", buffer); 1403 1404 if (result) asl_set(asl_msg, "com.apple.message.result", result); 1405 if (signature) asl_set(asl_msg, "com.apple.message.signature", signature); 1406 1407 va_list ptr; 1408 va_start(ptr,fmt); 1409 mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr); 1410 va_end(ptr); 1411 1412 int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); 1413 asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer); 1414 asl_set_filter(NULL, old_filter); 1415 asl_free(asl_msg); 1416} 1417 1418 1419mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m) 1420{ 1421 char buffer[16]; 1422 1423 aslmsg aslmsg = asl_new(ASL_TYPE_MSG); 1424 1425 // If we failed to allocate an aslmsg structure, keep accumulating 1426 // the statistics and try again at the next log interval. 1427 if (!aslmsg) 1428 { 1429 LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!"); 1430 return; 1431 } 1432 1433 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics"); 1434 1435 if (m->rrcache_totalused_unicast) 1436 { 1437 mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast); 1438 } 1439 else 1440 { 1441 LogMsg("mDNSLogDNSSECStatistics: unicast is zero"); 1442 buffer[0] = 0; 1443 } 1444 asl_set(aslmsg,"com.apple.message.MemUsage", buffer); 1445 1446 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0); 1447 asl_set(aslmsg,"com.apple.message.Latency0", buffer); 1448 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10); 1449 asl_set(aslmsg,"com.apple.message.Latency10", buffer); 1450 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20); 1451 asl_set(aslmsg,"com.apple.message.Latency20", buffer); 1452 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50); 1453 asl_set(aslmsg,"com.apple.message.Latency50", buffer); 1454 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100); 1455 asl_set(aslmsg,"com.apple.message.Latency100", buffer); 1456 1457 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0); 1458 asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer); 1459 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3); 1460 asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer); 1461 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7); 1462 asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer); 1463 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10); 1464 asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer); 1465 1466 // Ignore IndeterminateStatus as we don't log them 1467 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus); 1468 asl_set(aslmsg,"com.apple.message.SecureStatus", buffer); 1469 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus); 1470 asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer); 1471 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus); 1472 asl_set(aslmsg,"com.apple.message.BogusStatus", buffer); 1473 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus); 1474 asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer); 1475 1476 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent); 1477 asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer); 1478 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0); 1479 asl_set(aslmsg,"com.apple.message.MsgSize0", buffer); 1480 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1); 1481 asl_set(aslmsg,"com.apple.message.MsgSize1", buffer); 1482 mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2); 1483 asl_set(aslmsg,"com.apple.message.MsgSize2", buffer); 1484 1485 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, ""); 1486 asl_free(aslmsg); 1487} 1488 1489// Calculate packets per hour given total packet count and interval in seconds. 1490// Cast one term of multiplication to (long) to use 64-bit arithmetic 1491// and avoid a potential 32-bit overflow prior to the division. 1492#define ONE_HOUR 3600 1493#define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL)) 1494 1495// Put packet rate data in discrete buckets. 1496mDNSlocal int mDNSBucketData(int inputData, int interval) 1497{ 1498 if (!interval) 1499 { 1500 LogMsg("mDNSBucketData: interval is zero!"); 1501 return 0; 1502 } 1503 1504 int ratePerHour = PACKET_RATE(inputData, interval); 1505 int bucket; 1506 1507 if (ratePerHour == 0) 1508 bucket = 0; 1509 else if (ratePerHour <= 10) 1510 bucket = 10; 1511 else if (ratePerHour <= 100) 1512 bucket = 100; 1513 else if (ratePerHour <= 1000) 1514 bucket = 1000; 1515 else if (ratePerHour <= 5000) 1516 bucket = 5000; 1517 else if (ratePerHour <= 10000) 1518 bucket = 10000; 1519 else if (ratePerHour <= 50000) 1520 bucket = 50000; 1521 else if (ratePerHour <= 100000) 1522 bucket = 100000; 1523 else if (ratePerHour <= 250000) 1524 bucket = 250000; 1525 else if (ratePerHour <= 500000) 1526 bucket = 500000; 1527 else 1528 bucket = 1000000; 1529 1530 return bucket; 1531} 1532 1533mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m) 1534{ 1535 static mDNSs32 last_PktNum, last_MPktNum; 1536 static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent; 1537 static mDNSs32 last_RemoteSubnet; 1538 1539 mDNSs32 interval; 1540 char buffer[16]; 1541 mDNSs32 inMulticast = m->MPktNum - last_MPktNum; 1542 mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast; 1543 mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent; 1544 mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent; 1545 mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet; 1546 1547 1548 // save starting values for new interval 1549 last_PktNum = m->PktNum; 1550 last_MPktNum = m->MPktNum; 1551 last_UnicastPacketsSent = m->UnicastPacketsSent; 1552 last_MulticastPacketsSent = m->MulticastPacketsSent; 1553 last_RemoteSubnet = m->RemoteSubnet; 1554 1555 // Need a non-zero active time interval. 1556 if (!m->ActiveStatTime) 1557 return; 1558 1559 // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero. 1560 interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR; 1561 1562 // Use a minimum of 30 minutes of awake time to calculate average packet rates. 1563 // The rounded awake interval should not be greater than the rounded reporting 1564 // interval. 1565 if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR)) 1566 return; 1567 1568 aslmsg aslmsg = asl_new(ASL_TYPE_MSG); 1569 1570 if (!aslmsg) 1571 { 1572 LogMsg("mDNSLogBonjourStatistics: asl_new() failed!"); 1573 return; 1574 } 1575 // log in MessageTracer format 1576 asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics"); 1577 1578 snprintf(buffer, sizeof(buffer), "%d", interval); 1579 asl_set(aslmsg,"com.apple.message.interval", buffer); 1580 1581 // log the packet rates as packets per hour 1582 snprintf(buffer, sizeof(buffer), "%d", 1583 mDNSBucketData(inUnicast, m->ActiveStatTime)); 1584 asl_set(aslmsg,"com.apple.message.UnicastIn", buffer); 1585 1586 snprintf(buffer, sizeof(buffer), "%d", 1587 mDNSBucketData(inMulticast, m->ActiveStatTime)); 1588 asl_set(aslmsg,"com.apple.message.MulticastIn", buffer); 1589 1590 snprintf(buffer, sizeof(buffer), "%d", 1591 mDNSBucketData(outUnicast, m->ActiveStatTime)); 1592 asl_set(aslmsg,"com.apple.message.UnicastOut", buffer); 1593 1594 snprintf(buffer, sizeof(buffer), "%d", 1595 mDNSBucketData(outMulticast, m->ActiveStatTime)); 1596 asl_set(aslmsg,"com.apple.message.MulticastOut", buffer); 1597 1598 snprintf(buffer, sizeof(buffer), "%d", 1599 mDNSBucketData(remoteSubnet, m->ActiveStatTime)); 1600 asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer); 1601 1602 asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, ""); 1603 1604 asl_free(aslmsg); 1605} 1606 1607// Log multicast and unicast traffic statistics to MessageTracer on OSX 1608mDNSexport void mDNSLogStatistics(mDNS *const m) 1609{ 1610 // MessageTracer only available on OSX 1611 if (iOSVers) 1612 return; 1613 1614 mDNSs32 currentUTC = mDNSPlatformUTC(); 1615 1616 // log runtime statistics 1617 if ((currentUTC - m->NextStatLogTime) >= 0) 1618 { 1619 m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime; 1620 // If StatStartTime is zero, it hasn't been reinitialized yet 1621 // in the wakeup code path. 1622 if (m->StatStartTime) 1623 { 1624 m->ActiveStatTime += currentUTC - m->StatStartTime; 1625 } 1626 1627 // Only log statistics if we have recorded some active time during 1628 // this statistics interval. 1629 if (m->ActiveStatTime) 1630 { 1631 mDNSLogBonjourStatistics(m); 1632 mDNSLogDNSSECStatistics(m); 1633 } 1634 1635 // Start a new statistics gathering interval. 1636 m->StatStartTime = currentUTC; 1637 m->ActiveStatTime = 0; 1638 } 1639} 1640 1641#endif // APPLE_OSX_mDNSResponder 1642 1643#if COMPILER_LIKES_PRAGMA_MARK 1644#pragma mark - 1645#pragma mark - UDP & TCP send & receive 1646#endif 1647 1648mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr) 1649{ 1650 mDNSBool result = mDNSfalse; 1651 SCNetworkConnectionFlags flags; 1652 CFDataRef remote_addr; 1653 CFMutableDictionaryRef options; 1654 SCNetworkReachabilityRef ReachRef = NULL; 1655 1656 options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1657 remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len); 1658 CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr); 1659 CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue); 1660 ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options); 1661 CFRelease(options); 1662 CFRelease(remote_addr); 1663 1664 if (!ReachRef) 1665 { 1666 LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions"); 1667 goto end; 1668 } 1669 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) 1670 { 1671 LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); 1672 goto end; 1673 } 1674 result = flags & kSCNetworkFlagsConnectionRequired; 1675 1676end: 1677 if (ReachRef) 1678 CFRelease(ReachRef); 1679 return result; 1680} 1681 1682// Set traffic class for socket 1683mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass) 1684{ 1685 int traffic_class; 1686 1687 if (useBackgroundTrafficClass) 1688 traffic_class = SO_TC_BK_SYS; 1689 else 1690 traffic_class = SO_TC_CTL; 1691 1692 (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class)); 1693} 1694 1695mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q) 1696{ 1697 if (src) 1698 { 1699 int s; 1700 1701 if (dst->type == mDNSAddrType_IPv4) 1702 { 1703 s = src->ss.sktv4; 1704 } 1705 else 1706 { 1707 s = src->ss.sktv6; 1708 } 1709 1710 if (q->pid) 1711 { 1712 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1) 1713 { 1714 LogInfo("mDNSPlatformSetDelegatePID: Delegate PID failed %s for PID %d", strerror(errno), q->pid); 1715 } 1716 } 1717 else 1718 { 1719 if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1) 1720 { 1721 LogInfo("mDNSPlatformSetDelegatePID: Delegate UUID failed %s", strerror(errno)); 1722 } 1723 } 1724 } 1725} 1726 1727// Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket" 1728// Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface" 1729// OR send via our primary v4 unicast socket 1730// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket 1731mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, 1732 mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, 1733 mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass) 1734{ 1735 NetworkInterfaceInfoOSX *info = mDNSNULL; 1736 struct sockaddr_storage to; 1737 int s = -1, err; 1738 mStatus result = mStatus_NoError; 1739 1740 if (InterfaceID) 1741 { 1742 info = IfindexToInterfaceInfoOSX(m, InterfaceID); 1743 if (info == NULL) 1744 { 1745 // We may not have registered interfaces with the "core" as we may not have 1746 // seen any interface notifications yet. This typically happens during wakeup 1747 // where we might try to send DNS requests (non-SuppressUnusable questions internal 1748 // to mDNSResponder) before we receive network notifications. 1749 LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID); 1750 return mStatus_BadParamErr; 1751 } 1752 } 1753 1754 char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast"; 1755 1756 if (dst->type == mDNSAddrType_IPv4) 1757 { 1758 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to; 1759 sin_to->sin_len = sizeof(*sin_to); 1760 sin_to->sin_family = AF_INET; 1761 sin_to->sin_port = dstPort.NotAnInteger; 1762 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger; 1763 s = (src ? src->ss : m->p->permanentsockets).sktv4; 1764 1765 if (info) // Specify outgoing interface 1766 { 1767 if (!mDNSAddrIsDNSMulticast(dst)) 1768 { 1769 #ifdef IP_BOUND_IF 1770 if (info->scope_id == 0) 1771 LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name); 1772 else 1773 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id)); 1774 #else 1775 { 1776 static int displayed = 0; 1777 if (displayed < 1000) 1778 { 1779 displayed++; 1780 LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets"); 1781 } 1782 } 1783 #endif 1784 } 1785 else 1786 #ifdef IP_MULTICAST_IFINDEX 1787 { 1788 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id)); 1789 // We get an error when we compile on a machine that supports this option and run the binary on 1790 // a different machine that does not support it 1791 if (err < 0) 1792 { 1793 if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno); 1794 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr)); 1795 if (err < 0 && !m->p->NetworkChanged) 1796 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno)); 1797 } 1798 } 1799 #else 1800 { 1801 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr)); 1802 if (err < 0 && !m->p->NetworkChanged) 1803 LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno)); 1804 1805 } 1806 #endif 1807 } 1808 } 1809 1810 else if (dst->type == mDNSAddrType_IPv6) 1811 { 1812 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to; 1813 sin6_to->sin6_len = sizeof(*sin6_to); 1814 sin6_to->sin6_family = AF_INET6; 1815 sin6_to->sin6_port = dstPort.NotAnInteger; 1816 sin6_to->sin6_flowinfo = 0; 1817 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6; 1818 sin6_to->sin6_scope_id = info ? info->scope_id : 0; 1819 s = (src ? src->ss : m->p->permanentsockets).sktv6; 1820 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface 1821 { 1822 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id)); 1823 if (err < 0) 1824 { 1825 char name[IFNAMSIZ]; 1826 if (if_indextoname(info->scope_id, name) != NULL) 1827 LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno)); 1828 else 1829 LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id); 1830 } 1831 } 1832 } 1833 1834 else 1835 { 1836 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!"); 1837#if ForceAlerts 1838 *(long*)0 = 0; 1839#endif 1840 return mStatus_BadParamErr; 1841 } 1842 1843 if (s >= 0) 1844 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d", 1845 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s); 1846 else 1847 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)", 1848 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort)); 1849 1850 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet 1851 // If we don't have the corresponding type of socket available, then return mStatus_Invalid 1852 if (s < 0) return(mStatus_Invalid); 1853 1854 // switch to background traffic class for this message if requested 1855 if (useBackgroundTrafficClass) 1856 setTrafficClass(s, useBackgroundTrafficClass); 1857 1858 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len); 1859 1860 // set traffic class back to default value 1861 if (useBackgroundTrafficClass) 1862 setTrafficClass(s, mDNSfalse); 1863 1864 if (err < 0) 1865 { 1866 static int MessageCount = 0; 1867 LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", 1868 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); 1869 if (!mDNSAddressIsAllDNSLinkGroup(dst)) 1870 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr); 1871 // Don't report EHOSTUNREACH in the first three minutes after boot 1872 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>) 1873 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries. 1874 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr); 1875 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change 1876 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr); 1877 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN) 1878 LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", 1879 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); 1880 else 1881 { 1882 MessageCount++; 1883 if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs 1884 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d", 1885 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount); 1886 else // If logging is enabled, remove the cap and log aggressively 1887 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d", 1888 s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount); 1889 } 1890 1891 result = mStatus_UnknownErr; 1892 } 1893 1894#ifdef IP_BOUND_IF 1895 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst)) 1896 { 1897 static const mDNSu32 ifindex = 0; 1898 setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); 1899 } 1900#endif 1901 1902 return(result); 1903} 1904 1905mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, 1906 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl) 1907{ 1908 static unsigned int numLogMessages = 0; 1909 struct iovec databuffers = { (char *)buffer, max }; 1910 struct msghdr msg; 1911 ssize_t n; 1912 struct cmsghdr *cmPtr; 1913 char ancillary[1024]; 1914 1915 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be 1916 1917 // Set up the message 1918 msg.msg_name = (caddr_t)from; 1919 msg.msg_namelen = *fromlen; 1920 msg.msg_iov = &databuffers; 1921 msg.msg_iovlen = 1; 1922 msg.msg_control = (caddr_t)&ancillary; 1923 msg.msg_controllen = sizeof(ancillary); 1924 msg.msg_flags = 0; 1925 1926 // Receive the data 1927 n = recvmsg(s, &msg, 0); 1928 if (n<0) 1929 { 1930 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno); 1931 return(-1); 1932 } 1933 if (msg.msg_controllen < (int)sizeof(struct cmsghdr)) 1934 { 1935 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d", 1936 s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno); 1937 return(-1); 1938 } 1939 if (msg.msg_flags & MSG_CTRUNC) 1940 { 1941 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s); 1942 return(-1); 1943 } 1944 1945 *fromlen = msg.msg_namelen; 1946 1947 // Parse each option out of the ancillary data. 1948 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr)) 1949 { 1950 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type); 1951 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR) 1952 { 1953 dstaddr->type = mDNSAddrType_IPv4; 1954 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr); 1955 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4); 1956 } 1957 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF) 1958 { 1959 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr); 1960 if (sdl->sdl_nlen < IF_NAMESIZE) 1961 { 1962 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen); 1963 ifname[sdl->sdl_nlen] = 0; 1964 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen); 1965 } 1966 } 1967 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL) 1968 *ttl = *(u_char*)CMSG_DATA(cmPtr); 1969 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO) 1970 { 1971 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr); 1972 dstaddr->type = mDNSAddrType_IPv6; 1973 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr; 1974 myIfIndexToName(ip6_info->ipi6_ifindex, ifname); 1975 } 1976 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT) 1977 *ttl = *(int*)CMSG_DATA(cmPtr); 1978 } 1979 1980 return(n); 1981} 1982 1983mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr) 1984{ 1985 NetworkInterfaceInfo *intf; 1986 1987 if (addr->type == mDNSAddrType_IPv4) 1988 { 1989 for (intf = m->HostInterfaces; intf; intf = intf->next) 1990 { 1991 if (intf->ip.type == addr->type && intf->McastTxRx) 1992 { 1993 if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0) 1994 { 1995 return(intf->InterfaceID); 1996 } 1997 } 1998 } 1999 } 2000 2001 if (addr->type == mDNSAddrType_IPv6) 2002 { 2003 for (intf = m->HostInterfaces; intf; intf = intf->next) 2004 { 2005 if (intf->ip.type == addr->type && intf->McastTxRx) 2006 { 2007 if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) && 2008 ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) && 2009 ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) && 2010 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0))) 2011 { 2012 return(intf->InterfaceID); 2013 } 2014 } 2015 } 2016 } 2017 return(mDNSInterface_Any); 2018} 2019 2020mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src) 2021{ 2022 // We should have a DNSMessage header followed by the question and an answer 2023 // which also includes a CNAME (that's when this function is called). To keep it 2024 // simple, we expect at least the size of DNSMessage header(12) and size of "A" 2025 // record (14 bytes). 2026 char buffer[26]; 2027 int ret; 2028 2029 (void) m; 2030 2031 if (!src) 2032 return mDNSfalse; 2033 2034 ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK); 2035 if (ret > 0) 2036 return mDNStrue; 2037 else 2038 return mDNSfalse; 2039} 2040 2041mDNSexport void myKQSocketCallBack(int s1, short filter, void *context) 2042{ 2043 KQSocketSet *const ss = (KQSocketSet *)context; 2044 mDNS *const m = ss->m; 2045 int err = 0, count = 0, closed = 0; 2046 2047 if (filter != EVFILT_READ) 2048 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ); 2049 2050 if (s1 != ss->sktv4 && s1 != ss->sktv6) 2051 { 2052 LogMsg("myKQSocketCallBack: native socket %d", s1); 2053 LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6); 2054 } 2055 2056 while (!closed) 2057 { 2058 mDNSAddr senderAddr, destAddr; 2059 mDNSIPPort senderPort; 2060 struct sockaddr_storage from; 2061 size_t fromlen = sizeof(from); 2062 char packetifname[IF_NAMESIZE] = ""; 2063 mDNSu8 ttl; 2064 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl); 2065 if (err < 0) break; 2066 2067 count++; 2068 if (from.ss_family == AF_INET) 2069 { 2070 struct sockaddr_in *s = (struct sockaddr_in*)&from; 2071 senderAddr.type = mDNSAddrType_IPv4; 2072 senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr; 2073 senderPort.NotAnInteger = s->sin_port; 2074 //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); 2075 } 2076 else if (from.ss_family == AF_INET6) 2077 { 2078 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from; 2079 senderAddr.type = mDNSAddrType_IPv6; 2080 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr; 2081 senderPort.NotAnInteger = sin6->sin6_port; 2082 //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); 2083 } 2084 else 2085 { 2086 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family); 2087 return; 2088 } 2089 2090 // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet 2091 mDNSInterfaceID InterfaceID = mDNSNULL; 2092 NetworkInterfaceInfoOSX *intf = m->p->InterfaceList; 2093 while (intf) 2094 { 2095 if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname)) 2096 break; 2097 intf = intf->next; 2098 } 2099 2100 // When going to sleep we deregister all our interfaces, but if the machine 2101 // takes a few seconds to sleep we may continue to receive multicasts 2102 // during that time, which would confuse mDNSCoreReceive, because as far 2103 // as it's concerned, we should have no active interfaces any more. 2104 // Hence we ignore multicasts for which we can find no matching InterfaceID. 2105 if (intf) 2106 InterfaceID = intf->ifinfo.InterfaceID; 2107 else if (mDNSAddrIsDNSMulticast(&destAddr)) 2108 continue; 2109 2110 if (!InterfaceID) 2111 { 2112 InterfaceID = FindMyInterface(m, &destAddr); 2113 } 2114 2115// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s", 2116// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname); 2117 2118 // mDNSCoreReceive may close the socket we're reading from. We must break out of our 2119 // loop when that happens, or we may try to read from an invalid FD. We do this by 2120 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us 2121 // if it closes the socketset. 2122 ss->closeFlag = &closed; 2123 2124 if (ss->proxy) 2125 { 2126 m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, 2127 senderPort, &destAddr, ss->port, InterfaceID, NULL); 2128 } 2129 else 2130 { 2131 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID); 2132 } 2133 2134 // if we didn't close, we can safely dereference the socketset, and should to 2135 // reset the closeFlag, since it points to something on the stack 2136 if (!closed) ss->closeFlag = mDNSNULL; 2137 } 2138 2139 if (err < 0 && (errno != EWOULDBLOCK || count == 0)) 2140 { 2141 // Something is busted here. 2142 // kqueue says there is a packet, but myrecvfrom says there is not. 2143 // Try calling select() to get another opinion. 2144 // Find out about other socket parameter that can help understand why select() says the socket is ready for read 2145 // All of this is racy, as data may have arrived after the call to select() 2146 static unsigned int numLogMessages = 0; 2147 int save_errno = errno; 2148 int so_error = -1; 2149 int so_nread = -1; 2150 int fionread = -1; 2151 socklen_t solen = sizeof(int); 2152 fd_set readfds; 2153 struct timeval timeout; 2154 int selectresult; 2155 FD_ZERO(&readfds); 2156 FD_SET(s1, &readfds); 2157 timeout.tv_sec = 0; 2158 timeout.tv_usec = 0; 2159 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout); 2160 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1) 2161 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno); 2162 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1) 2163 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno); 2164 if (ioctl(s1, FIONREAD, &fionread) == -1) 2165 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno); 2166 if (numLogMessages++ < 100) 2167 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d", 2168 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count); 2169 if (numLogMessages > 5) 2170 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 2171 "Congratulations, you've reproduced an elusive bug.\r" 2172 "Please contact the current assignee of <rdar://problem/3375328>.\r" 2173 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r" 2174 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem."); 2175 2176 sleep(1); // After logging this error, rate limit so we don't flood syslog 2177 } 2178} 2179 2180mDNSlocal void doTcpSocketCallback(TCPSocket *sock) 2181{ 2182 mDNSBool c = !sock->connected; 2183 sock->connected = mDNStrue; 2184 sock->callback(sock, sock->context, c, sock->err); 2185 // Note: the callback may call CloseConnection here, which frees the context structure! 2186} 2187 2188#ifndef NO_SECURITYFRAMEWORK 2189 2190mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength) 2191{ 2192 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0); 2193 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); } 2194 if (ret >= 0) { *dataLength = ret; return(noErr); } 2195 *dataLength = 0; 2196 if (errno == EAGAIN ) return(errSSLWouldBlock); 2197 if (errno == ENOENT ) return(errSSLClosedGraceful); 2198 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort); 2199 LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno)); 2200 return(errSSLClosedAbort); 2201} 2202 2203mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength) 2204{ 2205 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0); 2206 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); } 2207 if (ret > 0) { *dataLength = ret; return(noErr); } 2208 *dataLength = 0; 2209 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful); 2210 if ( errno == EAGAIN ) return(errSSLWouldBlock); 2211 if ( errno == ECONNRESET) return(errSSLClosedAbort); 2212 LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno)); 2213 return(errSSLClosedAbort); 2214} 2215 2216mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype) 2217{ 2218 char domname_cstr[MAX_ESCAPED_DOMAIN_NAME]; 2219 2220 sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype); 2221 if (!sock->tlsContext) 2222 { 2223 LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed"); 2224 return(mStatus_UnknownErr); 2225 } 2226 2227 mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock); 2228 if (err) 2229 { 2230 LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); 2231 goto fail; 2232 } 2233 2234 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock); 2235 if (err) 2236 { 2237 LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); 2238 goto fail; 2239 } 2240 2241 // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable 2242 // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them. 2243 err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0); 2244 if (err) 2245 { 2246 LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err); 2247 goto fail; 2248 } 2249 2250 // We already checked for NULL in hostname and this should never happen. Hence, returning -1 2251 // (error not in OSStatus space) is okay. 2252 if (!sock->hostname.c[0]) 2253 { 2254 LogMsg("ERROR: tlsSetupSock: hostname NULL"); 2255 err = -1; 2256 goto fail; 2257 } 2258 2259 ConvertDomainNameToCString(&sock->hostname, domname_cstr); 2260 err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr)); 2261 if (err) 2262 { 2263 LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err); 2264 goto fail; 2265 } 2266 2267 return(err); 2268 2269fail: 2270 if (sock->tlsContext) 2271 CFRelease(sock->tlsContext); 2272 return(err); 2273} 2274 2275#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2276mDNSlocal void doSSLHandshake(TCPSocket *sock) 2277{ 2278 mStatus err = SSLHandshake(sock->tlsContext); 2279 2280 //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is 2281 //defined, KQueueLock is a noop. Hence we need to serialize here 2282 // 2283 //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue. 2284 //We need the rest of the logic also. Otherwise, we can enable the READ 2285 //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is 2286 //ConnFailed which means we are going to free the tcpInfo. While it 2287 //is waiting to be dispatched, another read event can come into tcpKQSocketCallback 2288 //and potentially call doTCPCallback with error which can close the fd and free the 2289 //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo 2290 //is already freed. 2291 2292 dispatch_async(dispatch_get_main_queue(), ^{ 2293 2294 LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock 2295 2296 if (sock->handshake == handshake_to_be_closed) 2297 { 2298 LogInfo("SSLHandshake completed after close"); 2299 mDNSPlatformTCPCloseConnection(sock); 2300 } 2301 else 2302 { 2303 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry); 2304 else LogMsg("doSSLHandshake: sock->fd is -1"); 2305 2306 if (err == errSSLWouldBlock) 2307 sock->handshake = handshake_required; 2308 else 2309 { 2310 if (err) 2311 { 2312 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : ""); 2313 CFRelease(sock->tlsContext); 2314 sock->tlsContext = NULL; 2315 } 2316 2317 sock->err = err ? mStatus_ConnFailed : 0; 2318 sock->handshake = handshake_completed; 2319 2320 LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd); 2321 doTcpSocketCallback(sock); 2322 } 2323 } 2324 2325 LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd); 2326 return; 2327 }); 2328} 2329#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2330mDNSlocal void *doSSLHandshake(TCPSocket *sock) 2331{ 2332 // Warning: Touching sock without the kqueue lock! 2333 // We're protected because sock->handshake == handshake_in_progress 2334 mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake 2335 mStatus err = SSLHandshake(sock->tlsContext); 2336 2337 KQueueLock(m); 2338 debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock 2339 2340 if (sock->handshake == handshake_to_be_closed) 2341 { 2342 LogInfo("SSLHandshake completed after close"); 2343 mDNSPlatformTCPCloseConnection(sock); 2344 } 2345 else 2346 { 2347 if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry); 2348 else LogMsg("doSSLHandshake: sock->fd is -1"); 2349 2350 if (err == errSSLWouldBlock) 2351 sock->handshake = handshake_required; 2352 else 2353 { 2354 if (err) 2355 { 2356 LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : ""); 2357 CFRelease(sock->tlsContext); 2358 sock->tlsContext = NULL; 2359 } 2360 2361 sock->err = err ? mStatus_ConnFailed : 0; 2362 sock->handshake = handshake_completed; 2363 2364 debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd); 2365 doTcpSocketCallback(sock); 2366 } 2367 } 2368 2369 debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd); 2370 KQueueUnlock(m, "doSSLHandshake"); 2371 return NULL; 2372} 2373#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2374 2375mDNSlocal void spawnSSLHandshake(TCPSocket* sock) 2376{ 2377 debugf("spawnSSLHandshake %p: entry", sock); 2378 2379 if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake); 2380 sock->handshake = handshake_in_progress; 2381 KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry); 2382 2383 // Dispatch it on a separate queue to help avoid blocking other threads/queues, and 2384 // to limit the number of threads used for SSLHandshake 2385 dispatch_async(SSLqueue, ^{doSSLHandshake(sock);}); 2386 2387 debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd); 2388} 2389 2390#endif /* NO_SECURITYFRAMEWORK */ 2391 2392mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context) 2393{ 2394 TCPSocket *sock = context; 2395 sock->err = mStatus_NoError; 2396 2397 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter); 2398 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter); 2399 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE 2400 if (filter == EVFILT_WRITE) 2401 KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry); 2402 2403 if (sock->flags & kTCPSocketFlags_UseTLS) 2404 { 2405#ifndef NO_SECURITYFRAMEWORK 2406 if (!sock->setup) 2407 { 2408 sock->setup = mDNStrue; 2409 sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType); 2410 if (sock->err) 2411 { 2412 LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err); 2413 return; 2414 } 2415 } 2416 if (sock->handshake == handshake_required) 2417 { 2418 spawnSSLHandshake(sock); 2419 return; 2420 } 2421 else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) 2422 { 2423 return; 2424 } 2425 else if (sock->handshake != handshake_completed) 2426 { 2427 if (!sock->err) 2428 sock->err = mStatus_UnknownErr; 2429 LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake); 2430 } 2431#else /* NO_SECURITYFRAMEWORK */ 2432 sock->err = mStatus_UnsupportedErr; 2433#endif /* NO_SECURITYFRAMEWORK */ 2434 } 2435 2436 doTcpSocketCallback(sock); 2437} 2438 2439#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2440mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef) 2441{ 2442 dispatch_queue_t queue = dispatch_get_main_queue(); 2443 dispatch_source_t source; 2444 if (flags == EV_DELETE) 2445 { 2446 if (filter == EVFILT_READ) 2447 { 2448 dispatch_source_cancel(entryRef->readSource); 2449 dispatch_release(entryRef->readSource); 2450 entryRef->readSource = mDNSNULL; 2451 debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource); 2452 } 2453 else if (filter == EVFILT_WRITE) 2454 { 2455 dispatch_source_cancel(entryRef->writeSource); 2456 dispatch_release(entryRef->writeSource); 2457 entryRef->writeSource = mDNSNULL; 2458 debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource); 2459 } 2460 else 2461 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter); 2462 return 0; 2463 } 2464 if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags); 2465 2466 if (filter == EVFILT_READ) 2467 { 2468 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue); 2469 } 2470 else if (filter == EVFILT_WRITE) 2471 { 2472 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue); 2473 } 2474 else 2475 { 2476 LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter); 2477 return -1; 2478 } 2479 if (!source) return -1; 2480 dispatch_source_set_event_handler(source, ^{ 2481 2482 mDNSs32 stime = mDNSPlatformRawTime(); 2483 entryRef->KQcallback(fd, filter, entryRef->KQcontext); 2484 mDNSs32 etime = mDNSPlatformRawTime(); 2485 if (etime - stime >= WatchDogReportingThreshold) 2486 LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime); 2487 2488 // Trigger the event delivery to the application. Even though we trigger the 2489 // event completion after handling every event source, these all will hopefully 2490 // get merged 2491 TriggerEventCompletion(); 2492 2493 }); 2494 dispatch_source_set_cancel_handler(source, ^{ 2495 if (entryRef->fdClosed) 2496 { 2497 //LogMsg("CancelHandler: closing fd %d", fd); 2498 close(fd); 2499 } 2500 }); 2501 dispatch_resume(source); 2502 if (filter == EVFILT_READ) 2503 entryRef->readSource = source; 2504 else 2505 entryRef->writeSource = source; 2506 2507 return 0; 2508} 2509 2510mDNSexport void KQueueLock(mDNS *const m) 2511{ 2512 (void)m; //unused 2513} 2514mDNSexport void KQueueUnlock(mDNS *const m, const char const *task) 2515{ 2516 (void)m; //unused 2517 (void)task; //unused 2518} 2519#else 2520mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef) 2521{ 2522 struct kevent new_event; 2523 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef); 2524 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0; 2525} 2526 2527mDNSexport void KQueueLock(mDNS *const m) 2528{ 2529 pthread_mutex_lock(&m->p->BigMutex); 2530 m->p->BigMutexStartTime = mDNSPlatformRawTime(); 2531} 2532 2533mDNSexport void KQueueUnlock(mDNS *const m, const char* task) 2534{ 2535 mDNSs32 end = mDNSPlatformRawTime(); 2536 (void)task; 2537 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold) 2538 LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime); 2539 2540 pthread_mutex_unlock(&m->p->BigMutex); 2541 2542 char wake = 1; 2543 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1) 2544 LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno)); 2545} 2546#endif 2547 2548mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd) 2549{ 2550#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2551 (void) fd; //unused 2552 if (kq->readSource) 2553 { 2554 dispatch_source_cancel(kq->readSource); 2555 kq->readSource = mDNSNULL; 2556 } 2557 if (kq->writeSource) 2558 { 2559 dispatch_source_cancel(kq->writeSource); 2560 kq->writeSource = mDNSNULL; 2561 } 2562 // Close happens in the cancellation handler 2563 debugf("mDNSPlatformCloseFD: resetting sources for %d", fd); 2564 kq->fdClosed = mDNStrue; 2565#else 2566 (void)kq; //unused 2567 close(fd); 2568#endif 2569} 2570 2571mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass) 2572{ 2573 KQSocketSet *cp = &sock->ss; 2574 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6; 2575 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6; 2576 const int on = 1; // "on" for setsockopt 2577 mStatus err; 2578 2579 int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP); 2580 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); } 2581 2582 // for TCP sockets, the traffic class is set once and not changed 2583 setTrafficClass(skt, useBackgroundTrafficClass); 2584 2585 if (sa_family == AF_INET) 2586 { 2587 // Bind it 2588 struct sockaddr_in addr; 2589 mDNSPlatformMemZero(&addr, sizeof(addr)); 2590 addr.sin_family = AF_INET; 2591 addr.sin_port = port->NotAnInteger; 2592 err = bind(skt, (struct sockaddr*) &addr, sizeof(addr)); 2593 if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; } 2594 2595 // Receive interface identifiers 2596 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)); 2597 if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; } 2598 2599 mDNSPlatformMemZero(&addr, sizeof(addr)); 2600 socklen_t len = sizeof(addr); 2601 err = getsockname(skt, (struct sockaddr*) &addr, &len); 2602 if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; } 2603 2604 port->NotAnInteger = addr.sin_port; 2605 } 2606 else 2607 { 2608 // Bind it 2609 struct sockaddr_in6 addr6; 2610 mDNSPlatformMemZero(&addr6, sizeof(addr6)); 2611 addr6.sin6_family = AF_INET6; 2612 addr6.sin6_port = port->NotAnInteger; 2613 err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6)); 2614 if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; } 2615 2616 // We want to receive destination addresses and receive interface identifiers 2617 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); 2618 if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; } 2619 2620 mDNSPlatformMemZero(&addr6, sizeof(addr6)); 2621 socklen_t len = sizeof(addr6); 2622 err = getsockname(skt, (struct sockaddr *) &addr6, &len); 2623 if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; } 2624 2625 port->NotAnInteger = addr6.sin6_port; 2626 2627 } 2628 *s = skt; 2629 k->KQcallback = tcpKQSocketCallback; 2630 k->KQcontext = sock; 2631 k->KQtask = "mDNSPlatformTCPSocket"; 2632#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 2633 k->readSource = mDNSNULL; 2634 k->writeSource = mDNSNULL; 2635 k->fdClosed = mDNSfalse; 2636#endif 2637 return mStatus_NoError; 2638} 2639 2640mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass) 2641{ 2642 mStatus err; 2643 (void) m; 2644 2645 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket)); 2646 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); } 2647 2648 mDNSPlatformMemZero(sock, sizeof(TCPSocket)); 2649 2650 sock->ss.m = m; 2651 sock->ss.sktv4 = -1; 2652 sock->ss.sktv6 = -1; 2653 err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass); 2654 2655 if (!err) 2656 { 2657 err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass); 2658 if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; } 2659 } 2660 if (err) 2661 { 2662 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno)); 2663 freeL("TCPSocket/mDNSPlatformTCPSocket", sock); 2664 return(mDNSNULL); 2665 } 2666 // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect 2667 sock->fd = sock->ss.sktv4; 2668 sock->callback = mDNSNULL; 2669 sock->flags = flags; 2670 sock->context = mDNSNULL; 2671 sock->setup = mDNSfalse; 2672 sock->connected = mDNSfalse; 2673 sock->handshake = handshake_required; 2674 sock->m = m; 2675 sock->err = mStatus_NoError; 2676 2677 return sock; 2678} 2679 2680mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context) 2681{ 2682 KQSocketSet *cp = &sock->ss; 2683 int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6; 2684 KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6; 2685 mStatus err = mStatus_NoError; 2686 struct sockaddr_storage ss; 2687 2688 sock->callback = callback; 2689 sock->context = context; 2690 sock->setup = mDNSfalse; 2691 sock->connected = mDNSfalse; 2692 sock->handshake = handshake_required; 2693 sock->err = mStatus_NoError; 2694 2695 if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); } 2696 2697 if (dst->type == mDNSAddrType_IPv4) 2698 { 2699 struct sockaddr_in *saddr = (struct sockaddr_in *)&ss; 2700 mDNSPlatformMemZero(saddr, sizeof(*saddr)); 2701 saddr->sin_family = AF_INET; 2702 saddr->sin_port = dstport.NotAnInteger; 2703 saddr->sin_len = sizeof(*saddr); 2704 saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger; 2705 } 2706 else 2707 { 2708 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss; 2709 mDNSPlatformMemZero(saddr6, sizeof(*saddr6)); 2710 saddr6->sin6_family = AF_INET6; 2711 saddr6->sin6_port = dstport.NotAnInteger; 2712 saddr6->sin6_len = sizeof(*saddr6); 2713 saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6; 2714 } 2715 2716 // Watch for connect complete (write is ready) 2717 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE 2718 if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k)) 2719 { 2720 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed"); 2721 return errno; 2722 } 2723 2724 // Watch for incoming data 2725 if (KQueueSet(*s, EV_ADD, EVFILT_READ, k)) 2726 { 2727 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed"); 2728 return errno; 2729 } 2730 2731 if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking 2732 { 2733 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno)); 2734 return mStatus_UnknownErr; 2735 } 2736 2737 // We bind to the interface and all subsequent packets including the SYN will be sent out 2738 // on this interface 2739 // 2740 // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in 2741 // UDP). mDNSInterface_Unicast indicates this case and not a valid interface. 2742 if (InterfaceID && InterfaceID != mDNSInterface_Unicast) 2743 { 2744 NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID); 2745 if (dst->type == mDNSAddrType_IPv4) 2746 { 2747 #ifdef IP_BOUND_IF 2748 if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id)); 2749 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; } 2750 #else 2751 (void)InterfaceID; // Unused 2752 (void)info; // Unused 2753 #endif 2754 } 2755 else 2756 { 2757 #ifdef IPV6_BOUND_IF 2758 if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id)); 2759 else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; } 2760 #else 2761 (void)InterfaceID; // Unused 2762 (void)info; // Unused 2763 #endif 2764 } 2765 } 2766 2767 // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address 2768 // from which we can infer the destination address family. Hence we need to remember that here. 2769 // Instead of remembering the address family, we remember the right fd. 2770 sock->fd = *s; 2771 sock->kqEntry = k; 2772 // initiate connection wth peer 2773 if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0) 2774 { 2775 if (errno == EINPROGRESS) return mStatus_ConnPending; 2776 if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN) 2777 LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno)); 2778 else 2779 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len); 2780 return mStatus_ConnFailed; 2781 } 2782 2783 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously"); 2784 // kQueue should notify us, but this LogMsg is to help track down if it doesn't 2785 return err; 2786} 2787 2788// Why doesn't mDNSPlatformTCPAccept actually call accept() ? 2789mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd) 2790{ 2791 mStatus err = mStatus_NoError; 2792 2793 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket)); 2794 if (!sock) return(mDNSNULL); 2795 2796 mDNSPlatformMemZero(sock, sizeof(*sock)); 2797 sock->fd = fd; 2798 sock->flags = flags; 2799 2800 if (flags & kTCPSocketFlags_UseTLS) 2801 { 2802#ifndef NO_SECURITYFRAMEWORK 2803 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; } 2804 2805 err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType); 2806 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; } 2807 2808 err = SSLSetCertificate(sock->tlsContext, ServerCerts); 2809 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; } 2810#else 2811 err = mStatus_UnsupportedErr; 2812#endif /* NO_SECURITYFRAMEWORK */ 2813 } 2814#ifndef NO_SECURITYFRAMEWORK 2815exit: 2816#endif 2817 2818 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); } 2819 return(sock); 2820} 2821 2822mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock) 2823{ 2824 mDNSu16 port; 2825 2826 port = -1; 2827 if (sock) 2828 { 2829 port = sock->ss.port.NotAnInteger; 2830 } 2831 return port; 2832} 2833 2834mDNSlocal void CloseSocketSet(KQSocketSet *ss) 2835{ 2836 if (ss->sktv4 != -1) 2837 { 2838 mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4); 2839 ss->sktv4 = -1; 2840 } 2841 if (ss->sktv6 != -1) 2842 { 2843 mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6); 2844 ss->sktv6 = -1; 2845 } 2846 if (ss->closeFlag) *ss->closeFlag = 1; 2847} 2848 2849mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock) 2850{ 2851 if (sock) 2852 { 2853#ifndef NO_SECURITYFRAMEWORK 2854 if (sock->tlsContext) 2855 { 2856 if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext) 2857 { 2858 LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress"); 2859 // When we come back from SSLHandshake, we will notice that a close was here and 2860 // call this function again which will do the cleanup then. 2861 sock->handshake = handshake_to_be_closed; 2862 return; 2863 } 2864 2865 SSLClose(sock->tlsContext); 2866 CFRelease(sock->tlsContext); 2867 sock->tlsContext = NULL; 2868 } 2869#endif /* NO_SECURITYFRAMEWORK */ 2870 if (sock->ss.sktv4 != -1) 2871 shutdown(sock->ss.sktv4, 2); 2872 if (sock->ss.sktv6 != -1) 2873 shutdown(sock->ss.sktv6, 2); 2874 CloseSocketSet(&sock->ss); 2875 sock->fd = -1; 2876 2877 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock); 2878 } 2879} 2880 2881mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed) 2882{ 2883 ssize_t nread = 0; 2884 *closed = mDNSfalse; 2885 2886 if (sock->flags & kTCPSocketFlags_UseTLS) 2887 { 2888#ifndef NO_SECURITYFRAMEWORK 2889 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; } 2890 else if (sock->handshake == handshake_in_progress) return 0; 2891 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake); 2892 2893 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0)); 2894 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread); 2895 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen); 2896 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; } 2897 else if (err && err != errSSLWouldBlock) 2898 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; } 2899#else 2900 nread = -1; 2901 *closed = mDNStrue; 2902#endif /* NO_SECURITYFRAMEWORK */ 2903 } 2904 else 2905 { 2906 static int CLOSEDcount = 0; 2907 static int EAGAINcount = 0; 2908 nread = recv(sock->fd, buf, buflen, 0); 2909 2910 if (nread > 0) 2911 { 2912 CLOSEDcount = 0; 2913 EAGAINcount = 0; 2914 } // On success, clear our error counters 2915 else if (nread == 0) 2916 { 2917 *closed = mDNStrue; 2918 if ((++CLOSEDcount % 1000) == 0) 2919 { 2920 LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); 2921 assert(CLOSEDcount < 1000); 2922 // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times, 2923 // crash mDNSResponder using assert() and restart fresh. See advantages below: 2924 // 1.Better User Experience 2925 // 2.CrashLogs frequency can be monitored 2926 // 3.StackTrace can be used for more info 2927 } 2928 } 2929 // else nread is negative -- see what kind of error we got 2930 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; } 2931 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; } 2932 else // errno is EAGAIN (EWOULDBLOCK) -- no data available 2933 { 2934 nread = 0; 2935 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); } 2936 } 2937 } 2938 2939 return nread; 2940} 2941 2942mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len) 2943{ 2944 int nsent; 2945 2946 if (sock->flags & kTCPSocketFlags_UseTLS) 2947 { 2948#ifndef NO_SECURITYFRAMEWORK 2949 size_t processed; 2950 if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; } 2951 if (sock->handshake == handshake_in_progress) return 0; 2952 else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake); 2953 2954 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed); 2955 2956 if (!err) nsent = (int) processed; 2957 else if (err == errSSLWouldBlock) nsent = 0; 2958 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; } 2959#else 2960 nsent = -1; 2961#endif /* NO_SECURITYFRAMEWORK */ 2962 } 2963 else 2964 { 2965 nsent = send(sock->fd, msg, len, 0); 2966 if (nsent < 0) 2967 { 2968 if (errno == EAGAIN) nsent = 0; 2969 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; } 2970 } 2971 } 2972 2973 return nsent; 2974} 2975 2976mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) 2977{ 2978 return sock->fd; 2979} 2980 2981// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface 2982// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries 2983mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport) 2984{ 2985 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6; 2986 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6; 2987 const int on = 1; 2988 const int twofivefive = 255; 2989 mStatus err = mStatus_NoError; 2990 char *errstr = mDNSNULL; 2991 const int mtu = 0; 2992 2993 cp->closeFlag = mDNSNULL; 2994 2995 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP); 2996 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); } 2997 2998 // set default traffic class 2999 setTrafficClass(skt, mDNSfalse); 3000 3001#ifdef SO_RECV_ANYIF 3002 // Enable inbound packets on IFEF_AWDL interface. 3003 // Only done for multicast sockets, since we don't expect unicast socket operations 3004 // on the IFEF_AWDL interface. Operation is a no-op for other interface types. 3005 if (mDNSSameIPPort(port, MulticastDNSPort)) 3006 { 3007 err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on)); 3008 if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; } 3009 } 3010#endif // SO_RECV_ANYIF 3011 3012 // ... with a shared UDP port, if it's for multicast receiving 3013 if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); 3014 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; } 3015 3016 if (sa_family == AF_INET) 3017 { 3018 // We want to receive destination addresses 3019 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); 3020 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; } 3021 3022 // We want to receive interface identifiers 3023 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)); 3024 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; } 3025 3026 // We want to receive packet TTL value so we can check it 3027 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on)); 3028 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it 3029 3030 // Send unicast packets with TTL 255 3031 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive)); 3032 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; } 3033 3034 // And multicast packets with TTL 255 too 3035 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive)); 3036 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; } 3037 3038 // And start listening for packets 3039 struct sockaddr_in listening_sockaddr; 3040 listening_sockaddr.sin_family = AF_INET; 3041 listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping 3042 listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0; 3043 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr)); 3044 if (err) { errstr = "bind"; goto fail; } 3045 if (outport) outport->NotAnInteger = listening_sockaddr.sin_port; 3046 } 3047 else if (sa_family == AF_INET6) 3048 { 3049 // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error 3050 if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; } 3051 3052 // We want to receive destination addresses and receive interface identifiers 3053 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); 3054 if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; } 3055 3056 // We want to receive packet hop count value so we can check it 3057 err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)); 3058 if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; } 3059 3060 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too, 3061 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address 3062 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); 3063 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; } 3064 3065 // Send unicast packets with TTL 255 3066 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive)); 3067 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; } 3068 3069 // And multicast packets with TTL 255 too 3070 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive)); 3071 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; } 3072 3073 // Want to receive our own packets 3074 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on)); 3075 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; } 3076 3077 // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11 3078 err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu)); 3079 if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt 3080 LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)", 3081 skt, err, errno, strerror(errno)); 3082 3083 // And start listening for packets 3084 struct sockaddr_in6 listening_sockaddr6; 3085 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6)); 3086 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6); 3087 listening_sockaddr6.sin6_family = AF_INET6; 3088 listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping 3089 listening_sockaddr6.sin6_flowinfo = 0; 3090 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket 3091 listening_sockaddr6.sin6_scope_id = 0; 3092 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6)); 3093 if (err) { errstr = "bind"; goto fail; } 3094 if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port; 3095 } 3096 3097 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking 3098 fcntl(skt, F_SETFD, 1); // set close-on-exec 3099 *s = skt; 3100 k->KQcallback = myKQSocketCallBack; 3101 k->KQcontext = cp; 3102 k->KQtask = "UDP packet reception"; 3103#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 3104 k->readSource = mDNSNULL; 3105 k->writeSource = mDNSNULL; 3106 k->fdClosed = mDNSfalse; 3107#endif 3108 KQueueSet(*s, EV_ADD, EVFILT_READ, k); 3109 3110 return(err); 3111 3112fail: 3113 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero 3114 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port)) 3115 LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno)); 3116 3117 // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port 3118 if (!strcmp(errstr, "bind") && errno == EADDRINUSE) 3119 { 3120 err = EADDRINUSE; 3121 if (mDNSSameIPPort(port, MulticastDNSPort)) 3122 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3123 "Congratulations, you've reproduced an elusive bug.\r" 3124 "Please contact the current assignee of <rdar://problem/3814904>.\r" 3125 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r" 3126 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem."); 3127 } 3128 3129 mDNSPlatformCloseFD(k, skt); 3130 return(err); 3131} 3132 3133mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport) 3134{ 3135 mStatus err; 3136 mDNSIPPort port = requestedport; 3137 mDNSBool randomizePort = mDNSIPPortIsZero(requestedport); 3138 int i = 10000; // Try at most 10000 times to get a unique random port 3139 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket)); 3140 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); } 3141 mDNSPlatformMemZero(p, sizeof(UDPSocket)); 3142 p->ss.port = zeroIPPort; 3143 p->ss.m = m; 3144 p->ss.sktv4 = -1; 3145 p->ss.sktv6 = -1; 3146 p->ss.proxy = mDNSfalse; 3147 3148 do 3149 { 3150 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here 3151 if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF)); 3152 err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port); 3153 if (!err) 3154 { 3155 err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port); 3156 if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; } 3157 } 3158 i--; 3159 } while (err == EADDRINUSE && randomizePort && i); 3160 3161 if (err) 3162 { 3163 // In customer builds we don't want to log failures with port 5351, because this is a known issue 3164 // of failing to bind to this port when Internet Sharing has already bound to it 3165 // We also don't want to log about port 5350, due to a known bug when some other 3166 // process is bound to it. 3167 if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort)) 3168 LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); 3169 else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); 3170 freeL("UDPSocket", p); 3171 return(mDNSNULL); 3172 } 3173 return(p); 3174} 3175 3176mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) 3177{ 3178 CloseSocketSet(&sock->ss); 3179 freeL("UDPSocket", sock); 3180} 3181 3182#if COMPILER_LIKES_PRAGMA_MARK 3183#pragma mark - 3184#pragma mark - BPF Raw packet sending/receiving 3185#endif 3186 3187#if APPLE_OSX_mDNSResponder 3188 3189mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) 3190{ 3191 if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; } 3192 NetworkInterfaceInfoOSX *info; 3193 3194 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID); 3195 if (info == NULL) 3196 { 3197 LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID); 3198 return; 3199 } 3200 if (info->BPF_fd < 0) 3201 LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd); 3202 else 3203 { 3204 //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname); 3205 if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0) 3206 LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno)); 3207 } 3208} 3209 3210mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID) 3211{ 3212 if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; } 3213 NetworkInterfaceInfoOSX *info; 3214 info = IfindexToInterfaceInfoOSX(m, InterfaceID); 3215 if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; } 3216 // Manually inject an entry into our local ARP cache. 3217 // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.) 3218 if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL)) 3219 LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha); 3220 else 3221 { 3222 int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b); 3223 if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result); 3224 else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha); 3225 } 3226} 3227 3228mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i) 3229{ 3230 LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd); 3231#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 3232 // close will happen in the cancel handler 3233 dispatch_source_cancel(i->BPF_source); 3234#else 3235 3236 // Note: MUST NOT close() the underlying native BSD sockets. 3237 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because 3238 // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them. 3239 CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); 3240 CFRelease(i->BPF_rls); 3241 CFSocketInvalidate(i->BPF_cfs); 3242 CFRelease(i->BPF_cfs); 3243#endif 3244 i->BPF_fd = -1; 3245 if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; } 3246} 3247 3248mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info) 3249{ 3250 KQueueLock(info->m); 3251 3252 // 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 3253 // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition). 3254 if (info->BPF_fd < 0) goto exit; 3255 3256 ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len); 3257 const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg; 3258 const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n; 3259 debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname); 3260 3261 if (n<0) 3262 { 3263 /* <rdar://problem/10287386> 3264 * sometimes there can be a race condition btw when the bpf socket 3265 * gets data and the callback get scheduled and when we call BIOCSETF (which 3266 * clears the socket). this can cause the read to hang for a really long time 3267 * and effectively prevent us from responding to requests for long periods of time. 3268 * to prevent this make the socket non blocking and just bail if we dont get anything 3269 */ 3270 if (errno == EAGAIN) 3271 { 3272 LogMsg("bpf_callback got EAGAIN bailing"); 3273 goto exit; 3274 } 3275 LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno)); 3276 CloseBPF(info); 3277 goto exit; 3278 } 3279 3280 while (ptr < end) 3281 { 3282 const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr; 3283 debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d", 3284 info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen, 3285 ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen))); 3286 // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header. 3287 // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header, 3288 // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned. 3289 mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID); 3290 ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); 3291 } 3292exit: 3293 KQueueUnlock(info->m, "bpf_callback"); 3294} 3295#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 3296mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info) 3297{ 3298 bpf_callback_common(info); 3299} 3300#else 3301mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context) 3302{ 3303 (void)cfs; 3304 (void)CallBackType; 3305 (void)address; 3306 (void)data; 3307 bpf_callback_common((NetworkInterfaceInfoOSX *)context); 3308} 3309#endif 3310 3311mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win) 3312{ 3313 LogMsg("mDNSPlatformSendKeepalive called\n"); 3314 mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win); 3315} 3316 3317mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) 3318{ 3319 SCDynamicStoreRef store = NULL; 3320 CFStringRef entityname = NULL; 3321 3322 if ((store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ClearSPSMACAddress"), NULL, NULL))) 3323 { 3324 if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress"))) 3325 { 3326 if (SCDynamicStoreRemoveValue(store, entityname) == false) 3327 LogMsg("mDNSPlatformClearSPSMACAddr: Unable to remove key"); 3328 } 3329 } 3330 3331 if (entityname) CFRelease(entityname); 3332 if (store) CFRelease(store); 3333 return KERN_SUCCESS; 3334} 3335 3336mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname) 3337{ 3338 int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; 3339 LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname); 3340 mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname); 3341 return KERN_SUCCESS; 3342} 3343 3344mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr) 3345{ 3346 int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; 3347 3348 mDNSGetRemoteMAC(m, family, raddr->ip.v6.b); 3349 return KERN_SUCCESS; 3350} 3351 3352mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti) 3353{ 3354 mDNSs32 intfid; 3355 mDNSs32 error = 0; 3356 int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6; 3357 3358 error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid); 3359 if (error != KERN_SUCCESS) 3360 { 3361 LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error); 3362 return error; 3363 } 3364 mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid); 3365 return error; 3366} 3367 3368#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from) 3369 3370mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6) 3371{ 3372 int numv4 = 0, numv6 = 0; 3373 AuthRecord *rr; 3374 3375 for (rr = m->ResourceRecords; rr; rr=rr->next) 3376 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4) 3377 { 3378 if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4); 3379 numv4++; 3380 } 3381 3382 for (rr = m->ResourceRecords; rr; rr=rr->next) 3383 if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6) 3384 { 3385 if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6); 3386 numv6++; 3387 } 3388 3389 if (p4) *p4 = numv4; 3390 if (p6) *p6 = numv6; 3391 return(numv4 + numv6); 3392} 3393 3394mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID) 3395{ 3396 NetworkInterfaceInfoOSX *x; 3397 3398 // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also. 3399 for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break; 3400 3401 if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; } 3402 3403 #define MAX_BPF_ADDRS 250 3404 int numv4 = 0, numv6 = 0; 3405 3406 if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS) 3407 { 3408 LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6); 3409 if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS; 3410 numv6 = MAX_BPF_ADDRS - numv4; 3411 } 3412 3413 LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6); 3414 3415 // Caution: This is a static structure, so we need to be careful that any modifications we make to it 3416 // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times 3417 static struct bpf_insn filter[17 + MAX_BPF_ADDRS] = 3418 { 3419 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13) 3420 3421 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3 3422 BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP 3423 3424 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next 3425 3426 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit 3427 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21) 3428 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check 3429 BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND 3430 3431 // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for 3432 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33) 3433 }; 3434 3435 struct bpf_insn *pc = &filter[9]; 3436 struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0" 3437 struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks 3438 struct bpf_insn *ret4 = fail + 1; 3439 struct bpf_insn *ret6 = ret4 + 4; 3440 3441 static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing 3442 3443 static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53) 3444 3445 static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20) 3446 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) 3447 static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length 3448 static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74) 3449 3450 static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare 3451 3452 BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail 3453 BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check 3454 3455 // BPF Byte-Order Note 3456 // The BPF API designers apparently thought that programmers would not be smart enough to use htons 3457 // and htonl correctly to convert numeric values to network byte order on little-endian machines, 3458 // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings 3459 // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc. 3460 // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API 3461 // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange 3462 // that on little-endian machines we deliberately put addresses in memory with the bytes backwards, 3463 // so that when the BPF API goes through and swaps them all, they end up back as they should be. 3464 // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't* 3465 // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly. 3466 3467 // IPSEC capture size notes: 3468 // 8 bytes UDP header 3469 // 4 bytes Non-ESP Marker 3470 // 28 bytes IKE Header 3471 // -- 3472 // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet. 3473 3474 AuthRecord *rr; 3475 for (rr = m->ResourceRecords; rr; rr=rr->next) 3476 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4) 3477 { 3478 mDNSv4Addr a = rr->AddressProxy.ip.v4; 3479 pc->code = BPF_JMP + BPF_JEQ + BPF_K; 3480 BPF_SetOffset(pc, jt, ret4); 3481 pc->jf = 0; 3482 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]; 3483 pc++; 3484 } 3485 *pc++ = rf; 3486 3487 if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6); 3488 *pc++ = g6; // chk6 points here 3489 3490 // First cancel any previous ND group memberships we had, then create a fresh socket 3491 if (x->BPF_mcfd >= 0) close(x->BPF_mcfd); 3492 x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0); 3493 3494 for (rr = m->ResourceRecords; rr; rr=rr->next) 3495 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6) 3496 { 3497 const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6; 3498 pc->code = BPF_JMP + BPF_JEQ + BPF_K; 3499 BPF_SetOffset(pc, jt, ret6); 3500 pc->jf = 0; 3501 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]; 3502 pc++; 3503 3504 struct ipv6_mreq i6mr; 3505 i6mr.ipv6mr_interface = x->scope_id; 3506 i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix; 3507 i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD]; 3508 i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE]; 3509 i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF]; 3510 3511 // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state 3512 mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr)); 3513 if (err < 0 && (errno != EADDRNOTAVAIL)) 3514 LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); 3515 3516 err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); 3517 if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that 3518 LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); 3519 3520 LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a); 3521 } 3522 3523 if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail); 3524 *pc++ = rf; // fail points here 3525 3526 if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4); 3527 *pc++ = r4a; // ret4 points here 3528 *pc++ = r4b; 3529 *pc++ = r4c; 3530 *pc++ = r4d; 3531 3532 if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6); 3533 *pc++ = r6a; // ret6 points here 3534 3535 struct bpf_program prog = { pc - filter, filter }; 3536 3537#if 0 3538 // For debugging BPF filter program 3539 unsigned int q; 3540 for (q=0; q<prog.bf_len; q++) 3541 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); 3542#endif 3543 3544 if (!numv4 && !numv6) 3545 { 3546 LogSPS("mDNSPlatformUpdateProxyList: No need for filter"); 3547 if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0"); 3548 // Schedule check to see if we can close this BPF_fd now 3549 if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2); 3550 // prog.bf_len = 0; This seems to panic the kernel 3551 if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below 3552 } 3553 3554 if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno)); 3555 else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len); 3556} 3557 3558mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd) 3559{ 3560 mDNS_Lock(m); 3561 3562 NetworkInterfaceInfoOSX *i; 3563 for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break; 3564 if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); } 3565 else 3566 { 3567 LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd); 3568 3569 struct bpf_version v; 3570 if (ioctl(fd, BIOCVERSION, &v) < 0) 3571 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3572 else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor) 3573 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d", 3574 fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor); 3575 3576 if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0) 3577 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3578 3579 if (i->BPF_len > sizeof(m->imsg)) 3580 { 3581 i->BPF_len = sizeof(m->imsg); 3582 if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0) 3583 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3584 else 3585 LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len); 3586 } 3587 3588 static const u_int opt_one = 1; 3589 if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0) 3590 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3591 3592 //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0) 3593 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3594 3595 //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0) 3596 // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3597 3598 /* <rdar://problem/10287386> 3599 * make socket non blocking see comments in bpf_callback_common for more info 3600 */ 3601 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking 3602 { 3603 LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); 3604 } 3605 3606 struct ifreq ifr; 3607 mDNSPlatformMemZero(&ifr, sizeof(ifr)); 3608 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name)); 3609 if (ioctl(fd, BIOCSETIF, &ifr) < 0) 3610 { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; } 3611 else 3612 { 3613#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 3614 i->BPF_fd = fd; 3615 i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue()); 3616 if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;} 3617 dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);}); 3618 dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);}); 3619 dispatch_resume(i->BPF_source); 3620#else 3621 CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL }; 3622 i->BPF_fd = fd; 3623 i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext); 3624 i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0); 3625 CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); 3626#endif 3627 mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID); 3628 } 3629 } 3630 3631 mDNS_Unlock(m); 3632} 3633 3634#endif // APPLE_OSX_mDNSResponder 3635 3636#if COMPILER_LIKES_PRAGMA_MARK 3637#pragma mark - 3638#pragma mark - Key Management 3639#endif 3640 3641#ifndef NO_SECURITYFRAMEWORK 3642mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity) 3643{ 3644 CFMutableArrayRef certChain = NULL; 3645 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); } 3646 SecCertificateRef cert; 3647 OSStatus err = SecIdentityCopyCertificate(identity, &cert); 3648 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err); 3649 else 3650 { 3651 SecPolicySearchRef searchRef; 3652 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef); 3653 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err); 3654 else 3655 { 3656 SecPolicyRef policy; 3657 err = SecPolicySearchCopyNext(searchRef, &policy); 3658 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err); 3659 else 3660 { 3661 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks); 3662 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL"); 3663 else 3664 { 3665 SecTrustRef trust; 3666 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust); 3667 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err); 3668 else 3669 { 3670 err = SecTrustEvaluate(trust, NULL); 3671 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err); 3672 else 3673 { 3674 CFArrayRef rawCertChain; 3675 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 3676 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain); 3677 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err); 3678 else 3679 { 3680 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain); 3681 if (!certChain) LogMsg("getCertChain: certChain is NULL"); 3682 else 3683 { 3684 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate: 3685 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html> 3686 CFArraySetValueAtIndex(certChain, 0, identity); 3687 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate 3688 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1); 3689 } 3690 CFRelease(rawCertChain); 3691 // Do not free statusChain: 3692 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says: 3693 // certChain: Call the CFRelease function to release this object when you are finished with it. 3694 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released... 3695 } 3696 } 3697 CFRelease(trust); 3698 } 3699 CFRelease(wrappedCert); 3700 } 3701 CFRelease(policy); 3702 } 3703 CFRelease(searchRef); 3704 } 3705 CFRelease(cert); 3706 } 3707 return certChain; 3708} 3709#endif /* NO_SECURITYFRAMEWORK */ 3710 3711mDNSexport mStatus mDNSPlatformTLSSetupCerts(void) 3712{ 3713#ifdef NO_SECURITYFRAMEWORK 3714 return mStatus_UnsupportedErr; 3715#else 3716 SecIdentityRef identity = nil; 3717 SecIdentitySearchRef srchRef = nil; 3718 OSStatus err; 3719 3720 // search for "any" identity matching specified key use 3721 // In this app, we expect there to be exactly one 3722 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef); 3723 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; } 3724 3725 err = SecIdentitySearchCopyNext(srchRef, &identity); 3726 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; } 3727 3728 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) 3729 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; } 3730 3731 // Found one. Call getCertChain to create the correct certificate chain. 3732 ServerCerts = GetCertChain(identity); 3733 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; } 3734 3735 return mStatus_NoError; 3736#endif /* NO_SECURITYFRAMEWORK */ 3737} 3738 3739mDNSexport void mDNSPlatformTLSTearDownCerts(void) 3740{ 3741#ifndef NO_SECURITYFRAMEWORK 3742 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; } 3743#endif /* NO_SECURITYFRAMEWORK */ 3744} 3745 3746// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel 3747mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel) 3748{ 3749 CFStringEncoding encoding = kCFStringEncodingUTF8; 3750 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding); 3751 if (cfs) 3752 { 3753 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); 3754 CFRelease(cfs); 3755 } 3756} 3757 3758// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel 3759mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel) 3760{ 3761 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL); 3762 if (cfs) 3763 { 3764 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); 3765 CFRelease(cfs); 3766 } 3767} 3768 3769mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict) 3770{ 3771 mDNSs32 val; 3772 CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled")); 3773 if (!state) return mDNSfalse; 3774 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) 3775 { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; } 3776 return val ? mDNStrue : mDNSfalse; 3777} 3778 3779mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) 3780{ 3781 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); } 3782 3783 if (sa->sa_family == AF_INET) 3784 { 3785 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa; 3786 ip->type = mDNSAddrType_IPv4; 3787 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr; 3788 return(mStatus_NoError); 3789 } 3790 3791 if (sa->sa_family == AF_INET6) 3792 { 3793 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa; 3794 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id 3795 // value into the second word of the IPv6 link-local address, so they can just 3796 // pass around IPv6 address structures instead of full sockaddr_in6 structures. 3797 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do. 3798 // To work around this we always whack the second word of any IPv6 link-local address back to zero. 3799 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0; 3800 ip->type = mDNSAddrType_IPv6; 3801 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr; 3802 return(mStatus_NoError); 3803 } 3804 3805 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family); 3806 return(mStatus_Invalid); 3807} 3808 3809mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name) 3810{ 3811 mDNSEthAddr eth = zeroEthAddr; 3812 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL); 3813 if (!store) 3814 LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 3815 else 3816 { 3817 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name); 3818 if (entityname) 3819 { 3820 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname); 3821 if (dict) 3822 { 3823 CFRange range = { 0, 6 }; // Offset, length 3824 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID")); 3825 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b); 3826 CFRelease(dict); 3827 } 3828 CFRelease(entityname); 3829 } 3830 CFRelease(store); 3831 } 3832 return(eth); 3833} 3834 3835mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex) 3836{ 3837 struct ifaddrs *ifa; 3838 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next) 3839 if (ifa->ifa_addr->sa_family == AF_LINK) 3840 { 3841 const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr; 3842 if (sdl->sdl_index == ifindex) 3843 { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; } 3844 } 3845 *eth = zeroEthAddr; 3846 return -1; 3847} 3848 3849#ifndef SIOCGIFWAKEFLAGS 3850#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */ 3851#endif 3852 3853#ifndef IF_WAKE_ON_MAGIC_PACKET 3854#define IF_WAKE_ON_MAGIC_PACKET 0x01 3855#endif 3856 3857#ifndef ifr_wake_flags 3858#define ifr_wake_flags ifr_ifru.ifru_intval 3859#endif 3860 3861mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key) 3862{ 3863 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname)); 3864 if (!service) 3865 { 3866 LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname); 3867 return mDNSfalse; 3868 } 3869 3870 io_name_t n1, n2; 3871 IOObjectGetClass(service, n1); 3872 io_object_t parent; 3873 mDNSBool ret = mDNSfalse; 3874 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); 3875 if (kr == KERN_SUCCESS) 3876 { 3877 CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8); 3878 IOObjectGetClass(parent, n2); 3879 LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2); 3880 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL); 3881 if (!ref) 3882 { 3883 LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2); 3884 ret = mDNSfalse; 3885 } 3886 else 3887 { 3888 ret = mDNStrue; 3889 CFRelease(ref); 3890 } 3891 IOObjectRelease(parent); 3892 CFRelease(keystr); 3893 } 3894 else 3895 { 3896 LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr); 3897 ret = mDNSfalse; 3898 } 3899 IOObjectRelease(service); 3900 return ret; 3901} 3902 3903 3904mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf) 3905{ 3906 return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY); 3907} 3908 3909mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i) 3910{ 3911 if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces 3912 if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback 3913 3914 // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet 3915 // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability 3916 // when the power source is not AC Power. 3917 if (InterfaceSupportsKeepAlive(&i->ifinfo)) 3918 { 3919 LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname); 3920 return mDNStrue; 3921 } 3922 3923 int s = socket(AF_INET, SOCK_DGRAM, 0); 3924 if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); } 3925 3926 struct ifreq ifr; 3927 strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name)); 3928 if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0) 3929 { 3930 // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be 3931 // 102 when compiling kernel code, and 45 when compiling user-level code. Since this 3932 // error code is being returned from the kernel, we need to use the kernel version. 3933 #define KERNEL_EOPNOTSUPP 102 3934 if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier 3935 LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno)); 3936 // If on Leopard or earlier, we get EOPNOTSUPP, so in that case 3937 // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on. 3938 ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0; 3939 } 3940 3941 close(s); 3942 3943 // 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 3944 3945 LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no"); 3946 3947 return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0); 3948} 3949 3950mDNSlocal u_int64_t getExtendedFlags(char * ifa_name) 3951{ 3952 int sockFD; 3953 struct ifreq ifr; 3954 3955 sockFD = socket(AF_INET, SOCK_DGRAM, 0); 3956 if (sockFD < 0) 3957 { 3958 LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno)); 3959 return 0; 3960 } 3961 3962 ifr.ifr_addr.sa_family = AF_INET; 3963 strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name)); 3964 3965 if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1) 3966 { 3967 LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno)); 3968 ifr.ifr_eflags = 0; 3969 } 3970 LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags); 3971 3972 close(sockFD); 3973 return ifr.ifr_eflags; 3974} 3975 3976// Returns pointer to newly created NetworkInterfaceInfoOSX object, or 3977// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or 3978// may return NULL if out of memory (unlikely) or parameters are invalid for some reason 3979// (e.g. sa_family not AF_INET or AF_INET6) 3980mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc) 3981{ 3982 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name); 3983 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name); 3984 u_int64_t eflags = getExtendedFlags(ifa->ifa_name); 3985 3986 mDNSAddr ip, mask; 3987 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL); 3988 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL); 3989 3990 NetworkInterfaceInfoOSX **p; 3991 for (p = &m->p->InterfaceList; *p; p = &(*p)->next) 3992 if (scope_id == (*p)->scope_id && 3993 mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && 3994 mDNSSameEthAddress(&bssid, &(*p)->BSSID)) 3995 { 3996 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); 3997 // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output. 3998 // When interfaces are created with same MAC address, kernel resurrects the old interface. 3999 // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet 4000 // we get the corresponding name for the interface index on which the packet was received and check against 4001 // the InterfaceList for a matching name. So, keep the name in sync 4002 strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname)); 4003 (*p)->Exists = mDNStrue; 4004 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record 4005 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc; 4006 4007 // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected) 4008 // we may need to start or stop or sleep proxy browse operation 4009 const mDNSBool NetWake = NetWakeInterface(*p); 4010 if ((*p)->ifinfo.NetWake != NetWake) 4011 { 4012 (*p)->ifinfo.NetWake = NetWake; 4013 // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly. 4014 // If this interface is not already registered (i.e. it's a dormant interface we had in our list 4015 // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet. 4016 // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary. 4017 if ((*p)->Registered) 4018 { 4019 mDNS_Lock(m); 4020 if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo); 4021 else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo); 4022 mDNS_Unlock(m); 4023 } 4024 } 4025 // Reset the flag if it has changed this time. 4026 (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue; 4027 4028 return(*p); 4029 } 4030 4031 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i)); 4032 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i); 4033 if (!i) return(mDNSNULL); 4034 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX)); 4035 i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id; 4036 i->ifinfo.ip = ip; 4037 i->ifinfo.mask = mask; 4038 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname)); 4039 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0; 4040 // We can be configured to disable multicast advertisement, but we want to to support 4041 // local-only services, which need a loopback address record. 4042 i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses; 4043 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList 4044 i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse; 4045 i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue; 4046 i->ifinfo.DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse; 4047 4048 i->next = mDNSNULL; 4049 i->m = m; 4050 i->Exists = mDNStrue; 4051 i->Flashing = mDNSfalse; 4052 i->Occulting = mDNSfalse; 4053 i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse; 4054 if (eflags & IFEF_AWDL) 4055 { 4056 AWDLInterfaceID = i->ifinfo.InterfaceID; 4057 LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID); 4058 } 4059 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now 4060 i->LastSeen = utc; 4061 i->ifa_flags = ifa->ifa_flags; 4062 i->scope_id = scope_id; 4063 i->BSSID = bssid; 4064 i->sa_family = ifa->ifa_addr->sa_family; 4065 i->BPF_fd = -1; 4066 i->BPF_mcfd = -1; 4067 i->BPF_len = 0; 4068 i->Registered = mDNSNULL; 4069 4070 // Do this AFTER i->BSSID has been set up 4071 i->ifinfo.NetWake = NetWakeInterface(i); 4072 GetMAC(&i->ifinfo.MAC, scope_id); 4073 if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0]) 4074 LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip); 4075 4076 *p = i; 4077 return(i); 4078} 4079 4080#if APPLE_OSX_mDNSResponder 4081 4082#if COMPILER_LIKES_PRAGMA_MARK 4083#pragma mark - 4084#pragma mark - AutoTunnel 4085#endif 4086 4087#define kRacoonPort 4500 4088 4089static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL; 4090 4091#ifndef NO_SECURITYFRAMEWORK 4092 4093static CFMutableDictionaryRef domainStatusDict = NULL; 4094 4095mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q) 4096{ 4097 if (q->LongLived) 4098 { 4099 if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4)) 4100 return mStatus_NoSuchRecord; 4101 else if (q->state == LLQ_Poll) 4102 return mStatus_PollingMode; 4103 else if (q->state != LLQ_Established && !q->DuplicateOf) 4104 return mStatus_TransientErr; 4105 } 4106 4107 return mStatus_NoError; 4108} 4109 4110mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info) 4111{ 4112 mStatus status = mStatus_NoError; 4113 DNSQuestion* q, *worst_q = mDNSNULL; 4114 for (q = m->Questions; q; q=q->next) 4115 if (q->AuthInfo == info) 4116 { 4117 mStatus newStatus = CheckQuestionForStatus(q); 4118 if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; } 4119 else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; } 4120 else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; } 4121 } 4122 4123 if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success"); 4124 else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c); 4125 else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c); 4126 else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c); 4127 return status; 4128} 4129 4130mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info) 4131{ 4132 AuthRecord *r; 4133 4134 if (info->deltime) return mStatus_NoError; 4135 for (r = m->ResourceRecords; r; r = r->next) 4136 { 4137 // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from 4138 // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1), 4139 // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller 4140 // has already checked 4141 const domainname *n = r->resrec.name; 4142 while (n->c[0]) 4143 { 4144 DomainAuthInfo *ptr; 4145 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next) 4146 if (SameDomainName(&ptr->domain, n)) 4147 { 4148 if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime)) 4149 { 4150 mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name); 4151 return r->updateError; 4152 } 4153 } 4154 n = (const domainname *)(n->c + 1 + n->c[0]); 4155 } 4156 } 4157 return mStatus_NoError; 4158} 4159 4160#endif // ndef NO_SECURITYFRAMEWORK 4161 4162// MUST be called with lock held 4163mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info) 4164{ 4165#ifdef NO_SECURITYFRAMEWORK 4166 (void) m; 4167 (void)info; 4168#else 4169 // Note that in the LLQNAT, the clientCallback being non-zero means it's in use, 4170 // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use 4171 const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL; 4172 const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL; 4173 char buffer[1024]; 4174 mDNSu32 buflen = 0; 4175 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 4176 CFStringRef domain = NULL; 4177 CFStringRef tmp = NULL; 4178 CFNumberRef num = NULL; 4179 mStatus status = mStatus_NoError; 4180 mStatus llqStatus = mStatus_NoError; 4181 char llqBuffer[1024]; 4182 4183 mDNS_CheckLock(m); 4184 4185 if (!domainStatusDict) 4186 { 4187 domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 4188 if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; } 4189 } 4190 4191 if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; } 4192 4193 buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c); 4194 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 4195 if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; } 4196 4197 if (info->deltime) 4198 { 4199 if (CFDictionaryContainsKey(domainStatusDict, domain)) 4200 { 4201 CFDictionaryRemoveValue(domainStatusDict, domain); 4202 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict); 4203 } 4204 CFRelease(domain); 4205 CFRelease(dict); 4206 4207 return; 4208 } 4209 4210 mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router); 4211 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 4212 if (!tmp) 4213 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress"); 4214 else 4215 { 4216 CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp); 4217 CFRelease(tmp); 4218 } 4219 4220 if (llq) 4221 { 4222 mDNSu32 port = mDNSVal16(llq->ExternalPort); 4223 4224 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port); 4225 if (!num) 4226 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort"); 4227 else 4228 { 4229 CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num); 4230 CFRelease(num); 4231 } 4232 4233 if (llq->Result) 4234 { 4235 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result); 4236 if (!num) 4237 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus"); 4238 else 4239 { 4240 CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num); 4241 CFRelease(num); 4242 } 4243 } 4244 } 4245 4246 if (tun) 4247 { 4248 mDNSu32 port = mDNSVal16(tun->ExternalPort); 4249 4250 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port); 4251 if (!num) 4252 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort"); 4253 else 4254 { 4255 CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num); 4256 CFRelease(num); 4257 } 4258 4259 mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress); 4260 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 4261 if (!tmp) 4262 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress"); 4263 else 4264 { 4265 CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp); 4266 CFRelease(tmp); 4267 } 4268 4269 if (tun->Result) 4270 { 4271 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result); 4272 if (!num) 4273 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus"); 4274 else 4275 { 4276 CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num); 4277 CFRelease(num); 4278 } 4279 } 4280 } 4281 if (tun || llq) 4282 { 4283 mDNSu32 code = m->LastNATMapResultCode; 4284 4285 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code); 4286 if (!num) 4287 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode"); 4288 else 4289 { 4290 CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num); 4291 CFRelease(num); 4292 } 4293 } 4294 4295 mDNS_snprintf(buffer, sizeof(buffer), "Success"); 4296 llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info); 4297 status = UpdateRRStatus(m, buffer, sizeof(buffer), info); 4298 4299 // If we have a bad signature error updating a RR, it overrides any error as it needs to be 4300 // reported so that it can be fixed automatically (or the user needs to be notified) 4301 if (status != mStatus_NoError) 4302 { 4303 LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer); 4304 } 4305 else if (m->Router.type == mDNSAddrType_None) 4306 { 4307 status = mStatus_NoRouter; 4308 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none"); 4309 } 4310 else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4)) 4311 { 4312 status = mStatus_NoRouter; 4313 mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero"); 4314 } 4315 else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress)) 4316 { 4317 status = mStatus_ServiceNotRunning; 4318 mDNS_snprintf(buffer, sizeof(buffer), "No inner address"); 4319 } 4320 else if (!llq && !tun) 4321 { 4322 status = mStatus_NotInitializedErr; 4323 mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active"); 4324 } 4325 else if (llqStatus == mStatus_NoSuchRecord) 4326 { 4327 status = llqStatus; 4328 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); 4329 } 4330 else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT)) 4331 { 4332 status = mStatus_DoubleNAT; 4333 mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address"); 4334 } 4335 else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) || 4336 (tun && tun->Result == mStatus_NATPortMappingDisabled) || 4337 (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort))))) 4338 { 4339 status = mStatus_NATPortMappingDisabled; 4340 mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router"); 4341 } 4342 else if ((llq && llq->Result) || (tun && tun->Result)) 4343 { 4344 status = mStatus_NATTraversal; 4345 mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router"); 4346 } 4347 else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort))) 4348 { 4349 status = mStatus_NATTraversal; 4350 mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router"); 4351 } 4352 else 4353 { 4354 status = llqStatus; 4355 mDNS_snprintf(buffer, sizeof(buffer), llqBuffer); 4356 LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer); 4357 } 4358 4359 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); 4360 if (!num) 4361 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode"); 4362 else 4363 { 4364 CFDictionarySetValue(dict, CFSTR("StatusCode"), num); 4365 CFRelease(num); 4366 } 4367 4368 tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 4369 if (!tmp) 4370 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage"); 4371 else 4372 { 4373 CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp); 4374 CFRelease(tmp); 4375 } 4376 4377 if (!CFDictionaryContainsKey(domainStatusDict, domain) || 4378 !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain))) 4379 { 4380 CFDictionarySetValue(domainStatusDict, domain, dict); 4381 if (!m->ShutdownTime) 4382 { 4383 static char statusBuf[16]; 4384 mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status); 4385 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, ""); 4386 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict); 4387 } 4388 } 4389 4390 CFRelease(domain); 4391 CFRelease(dict); 4392 4393 debugf("UpdateAutoTunnelDomainStatus: %s", buffer); 4394#endif // def NO_SECURITYFRAMEWORK 4395} 4396 4397// MUST be called with lock held 4398mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m) 4399{ 4400#ifdef NO_SECURITYFRAMEWORK 4401 (void) m; 4402#else 4403 mDNS_CheckLock(m); 4404 DomainAuthInfo* info; 4405 for (info = m->AuthInfoList; info; info = info->next) 4406 if (info->AutoTunnel && !info->deltime) 4407 UpdateAutoTunnelDomainStatus(m, info); 4408#endif // def NO_SECURITYFRAMEWORK 4409} 4410 4411mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections 4412{ 4413 DomainAuthInfo *info; 4414 4415 for (info = m->AuthInfoList; info; info = info->next) 4416 if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))) 4417 break; 4418 4419 if (info != AnonymousRacoonConfig) 4420 { 4421 AnonymousRacoonConfig = info; 4422 // Create or revert configuration file, and start (or SIGHUP) Racoon 4423 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL); 4424 } 4425} 4426 4427mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result); 4428 4429// Caller must hold the lock 4430mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record) 4431{ 4432 mDNS_CheckLock(m); 4433 4434 LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c); 4435 4436 if (record->resrec.RecordType > kDNSRecordTypeDeregistering) 4437 { 4438 mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal); 4439 if (err) 4440 { 4441 record->resrec.RecordType = kDNSRecordTypeUnregistered; 4442 LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c); 4443 return mDNSfalse; 4444 } 4445 else LogInfo("DeregisterAutoTunnelRecord: Deregistered"); 4446 } 4447 else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType); 4448 4449 return mDNStrue; 4450} 4451 4452// Caller must hold the lock 4453mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info) 4454{ 4455 if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord)) 4456 { 4457 info->AutoTunnelHostRecord.namestorage.c[0] = 0; 4458 m->NextSRVUpdate = NonZeroTime(m->timenow); 4459 } 4460} 4461 4462// Caller must hold the lock 4463mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info) 4464{ 4465 mStatus err; 4466 mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result; 4467 4468 mDNS_CheckLock(m); 4469 4470 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem)) 4471 { 4472 LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)", 4473 info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState); 4474 DeregisterAutoTunnelHostRecord(m, info); 4475 } 4476 else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered) 4477 { 4478 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, 4479 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info); 4480 info->AutoTunnelHostRecord.namestorage.c[0] = 0; 4481 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel); 4482 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain); 4483 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress; 4484 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique; 4485 4486 err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord); 4487 if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c); 4488 else 4489 { 4490 // Make sure we trigger the registration of all SRV records in regState_NoTarget again 4491 m->NextSRVUpdate = NonZeroTime(m->timenow); 4492 LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c); 4493 } 4494 } 4495 else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType); 4496} 4497 4498// Caller must hold the lock 4499mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info) 4500{ 4501 LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c); 4502 4503 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget); 4504 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService); 4505 UpdateAutoTunnelHostRecord(m, info); 4506} 4507 4508// Caller must hold the lock 4509mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info) 4510{ 4511 mDNS_CheckLock(m); 4512 4513 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result) 4514 { 4515 LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result); 4516 DeregisterAutoTunnelServiceRecords(m, info); 4517 } 4518 else 4519 { 4520 if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered) 4521 { 4522 // 1. Set up our address record for the external tunnel address 4523 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record) 4524 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, 4525 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info); 4526 AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel"); 4527 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel); 4528 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain); 4529 info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress; 4530 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique; 4531 4532 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget); 4533 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c); 4534 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c); 4535 } 4536 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType); 4537 4538 if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered) 4539 { 4540 // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget 4541 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, 4542 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info); 4543 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp"); 4544 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel); 4545 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain); 4546 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0; 4547 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0; 4548 info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort; 4549 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage); 4550 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique; 4551 4552 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService); 4553 if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c); 4554 else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c); 4555 } 4556 else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType); 4557 4558 UpdateAutoTunnelHostRecord(m, info); 4559 4560 LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]", 4561 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort), 4562 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress); 4563 4564 } 4565} 4566 4567// Caller must hold the lock 4568mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info) 4569{ 4570 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo); 4571} 4572 4573// Caller must hold the lock 4574mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info) 4575{ 4576 mDNS_CheckLock(m); 4577 4578 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime) 4579 DeregisterAutoTunnelDeviceInfoRecord(m, info); 4580 else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered) 4581 { 4582 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info); 4583 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain); 4584 4585 info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data); 4586 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique; 4587 4588 mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo); 4589 if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c); 4590 else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c); 4591 } 4592 else 4593 LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType); 4594} 4595 4596// Caller must hold the lock 4597mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info) 4598{ 4599 LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c); 4600 4601 DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record); 4602 UpdateAutoTunnelHostRecord(m, info); 4603 UpdateAutoTunnelDomainStatus(m, info); 4604} 4605 4606// Caller must hold the lock 4607mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info) 4608{ 4609 mDNS_CheckLock(m); 4610 4611 if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake) 4612 DeregisterAutoTunnel6Record(m, info); 4613 else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered) 4614 { 4615 mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, 4616 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info); 4617 AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6"); 4618 AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel); 4619 AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain); 4620 info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr; 4621 info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique; 4622 4623 mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record); 4624 if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c); 4625 else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c); 4626 4627 UpdateAutoTunnelHostRecord(m, info); 4628 4629 LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]", 4630 info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr, 4631 info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress); 4632 4633 } 4634 else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType); 4635} 4636 4637mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 4638{ 4639 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext; 4640 if (result == mStatus_MemFree) 4641 { 4642 LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr)); 4643 4644 mDNS_Lock(m); 4645 4646 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister 4647 if (rr == &info->AutoTunnelHostRecord) 4648 { 4649 rr->namestorage.c[0] = 0; 4650 m->NextSRVUpdate = NonZeroTime(m->timenow); 4651 LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); 4652 } 4653 if (m->ShutdownTime) 4654 { 4655 LogInfo("AutoTunnelRecordCallback: Shutdown, returning"); 4656 mDNS_Unlock(m); 4657 return; 4658 } 4659 if (rr == &info->AutoTunnelHostRecord) 4660 { 4661 LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord"); 4662 UpdateAutoTunnelHostRecord(m,info); 4663 } 4664 else if (rr == &info->AutoTunnelDeviceInfo) 4665 { 4666 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord"); 4667 UpdateAutoTunnelDeviceInfoRecord(m,info); 4668 } 4669 else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget) 4670 { 4671 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords"); 4672 UpdateAutoTunnelServiceRecords(m,info); 4673 } 4674 else if (rr == &info->AutoTunnel6Record) 4675 { 4676 LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record"); 4677 UpdateAutoTunnel6Record(m,info); 4678 } 4679 4680 mDNS_Unlock(m); 4681 } 4682} 4683 4684mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n) 4685{ 4686 DomainAuthInfo *info; 4687 4688 LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d", 4689 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort)); 4690 4691 mDNS_Lock(m); 4692 4693 m->NextSRVUpdate = NonZeroTime(m->timenow); 4694 LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow); 4695 4696 for (info = m->AuthInfoList; info; info = info->next) 4697 if (info->AutoTunnel) 4698 UpdateAutoTunnelServiceRecords(m, info); 4699 4700 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections 4701 4702 UpdateAutoTunnelDomainStatuses(m); 4703 4704 mDNS_Unlock(m); 4705} 4706 4707mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info) 4708{ 4709 LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c); 4710 4711 mDNS_Lock(m); 4712 // We forcibly deregister the records that are based on the hostname. 4713 // When deregistration of each completes, the MemFree callback will make the 4714 // appropriate Update* call to use the new name to reregister. 4715 DeregisterAutoTunnelHostRecord(m, info); 4716 DeregisterAutoTunnelDeviceInfoRecord(m, info); 4717 DeregisterAutoTunnelServiceRecords(m, info); 4718 DeregisterAutoTunnel6Record(m, info); 4719 m->NextSRVUpdate = NonZeroTime(m->timenow); 4720 mDNS_Unlock(m); 4721} 4722 4723// Must be called with the lock held 4724mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info) 4725{ 4726 if (info->deltime) return; 4727 4728 if (info->AutoTunnelServiceStarted) 4729 { 4730 // On wake from sleep, this function will be called when determining SRV targets, 4731 // and needs to re-register the host record for the target to be set correctly 4732 UpdateAutoTunnelHostRecord(m, info); 4733 return; 4734 } 4735 4736 info->AutoTunnelServiceStarted = mDNStrue; 4737 4738 // Now that we have a service in this domain, we need to try to register the 4739 // AutoTunnel records, because the relay connection & NAT-T may have already been 4740 // started for another domain. If the relay connection is not up or the NAT-T has not 4741 // yet succeeded, the Update* functions are smart enough to not register the records. 4742 // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to 4743 // decide whether to register the AutoTunnel records in the calls below. 4744 UpdateAutoTunnelServiceRecords(m, info); 4745 UpdateAutoTunnel6Record(m, info); 4746 UpdateAutoTunnelDeviceInfoRecord(m, info); 4747 UpdateAutoTunnelHostRecord(m, info); 4748 4749 // If the global AutoTunnel NAT-T is not yet started, start it. 4750 if (!m->AutoTunnelNAT.clientContext) 4751 { 4752 m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback; 4753 m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active; 4754 m->AutoTunnelNAT.Protocol = NATOp_MapUDP; 4755 m->AutoTunnelNAT.IntPort = IPSECPort; 4756 m->AutoTunnelNAT.RequestedPort = IPSECPort; 4757 m->AutoTunnelNAT.NATLease = 0; 4758 mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT); 4759 if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err); 4760 } 4761} 4762 4763mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew) 4764{ 4765 mDNSv6Addr loc_outer6; 4766 mDNSv6Addr rmt_outer6; 4767 4768 // When we are tunneling over IPv6 Relay address, the port number is zero 4769 if (mDNSIPPortIsZero(tun->rmt_outer_port)) 4770 { 4771 loc_outer6 = tun->loc_outer6; 4772 rmt_outer6 = tun->rmt_outer6; 4773 } 4774 else 4775 { 4776 loc_outer6 = zerov6Addr; 4777 loc_outer6.b[0] = tun->loc_outer.b[0]; 4778 loc_outer6.b[1] = tun->loc_outer.b[1]; 4779 loc_outer6.b[2] = tun->loc_outer.b[2]; 4780 loc_outer6.b[3] = tun->loc_outer.b[3]; 4781 4782 rmt_outer6 = zerov6Addr; 4783 rmt_outer6.b[0] = tun->rmt_outer.b[0]; 4784 rmt_outer6.b[1] = tun->rmt_outer.b[1]; 4785 rmt_outer6.b[2] = tun->rmt_outer.b[2]; 4786 rmt_outer6.b[3] = tun->rmt_outer.b[3]; 4787 } 4788 4789 return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1))); 4790} 4791 4792// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine 4793#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3]) 4794 4795mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype) 4796{ 4797 DNSQuestion *q = m->Questions; 4798 while (q) 4799 { 4800 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d)) 4801 { 4802 LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4803 mDNSQuestionCallback *tmp = q->QuestionCallback; 4804 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel 4805 mDNS_StopQuery(m, q); 4806 mDNS_StartQuery(m, q); 4807 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value 4808 if (!success) q->NoAnswer = NoAnswer_Fail; 4809 // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too. 4810 // In general we have to assume that the question list might have changed in arbitrary ways. 4811 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is 4812 // already in use. The safest solution is just to go back to the start of the list and start again. 4813 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate 4814 // just one suspended question, so it's really a 2n algorithm. 4815 q = m->Questions; 4816 } 4817 else 4818 q = q->next; 4819 } 4820} 4821 4822mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success) 4823{ 4824 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has 4825 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN. 4826 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller -- 4827 // 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. 4828 // 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. 4829 ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA); 4830 ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A); 4831} 4832 4833mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success) 4834{ 4835 ClientTunnel **p = &m->TunnelClients; 4836 while (*p != tun && *p) p = &(*p)->next; 4837 if (*p) *p = tun->next; 4838 ReissueBlockedQuestions(m, &tun->dstname, success); 4839 LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun); 4840 freeL("ClientTunnel", tun); 4841} 4842 4843mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel) 4844{ 4845 ClientTunnel **p; 4846 mDNSBool needSetKeys = mDNStrue; 4847 4848 p = &tun->next; 4849 while (*p) 4850 { 4851 // Is this a tunnel to the same host that we are trying to setup now? 4852 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next; 4853 else 4854 { 4855 ClientTunnel *old = *p; 4856 if (v6Tunnel) 4857 { 4858 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; } 4859 LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4860 if (old->q.ThisQInterval >= 0) 4861 { 4862 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4863 mDNS_StopQuery(m, &old->q); 4864 } 4865 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) || 4866 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) || 4867 !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) || 4868 !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6)) 4869 { 4870 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or 4871 // the other parameters of the tunnel are different 4872 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4873 AutoTunnelSetKeys(old, mDNSfalse); 4874 } 4875 else 4876 { 4877 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old 4878 // as "tun" and "old" are identical 4879 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, 4880 &old->rmt_inner); 4881 needSetKeys = mDNSfalse; 4882 } 4883 } 4884 else 4885 { 4886 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; } 4887 LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4888 if (old->q.ThisQInterval >= 0) 4889 { 4890 LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4891 mDNS_StopQuery(m, &old->q); 4892 } 4893 else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) || 4894 !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) || 4895 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) || 4896 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) || 4897 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port)) 4898 { 4899 // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or 4900 // the other parameters of the tunnel are different 4901 LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4902 AutoTunnelSetKeys(old, mDNSfalse); 4903 } 4904 else 4905 { 4906 // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old 4907 // as "tun" and "old" are identical 4908 LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, 4909 &old->rmt_inner); 4910 needSetKeys = mDNSfalse; 4911 } 4912 } 4913 4914 *p = old->next; 4915 LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old); 4916 freeL("ClientTunnel", old); 4917 } 4918 } 4919 return needSetKeys; 4920} 4921 4922// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4 4923// tunnel will be deleted 4924mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel) 4925{ 4926 ClientTunnel **p; 4927 4928 p = &tun->next; 4929 while (*p) 4930 { 4931 // If there is more than one client tunnel to the same host, delete all of them. 4932 // We do this by just checking against the EUI64 rather than the full address 4933 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next; 4934 else 4935 { 4936 ClientTunnel *old = *p; 4937 if (v6Tunnel) 4938 { 4939 if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;} 4940 LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4941 } 4942 else 4943 { 4944 if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;} 4945 LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4946 } 4947 if (old->q.ThisQInterval >= 0) 4948 { 4949 LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4950 mDNS_StopQuery(m, &old->q); 4951 } 4952 else 4953 { 4954 LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner); 4955 AutoTunnelSetKeys(old, mDNSfalse); 4956 } 4957 *p = old->next; 4958 LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old); 4959 freeL("ClientTunnel", old); 4960 } 4961 } 4962} 4963 4964mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer) 4965{ 4966 mDNSBool needSetKeys = mDNStrue; 4967 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext; 4968 mDNSBool v6Tunnel = mDNSfalse; 4969 DomainAuthInfo *info; 4970 4971 // If the port is zero, then we have a relay address of the peer 4972 if (mDNSIPPortIsZero(tun->rmt_outer_port)) 4973 v6Tunnel = mDNStrue; 4974 4975 if (v6Tunnel) 4976 { 4977 LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6); 4978 tun->rmt_outer6 = answer->rdata->u.ipv6; 4979 tun->loc_outer6 = m->AutoTunnelRelayAddr; 4980 } 4981 else 4982 { 4983 LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4); 4984 tun->rmt_outer = answer->rdata->u.ipv4; 4985 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} }; 4986 tmpDst.ip.v4 = tun->rmt_outer; 4987 mDNSAddr tmpSrc = zeroAddr; 4988 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst); 4989 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4; 4990 else tun->loc_outer = m->AdvertisedV4.ip.v4; 4991 } 4992 4993 question->ThisQInterval = -1; // So we know this tunnel setup has completed 4994 4995 info = GetAuthInfoForName(m, &tun->dstname); 4996 if (!info) 4997 { 4998 LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c); 4999 ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse); 5000 return; 5001 } 5002 5003 tun->loc_inner = info->AutoTunnelInnerAddress; 5004 5005 // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and 5006 // look for existing tunnels to see whether they have the same information for our peer. 5007 // If not, delete them and need to create a new tunnel. If they are same, just use the 5008 // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer. 5009 TunnelClientDeleteAny(m, tun, !v6Tunnel); 5010 needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel); 5011 5012 if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner); 5013 else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner); 5014 5015 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError; 5016 static char msgbuf[32]; 5017 mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result); 5018 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, ""); 5019 // Kick off any questions that were held pending this tunnel setup 5020 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse); 5021} 5022 5023mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 5024{ 5025 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext; 5026 DomainAuthInfo *info; 5027 5028 LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype); 5029 5030 if (!AddRecord) return; 5031 mDNS_StopQuery(m, question); 5032 5033 // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure. 5034 // The code below will look for _autotunnel._udp SRV record followed by A record 5035 if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength) 5036 { 5037 LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 5038 static char msgbuf[16]; 5039 mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype)); 5040 mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, ""); 5041 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse); 5042 return; 5043 } 5044 5045 switch (tun->tc_state) 5046 { 5047 case TC_STATE_AAAA_PEER: 5048 if (question->qtype != kDNSType_AAAA) 5049 { 5050 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype); 5051 } 5052 info = GetAuthInfoForName(m, &tun->dstname); 5053 if (!info) 5054 { 5055 LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c); 5056 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue); 5057 return; 5058 } 5059 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress)) 5060 { 5061 LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6); 5062 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue); 5063 return; 5064 } 5065 if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress)) 5066 { 5067 LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6); 5068 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue); 5069 return; 5070 } 5071 tun->rmt_inner = answer->rdata->u.ipv6; 5072 LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner); 5073 if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)) 5074 { 5075 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA"); 5076 tun->tc_state = TC_STATE_AAAA_PEER_RELAY; 5077 question->qtype = kDNSType_AAAA; 5078 AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6"); 5079 } 5080 else 5081 { 5082 LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV"); 5083 tun->tc_state = TC_STATE_SRV_PEER; 5084 question->qtype = kDNSType_SRV; 5085 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp"); 5086 } 5087 AppendDomainName(&question->qname, &tun->dstname); 5088 mDNS_StartQuery(m, &tun->q); 5089 return; 5090 case TC_STATE_AAAA_PEER_RELAY: 5091 if (question->qtype != kDNSType_AAAA) 5092 { 5093 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype); 5094 } 5095 // If it failed, look for the SRV record. 5096 if (!answer->rdlength) 5097 { 5098 LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV"); 5099 tun->tc_state = TC_STATE_SRV_PEER; 5100 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp"); 5101 AppendDomainName(&question->qname, &tun->dstname); 5102 question->qtype = kDNSType_SRV; 5103 mDNS_StartQuery(m, &tun->q); 5104 return; 5105 } 5106 TunnelClientFinish(m, question, answer); 5107 return; 5108 case TC_STATE_SRV_PEER: 5109 if (question->qtype != kDNSType_SRV) 5110 { 5111 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype); 5112 } 5113 LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c); 5114 tun->tc_state = TC_STATE_ADDR_PEER; 5115 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target); 5116 tun->rmt_outer_port = answer->rdata->u.srv.port; 5117 question->qtype = kDNSType_A; 5118 mDNS_StartQuery(m, &tun->q); 5119 return; 5120 case TC_STATE_ADDR_PEER: 5121 if (question->qtype != kDNSType_A) 5122 { 5123 LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype); 5124 } 5125 TunnelClientFinish(m, question, answer); 5126 return; 5127 default: 5128 LogMsg("AutoTunnelCallback: Unknown question %p", question); 5129 } 5130} 5131 5132// Must be called with the lock held 5133mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) 5134{ 5135 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel)); 5136 if (!p) return; 5137 AssignDomainName(&p->dstname, &q->qname); 5138 p->MarkedForDeletion = mDNSfalse; 5139 p->loc_inner = zerov6Addr; 5140 p->loc_outer = zerov4Addr; 5141 p->loc_outer6 = zerov6Addr; 5142 p->rmt_inner = zerov6Addr; 5143 p->rmt_outer = zerov4Addr; 5144 p->rmt_outer6 = zerov6Addr; 5145 p->rmt_outer_port = zeroIPPort; 5146 p->tc_state = TC_STATE_AAAA_PEER; 5147 p->next = m->TunnelClients; 5148 m->TunnelClients = p; // We intentionally build list in reverse order 5149 5150 p->q.InterfaceID = mDNSInterface_Any; 5151 p->q.flags = 0; 5152 p->q.Target = zeroAddr; 5153 AssignDomainName(&p->q.qname, &q->qname); 5154 p->q.qtype = kDNSType_AAAA; 5155 p->q.qclass = kDNSClass_IN; 5156 p->q.LongLived = mDNSfalse; 5157 p->q.ExpectUnique = mDNStrue; 5158 p->q.ForceMCast = mDNSfalse; 5159 p->q.ReturnIntermed = mDNStrue; 5160 p->q.SuppressUnusable = mDNSfalse; 5161 p->q.SearchListIndex = 0; 5162 p->q.AppendSearchDomains = 0; 5163 p->q.RetryWithSearchDomains = mDNSfalse; 5164 p->q.TimeoutQuestion = 0; 5165 p->q.WakeOnResolve = 0; 5166 p->q.UseBackgroundTrafficClass = mDNSfalse; 5167 p->q.ValidationRequired = 0; 5168 p->q.ValidatingResponse = 0; 5169 p->q.ProxyQuestion = 0; 5170 p->q.qnameOrig = mDNSNULL; 5171 p->q.AnonInfo = mDNSNULL; 5172 p->q.pid = mDNSPlatformGetPID(); 5173 p->q.QuestionCallback = AutoTunnelCallback; 5174 p->q.QuestionContext = p; 5175 5176 LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : ""); 5177 mDNS_StartQuery_internal(m, &p->q); 5178} 5179 5180#endif // APPLE_OSX_mDNSResponder 5181 5182#if COMPILER_LIKES_PRAGMA_MARK 5183#pragma mark - 5184#pragma mark - Power State & Configuration Change Management 5185#endif 5186 5187mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) 5188{ 5189 mDNSBool foundav4 = mDNSfalse; 5190 mDNSBool foundav6 = mDNSfalse; 5191 struct ifaddrs *ifa = myGetIfAddrs(1); 5192 struct ifaddrs *v4Loopback = NULL; 5193 struct ifaddrs *v6Loopback = NULL; 5194 char defaultname[64]; 5195 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0); 5196 if (InfoSocket < 3 && errno != EAFNOSUPPORT) 5197 LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno)); 5198 5199 while (ifa) 5200 { 5201#if LIST_ALL_INTERFACES 5202 if (ifa->ifa_addr->sa_family == AF_APPLETALK) 5203 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK", 5204 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5205 else if (ifa->ifa_addr->sa_family == AF_LINK) 5206 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK", 5207 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5208 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6) 5209 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)", 5210 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5211 if (!(ifa->ifa_flags & IFF_UP)) 5212 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP", 5213 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5214 if (!(ifa->ifa_flags & IFF_MULTICAST)) 5215 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST", 5216 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5217 if (ifa->ifa_flags & IFF_POINTOPOINT) 5218 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT", 5219 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5220 if (ifa->ifa_flags & IFF_LOOPBACK) 5221 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK", 5222 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family); 5223#endif 5224 5225 if (ifa->ifa_addr->sa_family == AF_LINK) 5226 { 5227 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; 5228 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr)) 5229 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6); 5230 } 5231 5232 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr) 5233 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) 5234 { 5235 if (!ifa->ifa_netmask) 5236 { 5237 mDNSAddr ip; 5238 SetupAddr(&ip, ifa->ifa_addr); 5239 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a", 5240 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip); 5241 } 5242 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that 5243 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet 5244 else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0) 5245 { 5246 mDNSAddr ip; 5247 SetupAddr(&ip, ifa->ifa_addr); 5248 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d", 5249 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family); 5250 } 5251 // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2). 5252 else if ((int)if_nametoindex(ifa->ifa_name) <= 0) 5253 { 5254 LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name)); 5255 } 5256 else 5257 { 5258 // Make sure ifa_netmask->sa_family is set correctly 5259 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet 5260 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; 5261 int ifru_flags6 = 0; 5262 5263 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 5264 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0) 5265 { 5266 struct in6_ifreq ifr6; 5267 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6)); 5268 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name)); 5269 ifr6.ifr_addr = *sin6; 5270 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1) 5271 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6; 5272 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6); 5273 } 5274 5275 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) 5276 { 5277 if (ifa->ifa_flags & IFF_LOOPBACK) 5278 { 5279 if (ifa->ifa_addr->sa_family == AF_INET) 5280 v4Loopback = ifa; 5281 else if (sin6->sin6_addr.s6_addr[0] != 0xFD) 5282 v6Loopback = ifa; 5283 } 5284 else 5285 { 5286 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc); 5287 if (i && MulticastInterface(i) && i->ifinfo.Advertise) 5288 { 5289 if (ifa->ifa_addr->sa_family == AF_INET) 5290 foundav4 = mDNStrue; 5291 else 5292 foundav6 = mDNStrue; 5293 } 5294 } 5295 } 5296 } 5297 } 5298 ifa = ifa->ifa_next; 5299 } 5300 5301 // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising 5302 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc); 5303 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc); 5304 5305 // Now the list is complete, set the McastTxRx setting for each interface. 5306 NetworkInterfaceInfoOSX *i; 5307 for (i = m->p->InterfaceList; i; i = i->next) 5308 if (i->Exists) 5309 { 5310 mDNSBool txrx = MulticastInterface(i); 5311 if (i->ifinfo.McastTxRx != txrx) 5312 { 5313 i->ifinfo.McastTxRx = txrx; 5314 i->Exists = 2; // State change; need to deregister and reregister this interface 5315 } 5316 } 5317 5318 if (InfoSocket >= 0) 5319 close(InfoSocket); 5320 5321 mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring, 5322 m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]); 5323 5324 // Set up the nice label 5325 domainlabel nicelabel; 5326 nicelabel.c[0] = 0; 5327 GetUserSpecifiedFriendlyComputerName(&nicelabel); 5328 if (nicelabel.c[0] == 0) 5329 { 5330 debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname); 5331 MakeDomainLabelFromLiteralString(&nicelabel, defaultname); 5332 } 5333 5334 // Set up the RFC 1034-compliant label 5335 domainlabel hostlabel; 5336 hostlabel.c[0] = 0; 5337 GetUserSpecifiedLocalHostName(&hostlabel); 5338 if (hostlabel.c[0] == 0) 5339 { 5340 debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname); 5341 MakeDomainLabelFromLiteralString(&hostlabel, defaultname); 5342 } 5343 5344 mDNSBool namechange = mDNSfalse; 5345 5346 // We use a case-sensitive comparison here because even though changing the capitalization 5347 // of the name alone is not significant to DNS, it's still a change from the user's point of view 5348 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c)) 5349 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c); 5350 else 5351 { 5352 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot 5353 LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c); 5354 m->p->usernicelabel = m->nicelabel = nicelabel; 5355 namechange = mDNStrue; 5356 } 5357 5358 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c)) 5359 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c); 5360 else 5361 { 5362 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot 5363 LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c); 5364 m->p->userhostlabel = m->hostlabel = hostlabel; 5365 mDNS_SetFQDN(m); 5366 namechange = mDNStrue; 5367 } 5368 5369#if APPLE_OSX_mDNSResponder 5370 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records 5371 { 5372 DomainAuthInfo *info; 5373 for (info = m->AuthInfoList; info; info = info->next) 5374 if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info); 5375 } 5376#endif // APPLE_OSX_mDNSResponder 5377 5378 return(mStatus_NoError); 5379} 5380 5381// Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6 5382// Returns -1 if all the one-bits are not contiguous 5383mDNSlocal int CountMaskBits(mDNSAddr *mask) 5384{ 5385 int i = 0, bits = 0; 5386 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0; 5387 while (i < bytes) 5388 { 5389 mDNSu8 b = mask->ip.v6.b[i++]; 5390 while (b & 0x80) { bits++; b <<= 1; } 5391 if (b) return(-1); 5392 } 5393 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1); 5394 return(bits); 5395} 5396 5397// returns count of non-link local V4 addresses registered 5398mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) 5399{ 5400 NetworkInterfaceInfoOSX *i; 5401 int count = 0; 5402 for (i = m->p->InterfaceList; i; i = i->next) 5403 if (i->Exists) 5404 { 5405 NetworkInterfaceInfo *const n = &i->ifinfo; 5406 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC); 5407 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname); 5408 5409 if (i->Registered && i->Registered != primary) // Sanity check 5410 { 5411 LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary); 5412 i->Registered = mDNSNULL; 5413 } 5414 5415 if (!i->Registered) 5416 { 5417 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface, 5418 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it. 5419 // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it 5420 // 5421 5422 i->Registered = primary; 5423 5424 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away. 5425 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds. 5426 // 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. 5427 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60); 5428 5429 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address 5430 // everytime it creates a new interface. We think it is a duplicate and hence consider it 5431 // as flashing and occulting, that is, flapping. If an interface is marked as flapping, 5432 // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and 5433 // logs a warning message to system.log noting frequent interface transitions. 5434 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface. 5435 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink) 5436 { 5437 LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname, 5438 i->Flashing ? " (Flashing)" : "", 5439 i->Occulting ? " (Occulting)" : ""); 5440 mDNS_RegisterInterface(m, n, 0); 5441 } 5442 else 5443 { 5444 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting); 5445 } 5446 5447 if (!mDNSAddressIsLinkLocal(&n->ip)) count++; 5448 LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s", 5449 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask), 5450 i->Flashing ? " (Flashing)" : "", 5451 i->Occulting ? " (Occulting)" : "", 5452 n->InterfaceActive ? " (Primary)" : ""); 5453 5454 if (!n->McastTxRx) 5455 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); 5456 else 5457 { 5458 if (i->sa_family == AF_INET) 5459 { 5460 struct ip_mreq imr; 5461 primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger; 5462 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; 5463 imr.imr_interface = primary->ifa_v4addr; 5464 5465 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first, 5466 // before trying to join the group, to clear out stale kernel state which may be lingering. 5467 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state 5468 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group 5469 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't 5470 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state. 5471 // Also, trying to make the code leave the group when the adapter is removed doesn't work either, 5472 // because by the time we get the configuration change notification, the interface is already gone, 5473 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address"). 5474 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces 5475 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i) 5476 { 5477 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); 5478 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr)); 5479 if (err < 0 && (errno != EADDRNOTAVAIL)) 5480 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno)); 5481 } 5482 5483 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); 5484 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); 5485 // Joining same group twice can give "Address already in use" error -- no need to report that 5486 if (err < 0 && (errno != EADDRINUSE)) 5487 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface); 5488 } 5489 if (i->sa_family == AF_INET6) 5490 { 5491 struct ipv6_mreq i6mr; 5492 i6mr.ipv6mr_interface = primary->scope_id; 5493 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6; 5494 5495 if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i) 5496 { 5497 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); 5498 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr)); 5499 if (err < 0 && (errno != EADDRNOTAVAIL)) 5500 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); 5501 } 5502 5503 LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); 5504 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); 5505 // Joining same group twice can give "Address already in use" error -- no need to report that 5506 if (err < 0 && (errno != EADDRINUSE)) 5507 LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); 5508 } 5509 } 5510 } 5511 } 5512 5513 return count; 5514} 5515 5516mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc) 5517{ 5518 NetworkInterfaceInfoOSX *i; 5519 for (i = m->p->InterfaceList; i; i = i->next) 5520 { 5521 if (i->Exists) i->LastSeen = utc; 5522 i->Exists = mDNSfalse; 5523 } 5524} 5525 5526// returns count of non-link local V4 addresses deregistered 5527mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) 5528{ 5529 // First pass: 5530 // If an interface is going away, then deregister this from the mDNSCore. 5531 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away. 5532 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory 5533 // it refers to has gone away we'll crash. 5534 NetworkInterfaceInfoOSX *i; 5535 int count = 0; 5536 for (i = m->p->InterfaceList; i; i = i->next) 5537 { 5538 // If this interface is no longer active, or its InterfaceID is changing, deregister it 5539 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC); 5540 if (i->Registered) 5541 if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary) 5542 { 5543 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60); 5544 LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s", 5545 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, 5546 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), 5547 i->Flashing ? " (Flashing)" : "", 5548 i->Occulting ? " (Occulting)" : "", 5549 i->ifinfo.InterfaceActive ? " (Primary)" : ""); 5550 5551 // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address 5552 // everytime it creates a new interface. We think it is a duplicate and hence consider it 5553 // as flashing and occulting. The "core" does not flush the cache for this case. This leads to 5554 // stale data returned to the application even after the interface is removed. The application 5555 // then starts to send data but the new interface is not yet created. 5556 // Same logic applies when IFEF_DIRECTLINK flag is set on the interface. 5557 if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink) 5558 { 5559 LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname, 5560 i->Flashing ? " (Flashing)" : "", 5561 i->Occulting ? " (Occulting)" : ""); 5562 mDNS_DeregisterInterface(m, &i->ifinfo, 0); 5563 } 5564 else 5565 { 5566 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting); 5567 } 5568 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; 5569 i->Registered = mDNSNULL; 5570 // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface, 5571 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it. 5572 // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it. 5573 5574 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this 5575 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely. 5576 } 5577 } 5578 5579 // Second pass: 5580 // Now that everything that's going to deregister has done so, we can clean up and free the memory 5581 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList; 5582 while (*p) 5583 { 5584 i = *p; 5585 // If no longer active, delete interface from list and free memory 5586 if (!i->Exists) 5587 { 5588 if (i->LastSeen == utc) i->LastSeen = utc - 1; 5589 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60); 5590 LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding", 5591 i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, 5592 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen, 5593 i->ifinfo.InterfaceActive ? " (Primary)" : ""); 5594#if APPLE_OSX_mDNSResponder 5595 if (i->BPF_fd >= 0) CloseBPF(i); 5596#endif // APPLE_OSX_mDNSResponder 5597 if (delete) 5598 { 5599 *p = i->next; 5600 freeL("NetworkInterfaceInfoOSX", i); 5601 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop 5602 } 5603 } 5604 p = &i->next; 5605 } 5606 return count; 5607} 5608 5609mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name) 5610{ 5611 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem)); 5612 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted"); 5613 else 5614 { 5615 dnle->next = mDNSNULL; 5616 dnle->uid = uid; 5617 AssignDomainName(&dnle->name, name); 5618 **List = dnle; 5619 *List = &dnle->next; 5620 } 5621} 5622 5623mDNSlocal int compare_dns_configs(const void *aa, const void *bb) 5624{ 5625 dns_resolver_t *a = *(dns_resolver_t**)aa; 5626 dns_resolver_t *b = *(dns_resolver_t**)bb; 5627 5628 return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1; 5629} 5630 5631mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID) 5632{ 5633 char *buf = "."; 5634 mDNSu32 scopeid = 0; 5635 char ifid_buf[16]; 5636 5637 if (domain) 5638 buf = domain; 5639 // 5640 // Hash the search domain name followed by the InterfaceID. 5641 // As we have scoped search domains, we also included InterfaceID. If either of them change, 5642 // we will detect it. Even if the order of them change, we will detect it. 5643 // 5644 // Note: We have to handle a few of these tricky cases. 5645 // 5646 // 1) Current: com, apple.com Changing to: comapple.com 5647 // 2) Current: a.com,b.com Changing to a.comb.com 5648 // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8) 5649 // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2) 5650 // 5651 // There are more variants of the above. The key thing is if we include the null in each case 5652 // at the end of name and the InterfaceID, it will prevent a new name (which can't include 5653 // NULL as part of the name) to be mistakenly thought of as a old name. 5654 5655 scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue); 5656 // mDNS_snprintf always null terminates 5657 if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf)) 5658 LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid); 5659 5660 LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf); 5661 MD5_Update(sdc, buf, strlen(buf) + 1); 5662 MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1); 5663} 5664 5665mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc) 5666{ 5667 mDNSu8 md5_hash[MD5_LEN]; 5668 5669 MD5_Final(md5_hash, sdc); 5670 5671 if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN)) 5672 { 5673 // If the hash is different, either the search domains have changed or 5674 // the ordering between them has changed. Restart the questions that 5675 // would be affected by this. 5676 LogInfo("FinalizeSearchDomains: The hash is different"); 5677 memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN); 5678 RetrySearchDomainQuestions(m); 5679 } 5680 else { LogInfo("FinalizeSearchDomains: The hash is same"); } 5681} 5682 5683mDNSexport const char *DNSScopeToString(mDNSu32 scope) 5684{ 5685 switch (scope) 5686 { 5687 case kScopeNone: 5688 return "Unscoped"; 5689 case kScopeInterfaceID: 5690 return "InterfaceScoped"; 5691 case kScopeServiceID: 5692 return "ServiceScoped"; 5693 default: 5694 return "Unknown"; 5695 } 5696} 5697 5698mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc) 5699{ 5700 const char *scopeString = DNSScopeToString(scope); 5701 int j; 5702 5703 if (scope != kScopeNone) 5704 { 5705 LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface); 5706 return; 5707 } 5708 for (j = 0; j < resolver->n_search; j++) 5709 { 5710 LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]); 5711 UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL); 5712 mDNS_AddSearchDomain_CString(resolver->search[j], NULL); 5713 } 5714} 5715 5716mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex) 5717{ 5718 NetworkInterfaceInfoOSX *ni; 5719 mDNSInterfaceID interface; 5720 5721 for (ni = m->p->InterfaceList; ni; ni = ni->next) 5722 { 5723 if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) 5724 break; 5725 } 5726 if (ni != NULL) 5727 { 5728 interface = ni->ifinfo.InterfaceID; 5729 } 5730 else 5731 { 5732 // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID 5733 // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd 5734 // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers. 5735 // As the caller is going to ack the configuration always, we have to add all the DNS servers 5736 // in the configuration. Otherwise, we won't have any DNS servers up until the network change. 5737 5738 LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex); 5739 5740 // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below 5741 interface = (mDNSInterfaceID)(unsigned long)ifindex; 5742 } 5743 return interface; 5744} 5745 5746mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r) 5747{ 5748 char *opt = r->options; 5749 domainname d; 5750 5751 if (opt && !strncmp(opt, "mdns", strlen(opt))) 5752 { 5753 if (!MakeDomainNameFromDNSNameString(&d, r->domain)) 5754 { 5755 LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain); 5756 return; 5757 } 5758 mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout); 5759 } 5760} 5761 5762mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID) 5763{ 5764 int n; 5765 domainname d; 5766 int serviceID = 0; 5767 mDNSBool cellIntf = mDNSfalse; 5768 mDNSBool scopedDNS = mDNSfalse; 5769 mDNSBool reqA, reqAAAA; 5770 5771 if (!r->domain || !*r->domain) 5772 { 5773 d.c[0] = 0; 5774 } 5775 else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) 5776 { 5777 LogMsg("ConfigDNSServers: bad domain %s", r->domain); 5778 return; 5779 } 5780 // Parse the resolver specific attributes that affects all the DNS servers. 5781 if (scope == kScopeInterfaceID) 5782 { 5783 scopedDNS = mDNStrue; 5784 } 5785 else if (scope == kScopeServiceID) 5786 { 5787 serviceID = r->service_identifier; 5788 } 5789 5790#if TARGET_OS_IPHONE 5791 cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse; 5792#endif 5793 reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse); 5794 reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse); 5795 5796 for (n = 0; n < r->n_nameserver; n++) 5797 { 5798 mDNSAddr saddr; 5799 DNSServer *s; 5800 5801 if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6) 5802 continue; 5803 5804 if (SetupAddr(&saddr, r->nameserver[n])) 5805 { 5806 LogMsg("ConfigDNSServers: Bad address"); 5807 continue; 5808 } 5809 5810 // The timeout value is for all the DNS servers in a given resolver, hence we pass 5811 // the timeout value only for the first DNSServer. If we don't have a value in the 5812 // resolver, then use the core's default value 5813 // 5814 // Note: this assumes that when the core picks a list of DNSServers for a question, 5815 // it takes the sum of all the timeout values for all DNS servers. By doing this, it 5816 // tries all the DNS servers in a specified timeout 5817 s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope, 5818 (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue); 5819 if (s) 5820 { 5821 LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c); 5822 } 5823 } 5824} 5825 5826// ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and 5827// Service scope resolvers. This is indicated by the scope argument. 5828// 5829// "resolver" has entries that should only be used for unscoped questions. 5830// 5831// "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an 5832// interface index (q->InterfaceID) 5833// 5834// "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify 5835// a service identifier (q->ServiceID) 5836// 5837mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID) 5838{ 5839 int i; 5840 dns_resolver_t **resolver; 5841 int nresolvers; 5842 const char *scopeString = DNSScopeToString(scope); 5843 mDNSInterfaceID interface; 5844 5845 switch (scope) 5846 { 5847 case kScopeNone: 5848 resolver = config->resolver; 5849 nresolvers = config->n_resolver; 5850 break; 5851 case kScopeInterfaceID: 5852 resolver = config->scoped_resolver; 5853 nresolvers = config->n_scoped_resolver; 5854 break; 5855 case kScopeServiceID: 5856 resolver = config->service_specific_resolver; 5857 nresolvers = config->n_service_specific_resolver; 5858 break; 5859 default: 5860 return; 5861 } 5862 qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs); 5863 5864 for (i = 0; i < nresolvers; i++) 5865 { 5866 dns_resolver_t *r = resolver[i]; 5867 5868 LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver); 5869 5870 interface = mDNSInterface_Any; 5871 5872 // Parse the interface index 5873 if (r->if_index != 0) 5874 { 5875 interface = ConfigParseInterfaceID(m, r->if_index); 5876 } 5877 5878 if (setsearch) 5879 { 5880 ConfigSearchDomains(m, resolver[i], interface, scope, sdc); 5881 // Parse other scoped resolvers for search lists 5882 if (!setservers) 5883 continue; 5884 } 5885 5886 if (r->port == 5353 || r->n_nameserver == 0) 5887 { 5888 ConfigNonUnicastResolver(m, r); 5889 } 5890 else 5891 { 5892 // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the 5893 // scoped resolver are not used by other non-scoped or scoped resolvers. 5894 if (scope != kScopeNone) 5895 resGroupID++; 5896 5897 ConfigDNSServers(m, r, interface, scope, resGroupID); 5898 } 5899 } 5900} 5901 5902#if APPLE_OSX_mDNSResponder 5903mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q) 5904{ 5905 if (QuerySuppressed(q)) 5906 { 5907 debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 5908 return mDNSfalse; 5909 } 5910 if (mDNSOpaque16IsZero(q->TargetQID)) 5911 { 5912 debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 5913 return mDNSfalse; 5914 } 5915 // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response 5916 // for trigger. 5917 if (q->LOAddressAnswers) 5918 { 5919 debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 5920 return mDNSfalse; 5921 } 5922 return mDNStrue; 5923} 5924#endif 5925 5926// This function is called if we are not delivering unicast answers to "A" or "AAAA" questions. 5927// We set our state appropriately so that if we start receiving answers, trigger the 5928// upper layer to retry DNS questions. 5929#if APPLE_OSX_mDNSResponder 5930mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q) 5931{ 5932 if (!QuestionValidForDNSTrigger(q)) 5933 return; 5934 5935 // Ignore applications that start and stop queries for no reason before we ever talk 5936 // to any DNS server. 5937 if (!q->triedAllServersOnce) 5938 { 5939 LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype)); 5940 return; 5941 } 5942 if (q->qtype == kDNSType_A) 5943 m->p->v4answers = 0; 5944 if (q->qtype == kDNSType_AAAA) 5945 m->p->v6answers = 0; 5946 if (!m->p->v4answers || !m->p->v6answers) 5947 { 5948 LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c, 5949 DNSTypeName(q->qtype)); 5950 } 5951} 5952#endif 5953 5954mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config) 5955{ 5956 mDNS_CheckLock(m); 5957 5958 // Acking the configuration triggers configd to reissue the reachability queries 5959 m->p->DNSTrigger = NonZeroTime(m->timenow); 5960 _dns_configuration_ack(config, "com.apple.mDNSResponder"); 5961} 5962 5963// If v4q is non-NULL, it means we have received some answers for "A" type questions 5964// If v6q is non-NULL, it means we have received some answers for "AAAA" type questions 5965#if APPLE_OSX_mDNSResponder 5966mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q) 5967{ 5968 mDNSBool trigger = mDNSfalse; 5969 mDNSs32 timenow; 5970 5971 // Don't send triggers too often. 5972 // If we have started delivering answers to questions, we should send a trigger 5973 // if the time permits. If we are delivering answers, we should set the state 5974 // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know 5975 // whether the answers that are being delivered currently is for configd or some 5976 // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger, 5977 // then we won't deliver the trigger later when it is okay to send one as the 5978 // "answers" are already set to 1. Hence, don't affect the state of v4answers and 5979 // v6answers if we are not delivering triggers. 5980 mDNS_Lock(m); 5981 timenow = m->timenow; 5982 if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL) 5983 { 5984 if (!m->p->v4answers || !m->p->v6answers) 5985 { 5986 debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d", 5987 (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers); 5988 } 5989 mDNS_Unlock(m); 5990 return; 5991 } 5992 mDNS_Unlock(m); 5993 if (v4q != NULL && QuestionValidForDNSTrigger(v4q)) 5994 { 5995 int old = m->p->v4answers; 5996 5997 m->p->v4answers = 1; 5998 5999 // If there are IPv4 answers now and previously we did not have 6000 // any answers, trigger a DNS change so that reachability 6001 // can retry the queries again. 6002 if (!old) 6003 { 6004 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger), 6005 v4q->qname.c, DNSTypeName(v4q->qtype)); 6006 trigger = mDNStrue; 6007 } 6008 } 6009 if (v6q != NULL && QuestionValidForDNSTrigger(v6q)) 6010 { 6011 int old = m->p->v6answers; 6012 6013 m->p->v6answers = 1; 6014 // If there are IPv6 answers now and previously we did not have 6015 // any answers, trigger a DNS change so that reachability 6016 // can retry the queries again. 6017 if (!old) 6018 { 6019 LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger), 6020 v6q->qname.c, DNSTypeName(v6q->qtype)); 6021 trigger = mDNStrue; 6022 } 6023 } 6024 if (trigger) 6025 { 6026 dns_config_t *config = dns_configuration_copy(); 6027 if (config) 6028 { 6029 mDNS_Lock(m); 6030 AckConfigd(m, config); 6031 mDNS_Unlock(m); 6032 dns_configuration_free(config); 6033 } 6034 else 6035 { 6036 LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config"); 6037 } 6038 } 6039} 6040 6041mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config) 6042{ 6043 // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up 6044 // by someone using Microsoft Active Directory using "local" as a private internal top-level domain 6045 if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver && 6046 config->resolver[0]->nameserver[0]) 6047 { 6048 MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain); 6049 } 6050 else 6051 { 6052 ActiveDirectoryPrimaryDomain.c[0] = 0; 6053 } 6054 6055 //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local"); 6056 ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain); 6057 if (config->n_resolver && config->resolver[0]->n_nameserver && 6058 SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain)) 6059 { 6060 SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]); 6061 } 6062 else 6063 { 6064 AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)""); 6065 ActiveDirectoryPrimaryDomainLabelCount = 0; 6066 ActiveDirectoryPrimaryDomainServer = zeroAddr; 6067 } 6068} 6069#endif 6070 6071mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains) 6072{ 6073 int i; 6074 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL 6075 domainname d; 6076 6077 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL); 6078 if (!store) 6079 { 6080 LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 6081 } 6082 else 6083 { 6084 CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS); 6085 if (ddnsdict) 6086 { 6087 if (fqdn) 6088 { 6089 CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames")); 6090 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0) 6091 { 6092 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list 6093 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); 6094 if (fqdnDict && DictionaryIsEnabled(fqdnDict)) 6095 { 6096 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain")); 6097 if (name) 6098 { 6099 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || 6100 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0]) 6101 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)"); 6102 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf); 6103 } 6104 } 6105 } 6106 } 6107 6108 if (RegDomains) 6109 { 6110 CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains")); 6111 if (regArray && CFArrayGetCount(regArray) > 0) 6112 { 6113 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0); 6114 if (regDict && DictionaryIsEnabled(regDict)) 6115 { 6116 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain")); 6117 if (name) 6118 { 6119 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || 6120 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0]) 6121 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)"); 6122 else 6123 { 6124 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf); 6125 AppendDNameListElem(&RegDomains, 0, &d); 6126 } 6127 } 6128 } 6129 } 6130 } 6131 6132 if (BrowseDomains) 6133 { 6134 CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains")); 6135 if (browseArray) 6136 { 6137 for (i = 0; i < CFArrayGetCount(browseArray); i++) 6138 { 6139 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i); 6140 if (browseDict && DictionaryIsEnabled(browseDict)) 6141 { 6142 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain")); 6143 if (name) 6144 { 6145 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || 6146 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0]) 6147 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)"); 6148 else 6149 { 6150 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf); 6151 AppendDNameListElem(&BrowseDomains, 0, &d); 6152 } 6153 } 6154 } 6155 } 6156 } 6157 } 6158 CFRelease(ddnsdict); 6159 } 6160 6161 if (RegDomains) 6162 { 6163 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac); 6164 if (btmm) 6165 { 6166 CFIndex size = CFDictionaryGetCount(btmm); 6167 const void *key[size]; 6168 const void *val[size]; 6169 CFDictionaryGetKeysAndValues(btmm, key, val); 6170 for (i = 0; i < size; i++) 6171 { 6172 LogInfo("BackToMyMac %d", i); 6173 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8)) 6174 LogMsg("Can't read BackToMyMac %d key %s", i, buf); 6175 else 6176 { 6177 mDNSu32 uid = atoi(buf); 6178 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8)) 6179 LogMsg("Can't read BackToMyMac %d val %s", i, buf); 6180 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0]) 6181 { 6182 LogInfo("BackToMyMac %d %d %##s", i, uid, d.c); 6183 AppendDNameListElem(&RegDomains, uid, &d); 6184 } 6185 } 6186 } 6187 CFRelease(btmm); 6188 } 6189 } 6190 CFRelease(store); 6191 } 6192} 6193 6194// Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change 6195mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, 6196 DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig) 6197{ 6198 MD5_CTX sdc; // search domain context 6199 static mDNSu16 resolverGroupID = 0; 6200 6201 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed 6202 if (fqdn) fqdn->c[0] = 0; 6203 if (RegDomains ) *RegDomains = NULL; 6204 if (BrowseDomains) *BrowseDomains = NULL; 6205 6206 LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s", 6207 setservers ? " setservers" : "", 6208 setsearch ? " setsearch" : "", 6209 fqdn ? " fqdn" : "", 6210 RegDomains ? " RegDomains" : "", 6211 BrowseDomains ? " BrowseDomains" : ""); 6212 6213 if (setsearch) MD5_Init(&sdc); 6214 6215 // Add the inferred address-based configuration discovery domains 6216 // (should really be in core code I think, not platform-specific) 6217 if (setsearch) 6218 { 6219 struct ifaddrs *ifa = mDNSNULL; 6220 struct sockaddr_in saddr; 6221 mDNSPlatformMemZero(&saddr, sizeof(saddr)); 6222 saddr.sin_len = sizeof(saddr); 6223 saddr.sin_family = AF_INET; 6224 saddr.sin_port = 0; 6225 saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4; 6226 6227 // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation 6228 if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1); 6229 6230 while (ifa) 6231 { 6232 mDNSAddr a, n; 6233 char buf[64]; 6234 6235 if (ifa->ifa_addr->sa_family == AF_INET && 6236 ifa->ifa_netmask && 6237 !(ifa->ifa_flags & IFF_LOOPBACK) && 6238 !SetupAddr(&a, ifa->ifa_addr) && 6239 !mDNSv4AddressIsLinkLocal(&a.ip.v4) ) 6240 { 6241 // 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 6242 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet 6243 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly 6244 SetupAddr(&n, ifa->ifa_netmask); 6245 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code 6246 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3], 6247 a.ip.v4.b[2] & n.ip.v4.b[2], 6248 a.ip.v4.b[1] & n.ip.v4.b[1], 6249 a.ip.v4.b[0] & n.ip.v4.b[0]); 6250 UpdateSearchDomainHash(m, &sdc, buf, NULL); 6251 mDNS_AddSearchDomain_CString(buf, mDNSNULL); 6252 } 6253 ifa = ifa->ifa_next; 6254 } 6255 } 6256 6257#ifndef MDNS_NO_DNSINFO 6258 if (setservers || setsearch) 6259 { 6260 dns_config_t *config = dns_configuration_copy(); 6261 if (!config) 6262 { 6263 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed 6264 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail. 6265 // Apparently this is expected behaviour -- "not a bug". 6266 // Accordingly, we suppress syslog messages for the first three minutes after boot. 6267 // If we are still getting failures after three minutes, then we log them. 6268 if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180)) 6269 LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL"); 6270 } 6271 else 6272 { 6273 LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation); 6274 if (m->p->LastConfigGeneration == config->generation) 6275 { 6276 LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation); 6277 dns_configuration_free(config); 6278 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains); 6279 return mDNSfalse; 6280 } 6281#if APPLE_OSX_mDNSResponder 6282 SetupActiveDirectoryDomain(config); 6283#endif 6284 6285 // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry 6286 // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need 6287 // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between 6288 // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the 6289 // same resolverGroupID. 6290 // 6291 // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally. 6292 ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID); 6293 resolverGroupID += config->n_resolver; 6294 6295 ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID); 6296 resolverGroupID += config->n_scoped_resolver; 6297 6298 ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID); 6299 6300 // Acking provides a hint that we processed this current configuration and 6301 // we will use that from now on, assuming we don't get another one immediately 6302 // after we return from here. 6303 if (ackConfig) 6304 { 6305 // Note: We have to set the generation number here when we are acking. 6306 // For every DNS configuration change, we do the following: 6307 // 6308 // 1) Copy dns configuration, handle search domains change 6309 // 2) Copy dns configuration, handle dns server change 6310 // 6311 // If we update the generation number at step (1), we won't process the 6312 // DNS servers the second time because generation number would be the same. 6313 // As we ack only when we process dns servers, we set the generation number 6314 // during acking. 6315 m->p->LastConfigGeneration = config->generation; 6316 LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch); 6317 AckConfigd(m, config); 6318 } 6319 dns_configuration_free(config); 6320 if (setsearch) FinalizeSearchDomainHash(m, &sdc); 6321 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore 6322 setsearch = mDNSfalse; 6323 } 6324 } 6325#endif // MDNS_NO_DNSINFO 6326 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains); 6327 return mDNStrue; 6328} 6329 6330 6331mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r) 6332{ 6333 char buf[256]; 6334 (void)m; // Unused 6335 6336 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL); 6337 if (!store) 6338 LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 6339 else 6340 { 6341 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4); 6342 if (dict) 6343 { 6344 r->type = mDNSAddrType_IPv4; 6345 r->ip.v4 = zerov4Addr; 6346 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); 6347 if (string) 6348 { 6349 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) 6350 LogMsg("Could not convert router to CString"); 6351 else 6352 { 6353 struct sockaddr_in saddr; 6354 saddr.sin_len = sizeof(saddr); 6355 saddr.sin_family = AF_INET; 6356 saddr.sin_port = 0; 6357 inet_aton(buf, &saddr.sin_addr); 6358 6359 *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr; 6360 } 6361 } 6362 6363 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); 6364 if (string) 6365 { 6366 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address? 6367 struct ifaddrs *ifa = myGetIfAddrs(1); 6368 6369 *v4 = *v6 = zeroAddr; 6370 6371 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; } 6372 6373 // find primary interface in list 6374 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6)) 6375 { 6376 mDNSAddr tmp6 = zeroAddr; 6377 if (!strcmp(buf, ifa->ifa_name)) 6378 { 6379 if (ifa->ifa_addr->sa_family == AF_INET) 6380 { 6381 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr); 6382 } 6383 else if (ifa->ifa_addr->sa_family == AF_INET6) 6384 { 6385 SetupAddr(&tmp6, ifa->ifa_addr); 6386 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001 6387 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; } 6388 } 6389 } 6390 else 6391 { 6392 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address 6393 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0]) 6394 { 6395 SetupAddr(&tmp6, ifa->ifa_addr); 6396 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6; 6397 } 6398 } 6399 ifa = ifa->ifa_next; 6400 } 6401 6402 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use 6403 // V4 to communicate w/ our DNS server 6404 } 6405 6406exit: 6407 CFRelease(dict); 6408 } 6409 CFRelease(store); 6410 } 6411 return mStatus_NoError; 6412} 6413 6414mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status) 6415{ 6416 LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c); 6417 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL 6418 ConvertDomainNameToCString(dname, uname); 6419 6420 char *p = uname; 6421 while (*p) 6422 { 6423 *p = tolower(*p); 6424 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot 6425 p++; 6426 } 6427 6428 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity. 6429 // That single entity is a CFDictionary with name "HostNames". 6430 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN 6431 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN. 6432 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.) 6433 // The CFDictionary for each FQDN holds (at present) a single name/value pair, 6434 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success). 6435 6436 const CFStringRef StateKeys [1] = { CFSTR("HostNames") }; 6437 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) }; 6438 const CFStringRef StatusKeys[1] = { CFSTR("Status") }; 6439 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname); 6440 else 6441 { 6442 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) }; 6443 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status); 6444 else 6445 { 6446 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) }; 6447 if (HostVals[0]) 6448 { 6449 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) }; 6450 if (StateVals[0]) 6451 { 6452 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 6453 if (StateDict) 6454 { 6455 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict); 6456 CFRelease(StateDict); 6457 } 6458 CFRelease(StateVals[0]); 6459 } 6460 CFRelease(HostVals[0]); 6461 } 6462 CFRelease(StatusVals[0]); 6463 } 6464 CFRelease(HostKeys[0]); 6465 } 6466} 6467 6468#if APPLE_OSX_mDNSResponder 6469#if !NO_AWACS 6470 6471// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the 6472// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will 6473// help catch it 6474mDNSlocal mDNSBool IsBTMMDomain(domainname *d) 6475{ 6476 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL); 6477 if (!store) 6478 { 6479 LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 6480 return mDNSfalse; 6481 } 6482 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac); 6483 if (btmm) 6484 { 6485 CFIndex size = CFDictionaryGetCount(btmm); 6486 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL 6487 const void *key[size]; 6488 const void *val[size]; 6489 domainname dom; 6490 int i; 6491 CFDictionaryGetKeysAndValues(btmm, key, val); 6492 for (i = 0; i < size; i++) 6493 { 6494 LogInfo("BackToMyMac %d", i); 6495 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8)) 6496 LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf); 6497 else 6498 { 6499 mDNSu32 uid = atoi(buf); 6500 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8)) 6501 LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf); 6502 else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0]) 6503 { 6504 if (SameDomainName(&dom, d)) 6505 { 6506 LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid); 6507 CFRelease(btmm); 6508 CFRelease(store); 6509 return mDNStrue; 6510 } 6511 } 6512 } 6513 } 6514 CFRelease(btmm); 6515 } 6516 CFRelease(store); 6517 LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c); 6518 return mDNSfalse; 6519} 6520 6521// Appends data to the buffer 6522mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen) 6523{ 6524 int len; 6525 6526 len = strlcpy(buf + *currlen, data, bufsz - *currlen); 6527 if (len >= (bufsz - *currlen)) 6528 { 6529 // if we have exceeded the space in buf, it has already been NULL terminated 6530 // and we have nothing more to do. Set currlen to the last byte so that the caller 6531 // knows to do the right thing 6532 LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len); 6533 *currlen = bufsz - 1; 6534 return -1; 6535 } 6536 else { (*currlen) += len; } 6537 6538 buf[*currlen] = ','; 6539 if (*currlen >= bufsz) 6540 { 6541 LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen); 6542 *currlen = bufsz - 1; 6543 buf[*currlen] = 0; 6544 return -1; 6545 } 6546 // if we have filled up the buffer exactly, then there is no more work to do 6547 if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; } 6548 (*currlen)++; 6549 return *currlen; 6550} 6551 6552// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no 6553// BTMM domains, then bring down the connection to the relay. 6554mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) 6555{ 6556 DomainAuthInfo *BTMMDomain = mDNSNULL; 6557 DomainAuthInfo *FoundInList; 6558 static mDNSBool AWACSDConnected = mDNSfalse; 6559 char AllUsers[1024]; // maximum size of mach message 6560 char AllPass[1024]; // maximum size of mach message 6561 char username[MAX_DOMAIN_LABEL + 1]; 6562 int currulen = 0; 6563 int currplen = 0; 6564 6565 // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now, 6566 // we may not be able to send the dns queries over the relay connection which may be needed 6567 // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we 6568 // need to make sure that we send the disconnect before attempting the next connect as the 6569 // awacs connections are redirected based on usernames. 6570 // 6571 // For now we send a disconnect immediately. When we start sending dns queries over the relay 6572 // connection, we will need to fix this. 6573 6574 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next) 6575 if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain)) 6576 { 6577 // We need the passwd from the first domain. 6578 BTMMDomain = FoundInList; 6579 ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username); 6580 LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c); 6581 if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break; 6582 if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break; 6583 } 6584 6585 if (BTMMDomain) 6586 { 6587 // In the normal case (where we neither exceed the buffer size nor write bytes that 6588 // fit exactly into the buffer), currulen/currplen should be a different size than 6589 // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte. 6590 6591 if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0; 6592 if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0; 6593 6594 LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers); 6595 AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com"); 6596 AWACSDConnected = mDNStrue; 6597 } 6598 else 6599 { 6600 // Disconnect only if we connected previously 6601 if (AWACSDConnected) 6602 { 6603 LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect"); 6604 AWACS_Disconnect(); 6605 AWACSDConnected = mDNSfalse; 6606 } 6607 else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect"); 6608 } 6609} 6610#else 6611mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m) 6612{ 6613 (void) m; // Unused 6614 LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library"); 6615} 6616#endif // ! NO_AWACS 6617 6618mDNSlocal void ProcessConndConfigChanges(mDNS *const m); 6619 6620#endif // APPLE_OSX_mDNSResponder 6621 6622// MUST be called holding the lock 6623mDNSexport void SetDomainSecrets(mDNS *m) 6624{ 6625#ifdef NO_SECURITYFRAMEWORK 6626 (void) m; 6627 LogMsg("Note: SetDomainSecrets: no keychain support"); 6628#else 6629 mDNSBool haveAutoTunnels = mDNSfalse; 6630 6631 LogInfo("SetDomainSecrets"); 6632 6633 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds. 6634 // In the case where the user simultaneously removes their DDNS host name and the key 6635 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the 6636 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned 6637 // address records behind that we no longer have permission to delete. 6638 DomainAuthInfo *ptr; 6639 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next) 6640 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10); 6641 6642#if APPLE_OSX_mDNSResponder 6643 { 6644 // Mark all TunnelClients for deletion 6645 ClientTunnel *client; 6646 for (client = m->TunnelClients; client; client = client->next) 6647 { 6648 LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c); 6649 client->MarkedForDeletion = mDNStrue; 6650 } 6651 } 6652#endif // APPLE_OSX_mDNSResponder 6653 6654 // String Array used to write list of private domains to Dynamic Store 6655 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 6656 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; } 6657 CFIndex i; 6658 CFDataRef data = NULL; 6659 const int itemsPerEntry = 4; // domain name, key name, key value, Name value 6660 CFArrayRef secrets = NULL; 6661 int err = mDNSKeychainGetSecrets(&secrets); 6662 if (err || !secrets) 6663 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets); 6664 else 6665 { 6666 CFIndex ArrayCount = CFArrayGetCount(secrets); 6667 // Iterate through the secrets 6668 for (i = 0; i < ArrayCount; ++i) 6669 { 6670 mDNSBool AutoTunnel; 6671 int j, offset; 6672 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i); 6673 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry)) 6674 { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; } 6675 for (j = 0; j < CFArrayGetCount(entry); ++j) 6676 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j))) 6677 { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; } 6678 6679 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness 6680 6681 // Max legal domainname as C-string, including space for btmmprefix and terminating NUL 6682 // Get DNS domain this key is for (kmDNSKcWhere) 6683 char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)]; 6684 data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere); 6685 if (CFDataGetLength(data) >= (int)sizeof(stringbuf)) 6686 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; } 6687 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf); 6688 stringbuf[CFDataGetLength(data)] = '\0'; 6689 6690 AutoTunnel = mDNSfalse; 6691 offset = 0; 6692 if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix))) 6693 offset = strlen(dnsprefix); 6694 else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix))) 6695 { 6696 AutoTunnel = mDNStrue; 6697 offset = strlen(btmmprefix); 6698 } 6699 domainname domain; 6700 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; } 6701 6702 // Get key name (kmDNSKcAccount) 6703 data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount); 6704 if (CFDataGetLength(data) >= (int)sizeof(stringbuf)) 6705 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; } 6706 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf); 6707 stringbuf[CFDataGetLength(data)] = '\0'; 6708 6709 domainname keyname; 6710 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; } 6711 6712 // Get key data (kmDNSKcKey) 6713 data = CFArrayGetValueAtIndex(entry, kmDNSKcKey); 6714 if (CFDataGetLength(data) >= (int)sizeof(stringbuf)) 6715 { 6716 LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); 6717 continue; 6718 } 6719 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf); 6720 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key 6721 6722 // Get the Name of the keychain entry (kmDNSKcName) host or host:port 6723 // The hostname also has the port number and ":". It should take a maximum of 6 bytes. 6724 char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL 6725 data = CFArrayGetValueAtIndex(entry, kmDNSKcName); 6726 if (CFDataGetLength(data) >= (int)sizeof(hostbuf)) 6727 { 6728 LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data)); 6729 continue; 6730 } 6731 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf); 6732 hostbuf[CFDataGetLength(data)] = '\0'; 6733 6734 domainname hostname; 6735 mDNSIPPort port; 6736 char *hptr; 6737 hptr = strchr(hostbuf, ':'); 6738 6739 port.NotAnInteger = 0; 6740 if (hptr) 6741 { 6742 mDNSu8 *p; 6743 mDNSu16 val = 0; 6744 6745 *hptr++ = '\0'; 6746 while(hptr && *hptr != 0) 6747 { 6748 if (*hptr < '0' || *hptr > '9') 6749 { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;} 6750 val = val * 10 + *hptr - '0'; 6751 hptr++; 6752 } 6753 if (!val) continue; 6754 p = (mDNSu8 *)&val; 6755 port.NotAnInteger = p[0] << 8 | p[1]; 6756 } 6757 // The hostbuf is of the format dsid@hostname:port. We don't care about the dsid. 6758 hptr = strchr(hostbuf, '@'); 6759 if (hptr) 6760 hptr++; 6761 else 6762 hptr = hostbuf; 6763 if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; } 6764 6765 DomainAuthInfo *FoundInList; 6766 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next) 6767 if (SameDomainName(&FoundInList->domain, &domain)) break; 6768 6769#if APPLE_OSX_mDNSResponder 6770 if (FoundInList) 6771 { 6772 // If any client tunnel destination is in this domain, set deletion flag to false 6773 ClientTunnel *client; 6774 for (client = m->TunnelClients; client; client = client->next) 6775 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname)) 6776 { 6777 LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c); 6778 client->MarkedForDeletion = mDNSfalse; 6779 } 6780 } 6781 6782#endif // APPLE_OSX_mDNSResponder 6783 6784 // Uncomment the line below to view the keys as they're read out of the system keychain 6785 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE! 6786 //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])); 6787 LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1])); 6788 6789 // If didn't find desired domain in the list, make a new entry 6790 ptr = FoundInList; 6791 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue; 6792 if (!FoundInList) 6793 { 6794 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr)); 6795 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; } 6796 } 6797 6798 //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain); 6799 6800 // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain 6801 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr) 6802 { 6803 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately 6804 continue; 6805 } 6806 6807 ConvertDomainNameToCString(&domain, stringbuf); 6808 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8); 6809 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); } 6810 } 6811 CFRelease(secrets); 6812 } 6813 6814 if (!privateDnsArray || !CFEqual(privateDnsArray, sa)) 6815 { 6816 if (privateDnsArray) 6817 CFRelease(privateDnsArray); 6818 6819 privateDnsArray = sa; 6820 CFRetain(privateDnsArray); 6821 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray); 6822 } 6823 CFRelease(sa); 6824 6825#if APPLE_OSX_mDNSResponder 6826 { 6827 // clean up ClientTunnels 6828 ClientTunnel **pp = &m->TunnelClients; 6829 while (*pp) 6830 { 6831 if ((*pp)->MarkedForDeletion) 6832 { 6833 ClientTunnel *cur = *pp; 6834 LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c); 6835 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); 6836 AutoTunnelSetKeys(cur, mDNSfalse); 6837 *pp = cur->next; 6838 freeL("ClientTunnel", cur); 6839 } 6840 else 6841 pp = &(*pp)->next; 6842 } 6843 6844 mDNSBool needAutoTunnelNAT = mDNSfalse; 6845 DomainAuthInfo *info; 6846 for (info = m->AuthInfoList; info; info = info->next) 6847 { 6848 if (info->AutoTunnel) 6849 { 6850 UpdateAutoTunnelDeviceInfoRecord(m, info); 6851 UpdateAutoTunnelHostRecord(m, info); 6852 UpdateAutoTunnelServiceRecords(m, info); 6853 UpdateAutoTunnel6Record(m, info); 6854 if (info->deltime) 6855 { 6856 if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse; 6857 } 6858 else if (info->AutoTunnelServiceStarted) 6859 needAutoTunnelNAT = true; 6860 6861 UpdateAutoTunnelDomainStatus(m, info); 6862 } 6863 } 6864 6865 // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it 6866 if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext) 6867 { 6868 // stop the NAT operation, reset port, cleanup state 6869 mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT); 6870 m->AutoTunnelNAT.ExternalAddress = zerov4Addr; 6871 m->AutoTunnelNAT.NewAddress = zerov4Addr; 6872 m->AutoTunnelNAT.ExternalPort = zeroIPPort; 6873 m->AutoTunnelNAT.RequestedPort = zeroIPPort; 6874 m->AutoTunnelNAT.Lifetime = 0; 6875 m->AutoTunnelNAT.Result = mStatus_NoError; 6876 m->AutoTunnelNAT.clientContext = mDNSNULL; 6877 } 6878 6879 UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections 6880 ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary 6881 } 6882#endif // APPLE_OSX_mDNSResponder 6883 6884 CheckSuppressUnusableQuestions(m); 6885 6886#endif /* NO_SECURITYFRAMEWORK */ 6887} 6888 6889mDNSlocal void SetLocalDomains(void) 6890{ 6891 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 6892 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; } 6893 6894 CFArrayAppendValue(sa, CFSTR("local")); 6895 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa")); 6896 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa")); 6897 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa")); 6898 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa")); 6899 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa")); 6900 6901 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa); 6902 CFRelease(sa); 6903} 6904 6905mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val) 6906{ 6907#if USE_IOPMCOPYACTIVEPMPREFERENCES 6908 CFTypeRef blob = NULL; 6909 CFStringRef str = NULL; 6910 CFDictionaryRef odict = NULL; 6911 CFDictionaryRef idict = NULL; 6912 CFNumberRef number = NULL; 6913 6914 blob = IOPSCopyPowerSourcesInfo(); 6915 if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; } 6916 6917 odict = IOPMCopyActivePMPreferences(); 6918 if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; } 6919 6920 str = IOPSGetProvidingPowerSourceType(blob); 6921 if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; } 6922 6923 idict = CFDictionaryGetValue(odict, str); 6924 if (!idict) 6925 { 6926 char buf[256]; 6927 if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; 6928 LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf); 6929 goto end; 6930 } 6931 6932 number = CFDictionaryGetValue(idict, name); 6933 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val)) 6934 *val = 0; 6935end: 6936 if (blob) CFRelease(blob); 6937 if (odict) CFRelease(odict); 6938 6939#else 6940 6941 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL); 6942 if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 6943 else 6944 { 6945 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings); 6946 if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict"); 6947 else 6948 { 6949 CFNumberRef number = CFDictionaryGetValue(dict, name); 6950 if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val)) 6951 *val = 0; 6952 CFRelease(dict); 6953 } 6954 CFRelease(store); 6955 } 6956 6957#endif 6958} 6959 6960#if APPLE_OSX_mDNSResponder 6961 6962static CFMutableDictionaryRef spsStatusDict = NULL; 6963static const CFStringRef kMetricRef = CFSTR("Metric"); 6964 6965mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key) 6966{ 6967 mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0'; 6968 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp); 6969 if (!num) 6970 LogMsg("SPSStatusPutNumber: Could not create CFNumber"); 6971 else 6972 { 6973 CFDictionarySetValue(dict, key, num); 6974 CFRelease(num); 6975 } 6976} 6977 6978mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr) 6979{ 6980 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 6981 if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; } 6982 6983 char buffer[1024]; 6984 buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0; 6985 CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 6986 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; } 6987 CFDictionarySetValue(dict, CFSTR("FullName"), spsname); 6988 CFRelease(spsname); 6989 6990 if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type")); 6991 if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability")); 6992 if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower")); 6993 if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower")); 6994 6995 mDNSu32 tmp = SPSMetric(ptr); 6996 CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp); 6997 if (!num) 6998 LogMsg("SPSCreateDict: Could not create CFNumber"); 6999 else 7000 { 7001 CFDictionarySetValue(dict, kMetricRef, num); 7002 CFRelease(num); 7003 } 7004 7005 if (ptr[0] >= 12) 7006 { 7007 memcpy(buffer, ptr + 13, ptr[0] - 12); 7008 buffer[ptr[0] - 12] = 0; 7009 spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 7010 if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; } 7011 else 7012 { 7013 CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname); 7014 CFRelease(spsname); 7015 } 7016 } 7017 7018 return dict; 7019} 7020 7021mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context) 7022{ 7023 (void)context; 7024 return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef), 7025 (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef), 7026 NULL); 7027} 7028 7029mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 7030{ 7031 NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext; 7032 debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>"); 7033 7034 mDNS_Lock(m); 7035 mDNS_UpdateAllowSleep(m); 7036 mDNS_Unlock(m); 7037 7038 if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names 7039 7040 if (!spsStatusDict) 7041 { 7042 spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 7043 if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; } 7044 } 7045 7046 CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8); 7047 if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; } 7048 7049 CFMutableArrayRef array = NULL; 7050 7051 if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array)) 7052 { 7053 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 7054 if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; } 7055 CFDictionarySetValue(spsStatusDict, ifname, array); 7056 CFRelease(array); // let go of our reference, now that the dict has one 7057 } 7058 else 7059 if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; } 7060 7061 if (!answer) // special call that means the question has been stopped (because the interface is going away) 7062 CFArrayRemoveAllValues(array); 7063 else 7064 { 7065 CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c); 7066 if (!dict) { CFRelease(ifname); return; } 7067 7068 if (AddRecord) 7069 { 7070 if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict)) 7071 { 7072 int i=0; 7073 for (i=0; i<CFArrayGetCount(array); i++) 7074 if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan) 7075 break; 7076 CFArrayInsertValueAtIndex(array, i, dict); 7077 } 7078 else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c); 7079 } 7080 else 7081 { 7082 CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict); 7083 if (i != -1) CFArrayRemoveValueAtIndex(array, i); 7084 else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c); 7085 } 7086 7087 CFRelease(dict); 7088 } 7089 7090 if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array); 7091 7092 CFRelease(ifname); 7093} 7094 7095mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void) 7096{ 7097 mDNSs32 val = -1; 7098 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL); 7099 if (!store) 7100 LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 7101 else 7102 { 7103 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings); 7104 if (dict) 7105 { 7106 CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer")); 7107 if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val); 7108 CFRelease(dict); 7109 } 7110 CFRelease(store); 7111 } 7112 return val; 7113} 7114 7115mDNSlocal void SetSPS(mDNS *const m) 7116{ 7117 7118 // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy() 7119 mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0; 7120 7121 // For devices that are not running NAT, but are set to never sleep, we may choose to act 7122 // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg) 7123 //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0; 7124 7125 // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery 7126 7127 // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping, 7128 // it makes sense for them to offer low-priority Sleep Proxy service on the network. 7129 // We rate such a device as metric 70 ("Incidentally Available Hardware") 7130 if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware; 7131 7132 // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the 7133 // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software") 7134 if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService; 7135 7136#ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI 7137 // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active. 7138 if (IsAppleTV()) 7139 { 7140 NetworkInterfaceInfo *intf = mDNSNULL; 7141 mDNSEthAddr bssid = zeroEthAddr; 7142 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 7143 { 7144 bssid = GetBSSID(intf->ifname); 7145 if (!mDNSSameEthAddress(&bssid, &zeroEthAddr)) 7146 { 7147 LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services"); 7148 sps = 0; 7149 break; 7150 } 7151 } 7152 } 7153#endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI 7154 7155 mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures); 7156} 7157 7158// The definitions below should eventually come from some externally-supplied header file. 7159// However, since these definitions can't really be changed without breaking binary compatibility, 7160// they should never change, so in practice it should not be a big problem to have them defined here. 7161 7162enum 7163{ // commands from the daemon to the driver 7164 cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver 7165}; 7166 7167typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr; 7168 7169typedef struct 7170{ // cmd_mDNSOffloadRR structure 7171 uint32_t command; // set to OffloadRR 7172 uint32_t rrBufferSize; // number of bytes of RR records 7173 uint32_t numUDPPorts; // number of SRV UDP ports 7174 uint32_t numTCPPorts; // number of SRV TCP ports 7175 uint32_t numRRRecords; // number of RR records 7176 uint32_t compression; // rrRecords - compression is base for compressed strings 7177 FatPtr rrRecords; // address of array of pointers to the rr records 7178 FatPtr udpPorts; // address of udp port list (SRV) 7179 FatPtr tcpPorts; // address of tcp port list (SRV) 7180} mDNSOffloadCmd; 7181 7182#include <IOKit/IOKitLib.h> 7183#include <dns_util.h> 7184 7185mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray) 7186{ 7187 const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp"; 7188 int count = 0; 7189 AuthRecord *rr; 7190 for (rr = m->ResourceRecords; rr; rr=rr->next) 7191 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c)) 7192 { 7193 if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port; 7194 count++; 7195 } 7196 7197 // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500) 7198 if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext) 7199 { 7200 LogSPS("GetPortArray Back to My Mac at %d", count); 7201 if (portarray) portarray[count] = IPSECPort; 7202 count++; 7203 } 7204 return(count); 7205} 7206 7207#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 7208mDNSlocal mDNSBool SupportsTCPKeepAlive() 7209{ 7210 IOReturn ret = kIOReturnSuccess; 7211 CFTypeRef obj = NULL; 7212 mDNSBool supports = mDNSfalse; 7213 7214 ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj); 7215 if ((kIOReturnSuccess == ret) && (obj != NULL)) 7216 { 7217 supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse; 7218 CFRelease(obj); 7219 } 7220 LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support")); 7221 return supports; 7222} 7223 7224mDNSlocal mDNSBool OnBattery(void) 7225{ 7226 CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo(); 7227 CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo); 7228 mDNSBool result = mDNSfalse; 7229 7230 if (powerInfo != NULL) 7231 { 7232 result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc); 7233 CFRelease(powerInfo); 7234 } 7235 LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power"); 7236 return result; 7237} 7238 7239#endif // !TARGET_OS_EMBEDDED 7240 7241#define TfrRecordToNIC(RR) \ 7242 ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name)))) 7243 7244mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA) 7245{ 7246 *numbytes = 0; 7247 int count = 0; 7248 7249 AuthRecord *rr; 7250 7251 for (rr = m->ResourceRecords; rr; rr=rr->next) 7252 { 7253 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering) 7254 { 7255#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 7256 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec); 7257 // Skip over all other records if we are registering TCP KeepAlive records only 7258 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive. 7259 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA)) 7260 continue; 7261 7262 // Update the record before calculating the number of bytes required 7263 // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will 7264 // attempt to update the record again. 7265 if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError)) 7266 LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr)); 7267#else 7268 (void) TCPKAOnly; // unused 7269 (void) supportsTCPKA; // unused 7270 (void) intf; // unused 7271#endif // APPLE_OSX_mDNSResponder 7272 if (TfrRecordToNIC(rr)) 7273 { 7274 *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate; 7275 LogSPS("CountProxyRecords: %3d size %5d total %5d %s", 7276 count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr)); 7277 count++; 7278 } 7279 } 7280 } 7281 return(count); 7282} 7283 7284mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA) 7285{ 7286 mDNSu8 *p = msg->data; 7287 const mDNSu8 *const limit = p + *numbytes; 7288 InitializeDNSMessage(&msg->h, zeroID, zeroID); 7289 7290 int count = 0; 7291 AuthRecord *rr; 7292 7293 for (rr = m->ResourceRecords; rr; rr=rr->next) 7294 { 7295 if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering) 7296 { 7297#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 7298 mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec); 7299 7300 // Skip over all other records if we are registering TCP KeepAlive records only 7301 // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive 7302 if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA)) 7303 continue; 7304#else 7305 (void) TCPKAOnly; // unused 7306 (void) supportsTCPKA; // unused 7307#endif // APPLE_OSX_mDNSResponder 7308 7309 if (TfrRecordToNIC(rr)) 7310 { 7311 records[count].sixtyfourbits = zeroOpaque64; 7312 records[count].ptr = p; 7313 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 7314 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it 7315 p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); 7316 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state 7317 LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s", 7318 count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr)); 7319 count++; 7320 } 7321 } 7322 } 7323 *numbytes = p - msg->data; 7324} 7325 7326// If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod 7327// then we declare a dummy version here so that the code at least compiles 7328#ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER 7329static kern_return_t 7330IOConnectCallStructMethod( 7331 mach_port_t connection, // In 7332 uint32_t selector, // In 7333 const void *inputStruct, // In 7334 size_t inputStructCnt, // In 7335 void *outputStruct, // Out 7336 size_t *outputStructCnt) // In/Out 7337{ 7338 (void)connection; 7339 (void)selector; 7340 (void)inputStruct; 7341 (void)inputStructCnt; 7342 (void)outputStruct; 7343 (void)outputStructCnt; 7344 LogMsg("Compiled without IOConnectCallStructMethod"); 7345 return(KERN_FAILURE); 7346} 7347#endif 7348 7349mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf) 7350{ 7351 if(!UseInternalSleepProxy) 7352 { 7353 LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled"); 7354 return mDNSfalse; 7355 } 7356 return CheckInterfaceSupport(intf, mDNS_IOREG_KEY); 7357} 7358 7359mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held 7360{ 7361 mStatus result = mStatus_UnknownErr; 7362 mDNSBool TCPKAOnly = mDNSfalse; 7363 mDNSBool supportsTCPKA = mDNSfalse; 7364 mDNSBool onbattery = mDNSfalse; 7365 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname)); 7366 7367#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 7368 onbattery = OnBattery(); 7369 // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records 7370 supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()); 7371 7372 // Only TCP Keepalive records are to be offloaded if 7373 // - The system is on battery 7374 // - OR wake for network access is not set but powernap is enabled 7375 TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery); 7376#else 7377 (void) onbattery; // unused; 7378#endif 7379 if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); } 7380 7381 io_name_t n1, n2; 7382 IOObjectGetClass(service, n1); 7383 io_object_t parent; 7384 kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); 7385 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr); 7386 else 7387 { 7388 IOObjectGetClass(parent, n2); 7389 LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2); 7390 const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL); 7391 if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2); 7392 else 7393 { 7394 if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE))) 7395 LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s", 7396 intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE); 7397 else if (!UseInternalSleepProxy) 7398 LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname); 7399 else 7400 { 7401 io_connect_t conObj; 7402 kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj); 7403 if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr); 7404 else 7405 { 7406 mDNSOffloadCmd cmd; 7407 mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero 7408 cmd.command = cmd_mDNSOffloadRR; 7409 cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL); 7410 cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL); 7411 cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA); 7412 cmd.compression = sizeof(DNSMessageHeader); 7413 7414 DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize); 7415 cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)); 7416 cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort)); 7417 cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort)); 7418 7419 LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", 7420 msg, cmd.rrBufferSize, 7421 cmd.rrRecords.ptr, cmd.numRRRecords, 7422 cmd.udpPorts.ptr, cmd.numUDPPorts, 7423 cmd.tcpPorts.ptr, cmd.numTCPPorts); 7424 7425 if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr) 7426 LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d", 7427 msg, cmd.rrBufferSize, 7428 cmd.rrRecords.ptr, cmd.numRRRecords, 7429 cmd.udpPorts.ptr, cmd.numUDPPorts, 7430 cmd.tcpPorts.ptr, cmd.numTCPPorts); 7431 else 7432 { 7433 GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA); 7434 GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr); 7435 GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr); 7436 char outputData[2]; 7437 size_t outputDataSize = sizeof(outputData); 7438 kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize); 7439 LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr); 7440 if (kr == KERN_SUCCESS) result = mStatus_NoError; 7441 } 7442 7443 if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr); 7444 if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr); 7445 if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr); 7446 if (msg) freeL("mDNSOffloadCmd msg", msg); 7447 IOServiceClose(conObj); 7448 } 7449 } 7450 CFRelease(ref); 7451 } 7452 IOObjectRelease(parent); 7453 } 7454 IOObjectRelease(service); 7455 return result; 7456} 7457 7458#endif // APPLE_OSX_mDNSResponder 7459 7460mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void) 7461{ 7462 mDNSs32 val = 0; 7463 mDNSu8 ret = (mDNSu8)mDNS_NoWake; 7464 7465 if (DisableSleepProxyClient) 7466 { 7467 LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); 7468 return mDNSfalse; 7469 } 7470 7471 GetCurrentPMSetting(CFSTR("Wake On LAN"), &val); 7472 7473 ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake; 7474 7475#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED 7476 // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives. 7477 // Further policy decisions on whether to offload the records is handled during sleep processing. 7478 if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive()) 7479 ret = (mDNSu8)mDNS_WakeOnBattery; 7480#endif // APPLE_OSX_mDNSResponder 7481 7482 LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret); 7483 return ret; 7484} 7485 7486mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void) 7487{ 7488 mDNSs32 val = 0; 7489 GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val); 7490 return val != 0 ? mDNStrue : mDNSfalse; 7491} 7492 7493#if APPLE_OSX_mDNSResponder 7494// When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay) 7495// gets deregistered, so that older peers are forced to connect over direct UDP instead of 7496// the RR relay. 7497// 7498// When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM 7499// service records are deregistered, so they do not appear in peers' Finder sidebars. 7500// We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records 7501// depend on their associated SRV record and therefore will be deregistered together in a 7502// single update with the SRV record. 7503// 7504// Also, the per-zone _kerberos TXT record is always there, including while sleeping, so 7505// its presence shouldn't delay sleep. 7506// 7507// Note that the order of record deregistration is: first _autotunnel6 (if connected to RR 7508// relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT. 7509// 7510// Also note that returning false here will not delay sleep past the maximum of 10 seconds. 7511mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr) 7512{ 7513 if (!AuthRecord_uDNS(rr)) return mDNStrue; 7514 7515 if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6")) 7516 { 7517 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr)); 7518 return mDNSfalse; 7519 } 7520 7521 if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)) 7522 { 7523 if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone 7524 && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel")) 7525 { 7526 DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone); 7527 if (info && info->AutoTunnel) 7528 { 7529 LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr)); 7530 return mDNSfalse; 7531 } 7532 } 7533 } 7534 7535 return mDNStrue; 7536} 7537 7538// Caller must hold the lock 7539mDNSexport void RemoveAutoTunnel6Record(mDNS *const m) 7540{ 7541 DomainAuthInfo *info; 7542 // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will 7543 // deregister the record, and the MemFree callback won't re-register. 7544 m->AutoTunnelRelayAddr = zerov6Addr; 7545 for (info = m->AuthInfoList; info; info = info->next) 7546 if (info->AutoTunnel) 7547 UpdateAutoTunnel6Record(m, info); 7548} 7549 7550mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname) 7551{ 7552 struct ifaddrs *ifa; 7553 struct ifaddrs *ifaddrs; 7554 mDNSAddr addr; 7555 7556 if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;} 7557 7558 if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;} 7559 7560 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) 7561 { 7562 if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0) 7563 continue; 7564 if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6) 7565 continue; 7566 if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError) 7567 { 7568 LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address"); 7569 continue; 7570 } 7571 if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6)) 7572 { 7573 LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr); 7574 break; 7575 } 7576 } 7577 freeifaddrs(ifaddrs); 7578 return ifa != NULL; 7579} 7580 7581mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf) 7582{ 7583 mDNSv6Addr retVal; 7584 struct addrinfo hints; 7585 struct addrinfo *res0; 7586 7587 memset(&hints, 0, sizeof(hints)); 7588 hints.ai_family = AF_INET6; 7589 hints.ai_flags = AI_NUMERICHOST; 7590 7591 int err = getaddrinfo(buf, NULL, &hints, &res0); 7592 if (err) 7593 return zerov6Addr; 7594 7595 retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr; 7596 7597 freeaddrinfo(res0); 7598 7599 return retVal; 7600} 7601 7602mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict() 7603{ 7604 SCDynamicStoreRef store = NULL; 7605 CFDictionaryRef connd = NULL; 7606 CFDictionaryRef BTMMDict = NULL; 7607 7608 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL); 7609 if (!store) 7610 { 7611 LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 7612 goto end; 7613 } 7614 7615 connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity); 7616 if (!connd) 7617 { 7618 LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); 7619 goto end; 7620 } 7621 7622 BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac")); 7623 if (!BTMMDict) 7624 { 7625 LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac"); 7626 goto end; 7627 } 7628 7629 // Non-dictionary is treated as non-existent dictionary 7630 if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID()) 7631 { 7632 BTMMDict = NULL; 7633 LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary"); 7634 goto end; 7635 } 7636 7637 CFRetain(BTMMDict); 7638 7639end: 7640 if (connd) CFRelease(connd); 7641 if (store) CFRelease(store); 7642 7643 return BTMMDict; 7644} 7645 7646#define MAX_IPV6_TEXTUAL 40 7647 7648mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey) 7649{ 7650 mDNSv6Addr retVal = zerov6Addr; 7651 CFTypeRef string = NULL; 7652 char ifname[IFNAMSIZ]; 7653 char address[MAX_IPV6_TEXTUAL]; 7654 7655 if (!BTMMDict) 7656 return zerov6Addr; 7657 7658 if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string)) 7659 { 7660 LogInfo("ParseBackToMyMacAddr: interface key does not exist"); 7661 return zerov6Addr; 7662 } 7663 7664 if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8)) 7665 { 7666 LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString"); 7667 return zerov6Addr; 7668 } 7669 7670 if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string)) 7671 { 7672 LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does"); 7673 return zerov6Addr; 7674 } 7675 7676 if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8)) 7677 { 7678 LogMsg("ParseBackToMyMacAddr: Could not convert address to CString"); 7679 return zerov6Addr; 7680 } 7681 7682 retVal = IPv6AddressFromString(address); 7683 LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal); 7684 7685 if (mDNSIPv6AddressIsZero(retVal)) 7686 return zerov6Addr; 7687 7688 if (!IPv6AddressIsOnInterface(retVal, ifname)) 7689 { 7690 LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname); 7691 return zerov6Addr; 7692 } 7693 7694 return retVal; 7695} 7696 7697mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict) 7698{ 7699 CFTypeRef zones = NULL; 7700 7701 if (!BTMMDict) 7702 return NULL; 7703 7704 if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones)) 7705 { 7706 LogInfo("CopyBTMMZones: Zones key does not exist"); 7707 return NULL; 7708 } 7709 7710 return zones; 7711} 7712 7713mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info) 7714{ 7715 mDNSv6Addr addr = zerov6Addr; 7716 char buffer[MAX_ESCAPED_DOMAIN_NAME]; 7717 CFStringRef domain = NULL; 7718 CFTypeRef theZone = NULL; 7719 7720 if (!zones) 7721 return addr; 7722 7723 ConvertDomainNameToCString(&info->domain, buffer); 7724 domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); 7725 if (!domain) 7726 return addr; 7727 7728 if (CFDictionaryGetValueIfPresent(zones, domain, &theZone)) 7729 addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address")); 7730 7731 CFRelease(domain); 7732 7733 return addr; 7734} 7735 7736mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict) 7737{ 7738 DomainAuthInfo* info; 7739 CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict); 7740 mDNSv6Addr newAddr; 7741 7742 for (info = m->AuthInfoList; info; info = info->next) 7743 { 7744 if (!info->AutoTunnel) 7745 continue; 7746 7747 newAddr = ParseBackToMyMacZone(zones, info); 7748 7749 if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress)) 7750 continue; 7751 7752 info->AutoTunnelInnerAddress = newAddr; 7753 DeregisterAutoTunnelHostRecord(m, info); 7754 UpdateAutoTunnelHostRecord(m, info); 7755 UpdateAutoTunnelDomainStatus(m, info); 7756 } 7757} 7758 7759// MUST be called holding the lock 7760mDNSlocal void ProcessConndConfigChanges(mDNS *const m) 7761{ 7762 CFDictionaryRef dict = CopyConnectivityBackToMyMacDict(); 7763 if (!dict) 7764 LogInfo("ProcessConndConfigChanges: No BTMM dictionary"); 7765 mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress")); 7766 7767 LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr); 7768 7769 SetupBackToMyMacInnerAddresses(m, dict); 7770 7771 if (dict) CFRelease(dict); 7772 7773 if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr)) 7774 { 7775 m->AutoTunnelRelayAddr = relayAddr; 7776 7777 DomainAuthInfo* info; 7778 for (info = m->AuthInfoList; info; info = info->next) 7779 if (info->AutoTunnel) 7780 { 7781 DeregisterAutoTunnel6Record(m, info); 7782 UpdateAutoTunnel6Record(m, info); 7783 UpdateAutoTunnelDomainStatus(m, info); 7784 } 7785 7786 // Determine whether we need racoon to accept incoming connections 7787 UpdateAnonymousRacoonConfig(m); 7788 } 7789 7790 // If awacsd crashes or exits for some reason, restart it 7791 UpdateBTMMRelayConnection(m); 7792} 7793#endif /* APPLE_OSX_mDNSResponder */ 7794 7795mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m) 7796{ 7797 DNSServer *s; 7798 // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr 7799 for (s = m->DNSServers; s; s = s->next) 7800 { 7801 if (s->addr.ip.v4.b[0] == 17) 7802 { 7803 LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr); 7804 return mDNStrue; 7805 } 7806 } 7807 return mDNSfalse; 7808} 7809 7810mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) 7811{ 7812 LogInfo("*** Network Configuration Change *** (%d)%s", 7813 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0, 7814 m->p->NetworkChanged ? "" : " (no scheduled configuration change)"); 7815 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it 7816 mDNSs32 utc = mDNSPlatformUTC(); 7817 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); 7818 m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN(); 7819 MarkAllInterfacesInactive(m, utc); 7820 UpdateInterfaceList(m, utc); 7821 ClearInactiveInterfaces(m, utc); 7822 SetupActiveInterfaces(m, utc); 7823 7824#if APPLE_OSX_mDNSResponder 7825 7826 mDNS_Lock(m); 7827 ProcessConndConfigChanges(m); 7828 mDNS_Unlock(m); 7829 7830 // Scan to find client tunnels whose questions have completed, 7831 // but whose local inner/outer addresses have changed since the tunnel was set up 7832 ClientTunnel *p; 7833 for (p = m->TunnelClients; p; p = p->next) 7834 if (p->q.ThisQInterval < 0) 7835 { 7836 DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname); 7837 if (!info) 7838 { 7839 LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c); 7840 AutoTunnelSetKeys(p, mDNSfalse); 7841 } 7842 else 7843 { 7844 mDNSv6Addr inner = info->AutoTunnelInnerAddress; 7845 7846 if (!mDNSIPPortIsZero(p->rmt_outer_port)) 7847 { 7848 mDNSAddr tmpSrc = zeroAddr; 7849 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} }; 7850 tmpDst.ip.v4 = p->rmt_outer; 7851 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst); 7852 if (!mDNSSameIPv6Address(p->loc_inner, inner) || 7853 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4)) 7854 { 7855 AutoTunnelSetKeys(p, mDNSfalse); 7856 p->loc_inner = inner; 7857 p->loc_outer = tmpSrc.ip.v4; 7858 AutoTunnelSetKeys(p, mDNStrue); 7859 } 7860 } 7861 else 7862 { 7863 if (!mDNSSameIPv6Address(p->loc_inner, inner) || 7864 !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr)) 7865 { 7866 AutoTunnelSetKeys(p, mDNSfalse); 7867 p->loc_inner = inner; 7868 p->loc_outer6 = m->AutoTunnelRelayAddr; 7869 AutoTunnelSetKeys(p, mDNStrue); 7870 } 7871 } 7872 } 7873 } 7874 7875 SetSPS(m); 7876 7877 NetworkInterfaceInfoOSX *i; 7878 for (i = m->p->InterfaceList; i; i = i->next) 7879 { 7880 if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds 7881 { 7882 if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i); 7883 } 7884 else // else, we're Sleep Proxy Server; open BPF fds 7885 { 7886 if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1) 7887 { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); } 7888 } 7889 } 7890 7891#endif // APPLE_OSX_mDNSResponder 7892 7893 uDNS_SetupDNSConfig(m); 7894 mDNS_ConfigChanged(m); 7895 7896 if (IsAppleNetwork(m) != mDNS_McastTracingEnabled) 7897 { 7898 mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue; 7899 LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled"); 7900 UpdateDebugState(); 7901 } 7902 7903} 7904 7905// Called with KQueueLock & mDNS lock 7906mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay) 7907{ 7908 if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0) 7909 { 7910 m->p->NetworkChanged = NonZeroTime(m->timenow + delay); 7911 LogInfo("SetNetworkChanged: scheduling in %d msec", delay); 7912 } 7913} 7914 7915// Called with KQueueLock & mDNS lock 7916mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay) 7917{ 7918 // If it's not set or it needs to happen sooner than when it's currently set 7919 if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0) 7920 { 7921 m->p->KeyChainTimer = NonZeroTime(m->timenow + delay); 7922 LogInfo("SetKeyChainTimer: %d", delay); 7923 } 7924} 7925 7926// Copy the fourth slash-delimited element from either: 7927// State:/Network/Interface/<bsdname>/IPv4 7928// or 7929// Setup:/Network/Service/<servicename>/Interface 7930mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key) 7931{ 7932 CFArrayRef a; 7933 CFStringRef name = NULL; 7934 7935 a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/")); 7936 if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3)); 7937 if (a != NULL) CFRelease(a); 7938 7939 return name; 7940} 7941 7942// Whether a key from a network change notification corresponds to 7943// an IP service that is explicitly configured for IPv4 Link Local 7944mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys) 7945{ 7946 SCDynamicStoreRef store = NULL; 7947 CFDictionaryRef dict = NULL; 7948 CFMutableArrayRef a; 7949 const void **keys = NULL, **vals = NULL; 7950 CFStringRef pattern = NULL; 7951 int i, ic, j, jc; 7952 mDNSBool found = mDNSfalse; 7953 7954 jc = CFArrayGetCount(inkeys); 7955 if (!jc) goto done; 7956 7957 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL); 7958 if (store == NULL) goto done; 7959 7960 a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 7961 if (a == NULL) goto done; 7962 7963 // Setup:/Network/Service/[^/]+/Interface 7964 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface); 7965 if (pattern == NULL) goto done; 7966 CFArrayAppendValue(a, pattern); 7967 CFRelease(pattern); 7968 7969 // Setup:/Network/Service/[^/]+/IPv4 7970 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4); 7971 if (pattern == NULL) goto done; 7972 CFArrayAppendValue(a, pattern); 7973 CFRelease(pattern); 7974 7975 dict = SCDynamicStoreCopyMultiple(store, NULL, a); 7976 CFRelease(a); 7977 7978 if (!dict) 7979 { 7980 LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary"); 7981 goto done; 7982 } 7983 7984 ic = CFDictionaryGetCount(dict); 7985 vals = mDNSPlatformMemAllocate(sizeof (void *) * ic); 7986 keys = mDNSPlatformMemAllocate(sizeof (void *) * ic); 7987 CFDictionaryGetKeysAndValues(dict, keys, vals); 7988 7989 for (j = 0; j < jc && !found; j++) 7990 { 7991 CFStringRef key = CFArrayGetValueAtIndex(inkeys, j); 7992 CFStringRef ifname = NULL; 7993 7994 char buf[256]; 7995 7996 // It would be nice to use a regex here 7997 if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue; 7998 7999 if ((ifname = CopyNameFromKey(key)) == NULL) continue; 8000 if (mDNS_LoggingEnabled) 8001 { 8002 if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; 8003 LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf); 8004 } 8005 8006 for (i = 0; i < ic; i++) 8007 { 8008 CFDictionaryRef ipv4dict; 8009 CFStringRef name; 8010 CFStringRef serviceid; 8011 CFStringRef configmethod; 8012 8013 if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue; 8014 8015 if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue; 8016 8017 if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue; 8018 8019 if (!CFEqual(ifname, name)) continue; 8020 8021 if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue; 8022 if (mDNS_LoggingEnabled) 8023 { 8024 if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; 8025 LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf); 8026 } 8027 8028 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4); 8029 CFRelease(serviceid); 8030 if (pattern == NULL) continue; 8031 8032 ipv4dict = CFDictionaryGetValue(dict, pattern); 8033 CFRelease(pattern); 8034 if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue; 8035 8036 configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod); 8037 if (!configmethod) continue; 8038 8039 if (mDNS_LoggingEnabled) 8040 { 8041 if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; 8042 LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf); 8043 } 8044 8045 if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; } 8046 } 8047 8048 CFRelease(ifname); 8049 } 8050 8051done: 8052 if (vals != NULL) mDNSPlatformMemFree(vals); 8053 if (keys != NULL) mDNSPlatformMemFree(keys); 8054 if (dict != NULL) CFRelease(dict); 8055 if (store != NULL) CFRelease(store); 8056 8057 return found; 8058} 8059 8060mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) 8061{ 8062 (void)store; // Parameter not used 8063 mDNSBool changeNow = mDNSfalse; 8064 mDNS *const m = (mDNS *const)context; 8065 KQueueLock(m); 8066 mDNS_Lock(m); 8067 8068 mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay 8069 8070 int c = CFArrayGetCount(changedKeys); // Count changes 8071 CFRange range = { 0, c }; 8072 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0); 8073 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0); 8074 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0); 8075 int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0); 8076 if (c && c - c1 - c2 - c3 - c4 == 0) 8077 delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay 8078 8079 // Do immediate network changed processing for "p2p*" interfaces and 8080 // for interfaces with the IFEF_DIRECTLINK flag set. 8081 { 8082 CFArrayRef labels; 8083 CFIndex n; 8084 for (int i = 0; i < c; i++) 8085 { 8086 CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i); 8087 8088 // Only look at keys with prefix "State:/Network/Interface/" 8089 if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix)) 8090 continue; 8091 8092 // And suffix "IPv6" or "IPv4". 8093 if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4)) 8094 continue; 8095 8096 labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/")); 8097 if (labels == NULL) 8098 break; 8099 n = CFArrayGetCount(labels); 8100 8101 // Interface changes will have keys of the form: 8102 // State:/Network/Interface/<interfaceName>/IPv6 8103 // Thus five '/' seperated fields, the 4th one being the <interfaceName> string. 8104 if (n == 5) 8105 { 8106 char buf[256]; 8107 8108 // The 4th label (index = 3) should be the interface name. 8109 if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8) 8110 && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK))) 8111 { 8112 LogInfo("NetworkChanged: interface %s, not delaying network change", buf); 8113 changeNow = mDNStrue; 8114 CFRelease(labels); 8115 break; 8116 } 8117 } 8118 CFRelease(labels); 8119 } 8120 } 8121 8122 mDNSBool btmmChanged = CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac); 8123 if (btmmChanged) delay = 0; 8124 8125 if (mDNS_LoggingEnabled) 8126 { 8127 int i; 8128 for (i=0; i<c; i++) 8129 { 8130 char buf[256]; 8131 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; 8132 LogInfo("*** NetworkChanged SC key: %s", buf); 8133 } 8134 LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d", 8135 c, c>1 ? "s" : "", 8136 c1 ? "(Local Hostname) " : "", 8137 c2 ? "(Computer Name) " : "", 8138 c3 ? "(DynamicDNS) " : "", 8139 c4 ? "(DNS) " : "", 8140 changeNow ? 0 : delay); 8141 } 8142 8143 if (!changeNow) 8144 SetNetworkChanged(m, delay); 8145 8146 // Other software might pick up these changes to register or browse in WAB or BTMM domains, 8147 // so in order for secure updates to be made to the server, make sure to read the keychain and 8148 // setup the DomainAuthInfo before handing the network change. 8149 // If we don't, then we will first try to register services in the clear, then later setup the 8150 // DomainAuthInfo, which is incorrect. 8151 if (c3 || btmmChanged) 8152 SetKeyChainTimer(m, delay); 8153 8154 mDNS_Unlock(m); 8155 8156 // If DNS settings changed, immediately force a reconfig (esp. cache flush) 8157 // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig 8158 if (c4 || ChangedKeysHaveIPv4LL(changedKeys) || changeNow) mDNSMacOSXNetworkChanged(m); 8159 8160 KQueueUnlock(m, "NetworkChanged"); 8161} 8162 8163#if APPLE_OSX_mDNSResponder 8164mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context) 8165{ 8166 (void)context; 8167 char buf[IFNAMSIZ]; 8168 8169 CFStringRef ifnameStr = (CFStringRef)key; 8170 CFArrayRef array = (CFArrayRef)value; 8171 if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8)) 8172 buf[0] = 0; 8173 8174 LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array)); 8175 mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value); 8176} 8177#endif 8178 8179mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info) 8180{ 8181 mDNS *const m = (mDNS *const)info; 8182 (void)store; 8183 8184 LogInfo("DynamicStoreReconnected: Reconnected"); 8185 8186 // State:/Network/MulticastDNS 8187 SetLocalDomains(); 8188 8189 // State:/Network/DynamicDNS 8190 if (m->FQDN.c[0]) 8191 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); 8192 8193 // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted 8194 // as we receive network change notifications and thus not necessary. But we leave it here 8195 // so that if things are done differently in the future, this code still works. 8196 8197 // State:/Network/PrivateDNS 8198 if (privateDnsArray) 8199 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray); 8200 8201#if APPLE_OSX_mDNSResponder 8202 mDNS_Lock(m); 8203 // State:/Network/BackToMyMac 8204 UpdateAutoTunnelDomainStatuses(m); 8205 mDNS_Unlock(m); 8206 8207 // State:/Network/Interface/en0/SleepProxyServers 8208 if (spsStatusDict) 8209 CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL); 8210#endif 8211} 8212 8213mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) 8214{ 8215 mStatus err = -1; 8216 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL }; 8217 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context); 8218 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 8219 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4); 8220 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6); 8221 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 8222 8223 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; } 8224 if (!keys || !pattern1 || !pattern2 || !patterns) goto error; 8225 8226 CFArrayAppendValue(keys, NetworkChangedKey_IPv4); 8227 CFArrayAppendValue(keys, NetworkChangedKey_IPv6); 8228 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames); 8229 CFArrayAppendValue(keys, NetworkChangedKey_Computername); 8230 CFArrayAppendValue(keys, NetworkChangedKey_DNS); 8231 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS); 8232 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac); 8233 CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656> 8234 CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity); 8235 CFArrayAppendValue(patterns, pattern1); 8236 CFArrayAppendValue(patterns, pattern2); 8237 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort")); 8238 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) 8239 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; } 8240 8241#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 8242 if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue())) 8243 { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; } 8244#else 8245 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 8246 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; } 8247 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); 8248#endif 8249 SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected); 8250 m->p->Store = store; 8251 err = 0; 8252 goto exit; 8253 8254error: 8255 if (store) CFRelease(store); 8256 8257exit: 8258 if (patterns) CFRelease(patterns); 8259 if (pattern2) CFRelease(pattern2); 8260 if (pattern1) CFRelease(pattern1); 8261 if (keys) CFRelease(keys); 8262 8263 return(err); 8264} 8265 8266#if 0 // <rdar://problem/6751656> 8267mDNSlocal void PMChanged(void *context) 8268{ 8269 mDNS *const m = (mDNS *const)context; 8270 8271 KQueueLock(m); 8272 mDNS_Lock(m); 8273 8274 LogSPS("PMChanged"); 8275 8276 SetNetworkChanged(m, mDNSPlatformOneSecond * 2); 8277 8278 mDNS_Unlock(m); 8279 KQueueUnlock(m, "PMChanged"); 8280} 8281 8282mDNSlocal mStatus WatchForPMChanges(mDNS *const m) 8283{ 8284 m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m); 8285 if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; } 8286 8287 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); 8288 8289 return mStatus_NoError; 8290} 8291#endif 8292 8293#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded 8294 8295mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord) 8296{ 8297 AuthRecord *rr; 8298 pfArray_t portArray; 8299 pfArray_t protocolArray; 8300 uint32_t count = 0; 8301 8302 for (rr = m->ResourceRecords; rr; rr=rr->next) 8303 { 8304 if ((rr->resrec.rrtype == kDNSServiceType_SRV) 8305 && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P))) 8306 { 8307 const mDNSu8 *p; 8308 8309 if (count >= PFPortArraySize) 8310 { 8311 LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr)); 8312 continue; 8313 } 8314 8315 if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord)) 8316 { 8317 LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr)); 8318 continue; 8319 } 8320 8321 LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr)); 8322 8323 portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger; 8324 8325 // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name> 8326 p = rr->resrec.name->c; 8327 8328 // Skip to App Protocol 8329 if (p[0]) p += 1 + p[0]; 8330 8331 // Skip to Transport Protocol 8332 if (p[0]) p += 1 + p[0]; 8333 8334 if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP; 8335 else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP; 8336 else 8337 { 8338 LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service"); 8339 LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr)); 8340 return; 8341 } 8342 count++; 8343 } 8344 } 8345 mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray); 8346} 8347 8348// If the p2p interface already exists, update the Bonjour packet filter rules for it. 8349mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord) 8350{ 8351 mDNS *const m = &mDNSStorage; 8352 8353 NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 8354 while (intf) 8355 { 8356 if (strncmp(intf->ifname, "p2p", 3) == 0) 8357 { 8358 LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname); 8359 mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord); 8360 break; 8361 } 8362 intf = GetFirstActiveInterface(intf->next); 8363 } 8364} 8365 8366#else // !TARGET_OS_EMBEDDED 8367 8368// Currently no packet filter setup required on embedded platforms. 8369mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord) 8370{ 8371 (void) excludeRecord; // unused 8372} 8373 8374#endif // !TARGET_OS_EMBEDDED 8375 8376// Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements 8377// marked to include the AWDL interface. 8378mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr) 8379{ 8380 char ifname[IFNAMSIZ]; 8381 mDNSu32 interfaceIndex; 8382 DNSQuestion *q; 8383 AuthRecord *rr; 8384 NetworkInterfaceInfoOSX *infoOSX; 8385 mDNSInterfaceID InterfaceID; 8386 8387 snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit); 8388 interfaceIndex = if_nametoindex(ifname); 8389 8390 if (!interfaceIndex) 8391 { 8392 LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname); 8393 return; 8394 } 8395 8396 LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex); 8397 infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex); 8398 8399 // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing 8400 // when it is first brought up. 8401 if (!infoOSX) 8402 { 8403 LogInfo("newMasterElected: interface not yet active"); 8404 return; 8405 } 8406 InterfaceID = infoOSX->ifinfo.InterfaceID; 8407 8408 for (q = m->Questions; q; q=q->next) 8409 { 8410 if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL)) 8411 || q->InterfaceID == InterfaceID) 8412 { 8413 LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c); 8414 mDNSCoreRestartQuestion(m, q); 8415 } 8416 } 8417 8418 for (rr = m->ResourceRecords; rr; rr=rr->next) 8419 { 8420 if ((!rr->resrec.InterfaceID 8421 && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))) 8422 || rr->resrec.InterfaceID == InterfaceID) 8423 { 8424 LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c); 8425 mDNSCoreRestartRegistration(m, rr, -1); 8426 } 8427 } 8428} 8429 8430// An ssth array of all zeroes indicates the peer has no services registered. 8431mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op) 8432{ 8433 int i; 8434 int *intp = (int *) op->ssth; 8435 8436 // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if 8437 // it's not, print an error message and return false so that 8438 // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event 8439 // is received. 8440 if (MAX_SSTH_SIZE % sizeof(int)) 8441 { 8442 LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE); 8443 return mDNSfalse; 8444 } 8445 8446 for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++) 8447 { 8448 if (*intp) 8449 return mDNSfalse; 8450 } 8451 return mDNStrue; 8452} 8453 8454// mDNS_Reconfirm_internal() adds 33% to this interval, so the records should 8455// be removed in 4 seconds. 8456#define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3) 8457 8458// Mark records from this peer for deletion from the cache. 8459mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap) 8460{ 8461 mDNSu32 slot; 8462 CacheGroup *cg; 8463 CacheRecord *cr; 8464 mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex); 8465 8466 if (!InterfaceID) 8467 { 8468 LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex); 8469 return; 8470 } 8471 8472 FORALL_CACHERECORDS(slot, cg, cr) 8473 { 8474 if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress)) 8475 { 8476 LogInfo("removeCachedPeerRecords: %s %##s marking for deletion", 8477 DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c); 8478 mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime); 8479 } 8480 } 8481} 8482 8483// Handle KEV_DL_NODE_PRESENCE event. 8484mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p) 8485{ 8486 char buf[INET6_ADDRSTRLEN]; 8487 struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info; 8488 8489 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf))) 8490 LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI); 8491 else 8492 LogInfo("nodePresence: inet_ntop() error"); 8493 8494 // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of 8495 // all zeroes when a node is present and has no services registered. 8496 if (allZeroSSTH(op)) 8497 { 8498 mDNSAddr peerAddr; 8499 8500 peerAddr.type = mDNSAddrType_IPv6; 8501 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; 8502 8503 LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer"); 8504 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); 8505 } 8506} 8507 8508// Handle KEV_DL_NODE_ABSENCE event. 8509mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p) 8510{ 8511 mDNSAddr peerAddr; 8512 char buf[INET6_ADDRSTRLEN]; 8513 8514 if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf))) 8515 LogInfo("nodeAbsence: IPv6 address: %s", buf); 8516 else 8517 LogInfo("nodeAbsence: inet_ntop() error"); 8518 8519 peerAddr.type = mDNSAddrType_IPv6; 8520 peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr; 8521 8522 LogInfo("nodeAbsence: delete cached records from this peer"); 8523 removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr); 8524} 8525 8526mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context) 8527{ 8528 mDNS *const m = (mDNS *const)context; 8529 8530 mDNS_Lock(m); 8531 8532 struct { struct kern_event_msg k; char extra[256]; } msg; 8533 int bytes = recv(s1, &msg, sizeof(msg), 0); 8534 if (bytes < 0) 8535 LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno)); 8536 else 8537 { 8538 LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s", 8539 bytes, msg.k.total_size, 8540 msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?", 8541 msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?", 8542 msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?", 8543 msg.k.id, msg.k.event_code, 8544 msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" : 8545 msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" : 8546 msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" : 8547 msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" : 8548 msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" : 8549 msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" : 8550 msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" : 8551 msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" : 8552 msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" : 8553 msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" : 8554 msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" : 8555 msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" : 8556 msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" : 8557 msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" : 8558 msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" : 8559 msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" : 8560 msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" : 8561 msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" : 8562 msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" : 8563 msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" : 8564 msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" : 8565 msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" : 8566 msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" : 8567 "?"); 8568 8569 if (msg.k.event_code == KEV_DL_NODE_PRESENCE) 8570 nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data); 8571 8572 if (msg.k.event_code == KEV_DL_NODE_ABSENCE) 8573 nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data); 8574 8575 if (msg.k.event_code == KEV_DL_MASTER_ELECTED) 8576 newMasterElected(m, (struct net_event_data *) &msg.k.event_data); 8577 8578 // We receive network change notifications both through configd and through SYSPROTO_EVENT socket. 8579 // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP) 8580 // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if 8581 // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED. 8582 // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change. 8583 8584 if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON) 8585 SetNetworkChanged(m, mDNSPlatformOneSecond * 2); 8586 8587#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded 8588 8589 // For p2p interfaces, need to open the advertised service port in the firewall. 8590 if (msg.k.event_code == KEV_DL_IF_ATTACHED) 8591 { 8592 struct net_event_data * p; 8593 p = (struct net_event_data *) &msg.k.event_data; 8594 8595 if (strncmp(p->if_name, "p2p", 3) == 0) 8596 { 8597 char ifname[IFNAMSIZ]; 8598 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit); 8599 8600 LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name); 8601 8602 mDNSSetPacketFilterRules(m, ifname, NULL); 8603 } 8604 } 8605 8606 // For p2p interfaces, need to clear the firewall rules on interface detach 8607 if (msg.k.event_code == KEV_DL_IF_DETACHED) 8608 { 8609 struct net_event_data * p; 8610 p = (struct net_event_data *) &msg.k.event_data; 8611 8612 if (strncmp(p->if_name, "p2p", 3) == 0) 8613 { 8614 pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES 8615 char ifname[IFNAMSIZ]; 8616 snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit); 8617 8618 LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name); 8619 8620 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray); 8621 } 8622 } 8623#endif // !TARGET_OS_EMBEDDED 8624 8625 } 8626 8627 mDNS_Unlock(m); 8628} 8629 8630mDNSlocal mStatus WatchForSysEvents(mDNS *const m) 8631{ 8632 m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT); 8633 if (m->p->SysEventNotifier < 0) 8634 { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); } 8635 8636 struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS }; 8637 int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req); 8638 if (err < 0) 8639 { 8640 LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno)); 8641 close(m->p->SysEventNotifier); 8642 m->p->SysEventNotifier = -1; 8643 return(mStatus_UnknownErr); 8644 } 8645 8646 m->p->SysEventKQueue.KQcallback = SysEventCallBack; 8647 m->p->SysEventKQueue.KQcontext = m; 8648 m->p->SysEventKQueue.KQtask = "System Event Notifier"; 8649 KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue); 8650 8651 return(mStatus_NoError); 8652} 8653 8654#ifndef NO_SECURITYFRAMEWORK 8655mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context) 8656{ 8657 LogInfo("*** Keychain Changed ***"); 8658 mDNS *const m = (mDNS *const)context; 8659 SecKeychainRef skc; 8660 OSStatus err = SecKeychainCopyDefault(&skc); 8661 if (!err) 8662 { 8663 if (info->keychain == skc) 8664 { 8665 // 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 8666 mDNSBool relevant = (keychainEvent == kSecDeleteEvent); 8667 if (!relevant) 8668 { 8669 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr }; 8670 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats 8671 SecKeychainAttributeList *a = NULL; 8672 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL); 8673 if (!err) 8674 { 8675 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) || 8676 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) || 8677 (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix))))); 8678 SecKeychainItemFreeAttributesAndData(a, NULL); 8679 } 8680 } 8681 if (relevant) 8682 { 8683 LogInfo("*** Keychain Changed *** KeychainEvent=%d %s", 8684 keychainEvent, 8685 keychainEvent == kSecAddEvent ? "kSecAddEvent" : 8686 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : 8687 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>"); 8688 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding 8689 KQueueLock(m); 8690 mDNS_Lock(m); 8691 8692 // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain 8693 // then the BTMM DynStore dictionary, so delay reading the keychain for a second. 8694 // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes. 8695 // 8696 // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has, 8697 // the DynStore dictionary won't change (because the BTMM zone won't change). In that case, 8698 // a one second delay is ok, as we'll still converge to correctness, and there's no race 8699 // condition between the RegistrationDomain and the DomainAuthInfo. 8700 // 8701 // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set 8702 // the timer here, as it will not get set by NetworkChanged(). 8703 SetKeyChainTimer(m, mDNSPlatformOneSecond); 8704 8705 mDNS_Unlock(m); 8706 KQueueUnlock(m, "KeychainChanged"); 8707 } 8708 } 8709 CFRelease(skc); 8710 } 8711 8712 return 0; 8713} 8714#endif 8715 8716mDNSlocal void PowerOn(mDNS *const m) 8717{ 8718 mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake; 8719 if (m->p->WakeAtUTC) 8720 { 8721 long utc = mDNSPlatformUTC(); 8722 mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake 8723 if (m->p->WakeAtUTC - utc > 30) 8724 { 8725 LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc); 8726 } 8727 else if (utc - m->p->WakeAtUTC > 30) 8728 { 8729 LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC); 8730 } 8731 else if (IsAppleTV()) 8732 { 8733 LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC); 8734 } 8735 else 8736 { 8737 LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc); 8738 m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond; 8739 } 8740 } 8741} 8742 8743mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) 8744{ 8745 mDNS *const m = (mDNS *const)refcon; 8746 KQueueLock(m); 8747 (void)service; // Parameter not used 8748 debugf("PowerChanged %X %lX", messageType, messageArgument); 8749 8750 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting 8751 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); 8752 8753 switch(messageType) 8754 { 8755 case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240 8756 case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250 8757 mDNSCoreMachineSleep(m, true); 8758 if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); 8759 break; 8760 case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260 8761 case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270 8762 case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280 8763 mDNSCoreMachineSleep(m, true); 8764 break; 8765 case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290 8766 case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300 8767 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now 8768 if (m->SleepState) 8769 { 8770 LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState); 8771 PowerOn(m); 8772 } 8773 // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received 8774 // the System Configuration Framework "network changed" event that we expect 8775 // to receive some time shortly after the kIOMessageSystemWillPowerOn message 8776 mDNS_Lock(m); 8777 if (!m->p->NetworkChanged || 8778 m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0) 8779 m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2); 8780 mDNS_Unlock(m); 8781 8782 break; 8783 case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310 8784 case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320 8785 8786 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake 8787 if (m->SleepState != SleepState_Sleeping) 8788 { 8789 LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState); 8790 m->SleepState = SleepState_Sleeping; 8791 mDNSMacOSXNetworkChanged(m); 8792 } 8793 PowerOn(m); 8794 break; 8795 default: LogSPS("PowerChanged unknown message %X", messageType); break; 8796 } 8797 8798 if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument; 8799 else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); 8800 8801 KQueueUnlock(m, "PowerChanged Sleep/Wake"); 8802} 8803 8804// iPhone OS doesn't currently have SnowLeopard's IO Power Management 8805// but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements 8806#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED 8807mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor) 8808{ 8809 mDNS *const m = (mDNS *const)refcon; 8810 KQueueLock(m); 8811 LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s", 8812 connection, token, eventDescriptor, 8813 eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "", 8814 eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "", 8815 eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "", 8816 eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "", 8817 eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : ""); 8818 8819 // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting 8820 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); 8821 8822 if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU) 8823 { 8824 // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't 8825 // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to 8826 // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping 8827 // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup. 8828 if (m->SleepLimit) 8829 { 8830 LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState); 8831 IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie); 8832 m->SleepLimit = 0; 8833 } 8834 LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState); 8835 // If the network notifications have already come before we got the wakeup, we ignored them and 8836 // in case we get no more, we need to trigger one. 8837 mDNS_Lock(m); 8838 SetNetworkChanged(m, 2 * mDNSPlatformOneSecond); 8839 mDNS_Unlock(m); 8840 // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down. 8841 if (m->SleepState != SleepState_Awake) PowerOn(m); 8842 IOPMConnectionAcknowledgeEvent(connection, token); 8843 } 8844 else 8845 { 8846 // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting 8847 // we should hear nothing more until we're told that the CPU has started executing again. 8848 if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState); 8849 //sleep(5); 8850 //mDNSMacOSXNetworkChanged(m); 8851 mDNSCoreMachineSleep(m, true); 8852 //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); 8853 m->p->SleepCookie = token; 8854 } 8855 8856 KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake"); 8857} 8858#endif 8859 8860#if COMPILER_LIKES_PRAGMA_MARK 8861#pragma mark - 8862#pragma mark - /etc/hosts support 8863#endif 8864 8865// Implementation Notes 8866// 8867// As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about 8868// 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse 8869// them into a hash table. The implementation need to be able to do the following things efficiently 8870// 8871// 1. Detect duplicates e.g., two entries with "1.2.3.4 foo" 8872// 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk 8873// 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we 8874// need to be able set the RRSet of a resource record to the first one in the list and also update when 8875// one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and 8876// not a duplicate 8877// 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts 8878// 8879// CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom 8880// "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation 8881// of the core layer which does all of the above very efficiently 8882 8883#define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts 8884 8885mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result) 8886{ 8887 (void)m; // unused 8888 (void)rr; 8889 (void)result; 8890 if (result == mStatus_MemFree) 8891 { 8892 LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr)); 8893 freeL("etchosts", rr); 8894 } 8895} 8896 8897// Returns true on success and false on failure 8898mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth) 8899{ 8900 AuthRecord *rr; 8901 mDNSu32 slot; 8902 mDNSu32 namehash; 8903 AuthGroup *ag; 8904 mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly; 8905 mDNSu16 rrtype; 8906 8907 if (!domain) 8908 { 8909 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL"); 8910 return mDNSfalse; 8911 } 8912 if (!sa && !cname) 8913 { 8914 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL"); 8915 return mDNSfalse; 8916 } 8917 8918 if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6) 8919 { 8920 LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family); 8921 return mDNSfalse; 8922 } 8923 8924 8925 if (ifname) 8926 { 8927 mDNSu32 ifindex = if_nametoindex(ifname); 8928 if (!ifindex) 8929 { 8930 LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname); 8931 return mDNSfalse; 8932 } 8933 InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex; 8934 } 8935 8936 if (sa) 8937 rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA); 8938 else 8939 rrtype = kDNSType_CNAME; 8940 8941 // Check for duplicates. See whether we parsed an entry before like this ? 8942 slot = AuthHashSlot(domain); 8943 namehash = DomainNameHashValue(domain); 8944 ag = AuthGroupForName(auth, slot, namehash, domain); 8945 if (ag) 8946 { 8947 rr = ag->members; 8948 while (rr) 8949 { 8950 if (rr->resrec.rrtype == rrtype) 8951 { 8952 if (rrtype == kDNSType_A) 8953 { 8954 mDNSv4Addr ip; 8955 ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr; 8956 if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip)) 8957 { 8958 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c); 8959 return mDNSfalse; 8960 } 8961 } 8962 else if (rrtype == kDNSType_AAAA) 8963 { 8964 mDNSv6Addr ip6; 8965 ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0]; 8966 ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1]; 8967 ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2]; 8968 ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3]; 8969 if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6)) 8970 { 8971 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c); 8972 return mDNSfalse; 8973 } 8974 } 8975 else if (rrtype == kDNSType_CNAME) 8976 { 8977 if (SameDomainName(&rr->resrec.rdata->u.name, cname)) 8978 { 8979 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c); 8980 return mDNSfalse; 8981 } 8982 } 8983 } 8984 rr = rr->next; 8985 } 8986 } 8987 rr= mallocL("etchosts", sizeof(*rr)); 8988 if (rr == NULL) return mDNSfalse; 8989 mDNSPlatformMemZero(rr, sizeof(*rr)); 8990 mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL); 8991 AssignDomainName(&rr->namestorage, domain); 8992 8993 if (sa) 8994 { 8995 rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr); 8996 if (sa->sa_family == AF_INET) 8997 rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr; 8998 else 8999 { 9000 rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0]; 9001 rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1]; 9002 rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2]; 9003 rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3]; 9004 } 9005 } 9006 else 9007 { 9008 rr->resrec.rdlength = DomainNameLength(cname); 9009 rr->resrec.rdata->u.name.c[0] = 0; 9010 AssignDomainName(&rr->resrec.rdata->u.name, cname); 9011 } 9012 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 9013 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us 9014 LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr)); 9015 InsertAuthRecord(m, auth, rr); 9016 return mDNStrue; 9017} 9018 9019mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name) 9020{ 9021 int i; 9022 9023 *name = NULL; 9024 for (i = start; i < length; i++) 9025 { 9026 if (buffer[i] == '#') 9027 return -1; 9028 if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t') 9029 { 9030 *name = &buffer[i]; 9031 9032 // Found the start of a name, find the end and null terminate 9033 for (i++; i < length; i++) 9034 { 9035 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t') 9036 { 9037 buffer[i] = 0; 9038 break; 9039 } 9040 } 9041 return i; 9042 } 9043 } 9044 return -1; 9045} 9046 9047mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth) 9048{ 9049 int i; 9050 int ifStart = 0; 9051 char *ifname = NULL; 9052 domainname name1d; 9053 domainname name2d; 9054 char *name1; 9055 char *name2; 9056 int aliasIndex; 9057 9058 //Ignore leading whitespaces and tabs 9059 while (*buffer == ' ' || *buffer == '\t') 9060 { 9061 buffer++; 9062 length--; 9063 } 9064 9065 // Find the end of the address string 9066 for (i = 0; i < length; i++) 9067 { 9068 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%') 9069 { 9070 if (buffer[i] == '%') 9071 ifStart = i + 1; 9072 buffer[i] = 0; 9073 break; 9074 } 9075 } 9076 9077 // Convert the address string to an address 9078 struct addrinfo hints; 9079 bzero(&hints, sizeof(hints)); 9080 hints.ai_flags = AI_NUMERICHOST; 9081 struct addrinfo *gairesults = NULL; 9082 if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0) 9083 { 9084 LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null"); 9085 return; 9086 } 9087 9088 if (ifStart) 9089 { 9090 // Parse the interface 9091 ifname = &buffer[ifStart]; 9092 for (i = ifStart + 1; i < length; i++) 9093 { 9094 if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t') 9095 { 9096 buffer[i] = 0; 9097 break; 9098 } 9099 } 9100 } 9101 9102 i = EtcHostsParseOneName(i + 1, length, buffer, &name1); 9103 if (i == length) 9104 { 9105 // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc. 9106 if (!MakeDomainNameFromDNSNameString(&name1d, name1)) 9107 { 9108 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1); 9109 freeaddrinfo(gairesults); 9110 return; 9111 } 9112 mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth); 9113 } 9114 else if (i != -1) 9115 { 9116 domainname first; 9117 // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost". 9118 // When we parse again below, EtchHostsParseOneName would return -1 and we will end up 9119 // doing the right thing. 9120 if (!MakeDomainNameFromDNSNameString(&first, name1)) 9121 { 9122 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1); 9123 freeaddrinfo(gairesults); 9124 return; 9125 } 9126 // If the /etc/hosts has an entry like this 9127 // 9128 // 1.2.3.4 sun star bright 9129 // 9130 // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical 9131 // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun") 9132 // 9133 // To achieve this, we need to add the entry like this: 9134 // 9135 // star CNAME bright 9136 // bright CNAME sun 9137 // sun A 1.2.3.4 9138 // 9139 // We store the first name we parsed in "first". Then we parse additional names adding CNAME records 9140 // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last 9141 // entry and the first entry. Finally, we add the Address (A/AAAA) record. 9142 aliasIndex = 0; 9143 while (i <= length) 9144 { 9145 // Parse a name. If there are no names, we need to know whether we 9146 // parsed CNAMEs before or not. If we parsed CNAMEs before, then we 9147 // add a CNAME with the last name and the first name. Otherwise, this 9148 // is same as the common case above where the line has just one name 9149 // but with trailing white spaces. 9150 i = EtcHostsParseOneName(i + 1, length, buffer, &name2); 9151 if (name2) 9152 { 9153 if (!MakeDomainNameFromDNSNameString(&name2d, name2)) 9154 { 9155 LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2); 9156 freeaddrinfo(gairesults); 9157 return; 9158 } 9159 aliasIndex++; 9160 } 9161 else if (!aliasIndex) 9162 { 9163 // We have never parsed any aliases. This case happens if there 9164 // is just one name and some extra white spaces at the end. 9165 LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c); 9166 break; 9167 } 9168 else 9169 { 9170 // We have parsed at least one alias before and we reached the end of the line. 9171 // Setup a CNAME for the last name with "first" name as its RDATA 9172 name2d.c[0] = 0; 9173 AssignDomainName(&name2d, &first); 9174 } 9175 9176 // Don't add a CNAME for the first alias we parse (see the example above). 9177 // As we parse more, we might discover that there are no more aliases, in 9178 // which case we would have set "name2d" to "first" above. We need to add 9179 // the CNAME in that case. 9180 9181 if (aliasIndex > 1 || SameDomainName(&name2d, &first)) 9182 { 9183 // Ignore if it points to itself 9184 if (!SameDomainName(&name1d, &name2d)) 9185 { 9186 if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth)) 9187 { 9188 freeaddrinfo(gairesults); 9189 return; 9190 } 9191 } 9192 else 9193 LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c); 9194 } 9195 9196 // If we have already wrapped around, we just need to add the A/AAAA record alone 9197 // which is done below 9198 if (SameDomainName(&name2d, &first)) break; 9199 9200 // Remember the current name so that we can set the CNAME record if we parse one 9201 // more name 9202 name1d.c[0] = 0; 9203 AssignDomainName(&name1d, &name2d); 9204 } 9205 // Added all the CNAMEs if any, add the "A/AAAA" record 9206 mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth); 9207 } 9208 freeaddrinfo(gairesults); 9209} 9210 9211mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth) 9212{ 9213 mDNSBool good; 9214 char buf[ETCHOSTS_BUFSIZE]; 9215 ssize_t len; 9216 FILE *fp; 9217 9218 if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; } 9219 9220 fp = fopen("/etc/hosts", "r"); 9221 if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; } 9222 9223 while (1) 9224 { 9225 good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL); 9226 if (!good) break; 9227 9228 // skip comment and empty lines 9229 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n') 9230 continue; 9231 9232 len = strlen(buf); 9233 if (!len) break; // sanity check 9234 //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r) 9235 if (buf[len - 1] == '\r' || buf[len - 1] == '\n') 9236 { 9237 buf[len - 1] = '\0'; 9238 len = len - 1; 9239 } 9240 // fgets always null terminates and hence even if we have no 9241 // newline at the end, it is null terminated. The callee 9242 // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that 9243 // buf[length] is zero and hence we decrement len to reflect that. 9244 if (len) 9245 { 9246 //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes) 9247 //here we need to check for just \r but taking extra caution. 9248 if (buf[len - 1] == '\r' || buf[len - 1] == '\n') 9249 { 9250 buf[len - 1] = '\0'; 9251 len = len - 1; 9252 } 9253 } 9254 if (!len) //Sanity Check: len should never be zero 9255 { 9256 LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!"); 9257 continue; 9258 } 9259 mDNSMacOSXParseEtcHostsLine(m, buf, len, auth); 9260 } 9261 fclose(fp); 9262} 9263 9264mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m); 9265 9266mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m) 9267{ 9268#ifdef __DISPATCH_GROUP__ 9269 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch 9270 static dispatch_queue_t etcq = 0; 9271 static dispatch_source_t etcsrc = 0; 9272 static dispatch_source_t hostssrc = 0; 9273 9274 // First time through? just schedule ourselves on the main queue and we'll do the work later 9275 if (!etcq) 9276 { 9277 etcq = dispatch_get_main_queue(); 9278 if (etcq) 9279 { 9280 // Do this work on the queue, not here - solves potential synchronization issues 9281 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);}); 9282 } 9283 return -1; 9284 } 9285 9286 if (hostssrc) return dispatch_source_get_handle(hostssrc); 9287#endif 9288 9289 int fd = open("/etc/hosts", O_RDONLY); 9290 9291#ifdef __DISPATCH_GROUP__ 9292 // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch 9293 if (fd == -1) 9294 { 9295 // If the open failed and we're already watching /etc, we're done 9296 if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; } 9297 9298 // we aren't watching /etc, we should be 9299 fd = open("/etc", O_RDONLY); 9300 if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; } 9301 etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq); 9302 if (etcsrc == NULL) 9303 { 9304 close(fd); 9305 return -1; 9306 } 9307 dispatch_source_set_event_handler(etcsrc, 9308 ^{ 9309 u_int32_t flags = dispatch_source_get_data(etcsrc); 9310 LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags); 9311 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0) 9312 { 9313 dispatch_source_cancel(etcsrc); 9314 dispatch_release(etcsrc); 9315 etcsrc = NULL; 9316 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);}); 9317 return; 9318 } 9319 if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL) 9320 { 9321 mDNSMacOSXUpdateEtcHosts(m); 9322 } 9323 }); 9324 dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);}); 9325 dispatch_resume(etcsrc); 9326 9327 // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation 9328 fd = open("/etc/hosts", O_RDONLY | O_EVTONLY); 9329 if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; } 9330 } 9331 9332 // create a dispatch source to watch for changes to hosts file 9333 hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, 9334 (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME | 9335 DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq); 9336 if (hostssrc == NULL) 9337 { 9338 close(fd); 9339 return -1; 9340 } 9341 dispatch_source_set_event_handler(hostssrc, 9342 ^{ 9343 u_int32_t flags = dispatch_source_get_data(hostssrc); 9344 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags); 9345 if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0) 9346 { 9347 dispatch_source_cancel(hostssrc); 9348 dispatch_release(hostssrc); 9349 hostssrc = NULL; 9350 // Bug in LibDispatch: wait a second before scheduling the block. If we schedule 9351 // the block immediately, we try to open the file and the file may not exist and may 9352 // fail to get a notification in the future. When the file does not exist and 9353 // we start to monitor the directory, on "dispatch_resume" of that source, there 9354 // is no guarantee that the file creation will be notified always because when 9355 // the dispatch_resume returns, the kevent manager may not have registered the 9356 // kevent yet but the file may have been created 9357 usleep(1000000); 9358 dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);}); 9359 return; 9360 } 9361 if ((flags & DISPATCH_VNODE_WRITE) != 0) 9362 { 9363 mDNSMacOSXUpdateEtcHosts(m); 9364 } 9365 }); 9366 dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);}); 9367 dispatch_resume(hostssrc); 9368 9369 // Cleanup /etc source, no need to watch it if we already have /etc/hosts 9370 if (etcsrc) 9371 { 9372 dispatch_source_cancel(etcsrc); 9373 dispatch_release(etcsrc); 9374 etcsrc = NULL; 9375 } 9376 9377 LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc"); 9378 return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1; 9379#else 9380 (void)m; 9381 return fd; 9382#endif 9383} 9384 9385// When /etc/hosts is modified, flush all the cache records as there may be local 9386// authoritative answers now 9387mDNSlocal void FlushAllCacheRecords(mDNS *const m) 9388{ 9389 CacheRecord *cr; 9390 mDNSu32 slot; 9391 CacheGroup *cg; 9392 9393 FORALL_CACHERECORDS(slot, cg, cr) 9394 { 9395 // Skip multicast. 9396 if (cr->resrec.InterfaceID) continue; 9397 9398 // If a resource record can answer A or AAAA, they need to be flushed so that we will 9399 // never used to deliver an ADD or RMV 9400 if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) || 9401 RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA)) 9402 { 9403 LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr)); 9404 mDNS_PurgeCacheResourceRecord(m, cr); 9405 } 9406 } 9407} 9408 9409// Add new entries to the core. If justCheck is set, this function does not add, just returns true 9410mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck) 9411{ 9412 AuthGroup *ag; 9413 mDNSu32 slot; 9414 AuthRecord *rr, *primary, *rrnext; 9415 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 9416 for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next) 9417 { 9418 primary = NULL; 9419 for (rr = ag->members; rr; rr = rrnext) 9420 { 9421 rrnext = rr->next; 9422 AuthGroup *ag1; 9423 AuthRecord *rr1; 9424 mDNSBool found = mDNSfalse; 9425 ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec); 9426 if (ag1 && ag1->members) 9427 { 9428 if (!primary) primary = ag1->members; 9429 rr1 = ag1->members; 9430 while (rr1) 9431 { 9432 // We are not using InterfaceID in checking for duplicates. This means, 9433 // if there are two addresses for a given name e.g., fe80::1%en0 and 9434 // fe80::1%en1, we only add the first one. It is not clear whether 9435 // this is a common case. To fix this, we also need to modify 9436 // mDNS_Register_internal in how it handles duplicates. If it becomes a 9437 // common case, we will fix it then. 9438 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec)) 9439 { 9440 LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1)); 9441 found = mDNStrue; 9442 break; 9443 } 9444 rr1 = rr1->next; 9445 } 9446 } 9447 if (!found) 9448 { 9449 if (justCheck) 9450 { 9451 LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr)); 9452 return mDNStrue; 9453 } 9454 RemoveAuthRecord(m, newhosts, rr); 9455 // if there is no primary, point to self 9456 rr->RRSet = (primary ? primary : rr); 9457 rr->next = NULL; 9458 LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr)); 9459 if (mDNS_Register_internal(m, rr) != mStatus_NoError) 9460 LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr)); 9461 } 9462 } 9463 } 9464 return mDNSfalse; 9465} 9466 9467// Delete entries from the core that are no longer needed. If justCheck is set, this function 9468// does not delete, just returns true 9469mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck) 9470{ 9471 AuthGroup *ag; 9472 mDNSu32 slot; 9473 AuthRecord *rr, *primary, *rrnext; 9474 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 9475 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next) 9476 for (rr = ag->members; rr; rr = rrnext) 9477 { 9478 mDNSBool found = mDNSfalse; 9479 AuthGroup *ag1; 9480 AuthRecord *rr1; 9481 rrnext = rr->next; 9482 if (rr->RecordCallback != FreeEtcHosts) continue; 9483 ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec); 9484 if (ag1) 9485 { 9486 primary = rr1 = ag1->members; 9487 while (rr1) 9488 { 9489 if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec)) 9490 { 9491 LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr)); 9492 found = mDNStrue; 9493 break; 9494 } 9495 rr1 = rr1->next; 9496 } 9497 } 9498 // there is no corresponding record in newhosts for the same name. This means 9499 // we should delete this from the core. 9500 if (!found) 9501 { 9502 if (justCheck) 9503 { 9504 LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr)); 9505 return mDNStrue; 9506 } 9507 // if primary is going away, make sure that the rest of the records 9508 // point to the new primary 9509 if (rr == ag->members) 9510 { 9511 AuthRecord *new_primary = rr->next; 9512 AuthRecord *r = new_primary; 9513 while (r) 9514 { 9515 if (r->RRSet == rr) 9516 { 9517 LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r)); 9518 r->RRSet = new_primary; 9519 } 9520 else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name); 9521 r = r->next; 9522 } 9523 } 9524 LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr)); 9525 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 9526 } 9527 } 9528 return mDNSfalse; 9529} 9530 9531mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context) 9532{ 9533 AuthHash *newhosts = (AuthHash *)context; 9534 9535 mDNS_CheckLock(m); 9536 9537 //Delete old entries from the core if they are not present in the newhosts 9538 EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse); 9539 // Add the new entries to the core if not already present in the core 9540 EtcHostsAddNewEntries(m, newhosts, mDNSfalse); 9541} 9542 9543mDNSlocal void FreeNewHosts(AuthHash *newhosts) 9544{ 9545 mDNSu32 slot; 9546 AuthGroup *ag, *agnext; 9547 AuthRecord *rr, *rrnext; 9548 9549 for (slot = 0; slot < AUTH_HASH_SLOTS; slot++) 9550 for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext) 9551 { 9552 agnext = ag->next; 9553 for (rr = ag->members; rr; rr = rrnext) 9554 { 9555 rrnext = rr->next; 9556 freeL("etchosts", rr); 9557 } 9558 freeL("AuthGroups", ag); 9559 } 9560} 9561 9562mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m) 9563{ 9564 AuthHash newhosts; 9565 9566 // As we will be modifying the core, we can only have one thread running at 9567 // any point in time. 9568 KQueueLock(m); 9569 9570 mDNSPlatformMemZero(&newhosts, sizeof(AuthHash)); 9571 9572 // Get the file desecriptor (will trigger us to start watching for changes) 9573 int fd = mDNSMacOSXGetEtcHostsFD(m); 9574 if (fd != -1) 9575 { 9576 LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd); 9577 mDNSMacOSXParseEtcHosts(m, fd, &newhosts); 9578 } 9579 else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present"); 9580 9581 // Optimization: Detect whether /etc/hosts changed or not. 9582 // 9583 // 1. Check to see if there are any new entries. We do this by seeing whether any entries in 9584 // newhosts is already registered with core. If we find at least one entry that is not 9585 // registered with core, then it means we have work to do. 9586 // 9587 // 2. Next, we check to see if any of the entries that are registered with core is not present 9588 // in newhosts. If we find at least one entry that is not present, it means we have work to 9589 // do. 9590 // 9591 // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any 9592 // other thread from running. But mDNS_Lock is needed here as we will be traversing the core 9593 // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held 9594 // in the future and this code does not have to change. 9595 mDNS_Lock(m); 9596 // Add the new entries to the core if not already present in the core 9597 if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue)) 9598 { 9599 // No new entries to add, check to see if we need to delete any old entries from the 9600 // core if they are not present in the newhosts 9601 if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue)) 9602 { 9603 LogInfo("mDNSMacOSXUpdateEtcHosts: No work"); 9604 mDNS_Unlock(m); 9605 KQueueUnlock(m, "/etc/hosts changed"); 9606 FreeNewHosts(&newhosts); 9607 return; 9608 } 9609 } 9610 9611 // This will flush the cache, stop and start the query so that the queries 9612 // can look at the /etc/hosts again 9613 // 9614 // Notes: 9615 // 9616 // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to 9617 // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV 9618 // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries 9619 // delivers these events in the right order and then calls us back to delete them. 9620 // 9621 // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries 9622 // is a common function that looks at all local auth records and delivers a RMV including 9623 // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when 9624 // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering 9625 // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts 9626 // is called back where we do the Registration of the record. This results in RMV followed by ADD which 9627 // looks normal. 9628 mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts); 9629 mDNS_Unlock(m); 9630 9631 KQueueUnlock(m, "/etc/hosts changed"); 9632 FreeNewHosts(&newhosts); 9633} 9634 9635#if COMPILER_LIKES_PRAGMA_MARK 9636#pragma mark - 9637#pragma mark - Initialization & Teardown 9638#endif 9639 9640CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void); 9641CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey; 9642CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey; 9643CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; 9644 9645// Major version 13 is 10.9.x 9646mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring) 9647{ 9648 int major = 0, minor = 0; 9649 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>"; 9650 CFDictionaryRef vers = _CFCopySystemVersionDictionary(); 9651 if (vers) 9652 { 9653 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey); 9654 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey); 9655 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); 9656 if (cfprodname) 9657 CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8); 9658 if (cfprodvers) 9659 CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8); 9660 if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8)) 9661 sscanf(buildver, "%d%c%d", &major, &letter, &minor); 9662 CFRelease(vers); 9663 } 9664 if (!major) 9665 { 9666 major = 13; 9667 LogMsg("Note: No Major Build Version number found; assuming 13"); 9668 } 9669 if (HINFO_SWstring) 9670 mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion)); 9671 //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor); 9672 9673 // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers; 9674 if ((prodname[0] & 0xDF) == 'M') 9675 OSXVers = major; 9676 else 9677 iOSVers = major; 9678} 9679 9680// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT. 9681// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses -- 9682// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses. 9683mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) 9684{ 9685 int err = -1; 9686 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 9687 if (s < 3) 9688 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno)); 9689 else 9690 { 9691 struct sockaddr_in s5353; 9692 s5353.sin_family = AF_INET; 9693 s5353.sin_port = MulticastDNSPort.NotAnInteger; 9694 s5353.sin_addr.s_addr = 0; 9695 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353)); 9696 close(s); 9697 } 9698 9699 if (err) LogMsg("No unicast UDP responses"); 9700 else debugf("Unicast UDP responses okay"); 9701 return(err == 0); 9702} 9703 9704mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain) 9705{ 9706 AuthRecord *rr; 9707 const domainname *pname = (domainname *)"\x9" "localhost"; 9708 9709 rr= mallocL("localhosts", sizeof(*rr)); 9710 if (rr == NULL) return; 9711 mDNSPlatformMemZero(rr, sizeof(*rr)); 9712 9713 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL); 9714 AssignDomainName(&rr->namestorage, domain); 9715 9716 rr->resrec.rdlength = DomainNameLength(pname); 9717 rr->resrec.rdata->u.name.c[0] = 0; 9718 AssignDomainName(&rr->resrec.rdata->u.name, pname); 9719 9720 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 9721 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us 9722 mDNS_Register(m, rr); 9723} 9724 9725// Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying 9726// on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely 9727// fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating 9728// a bad user experience. For now, we specifically create only localhosts to handle radar://9354225 9729// 9730// Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate 9731// intentionally to avoid adding to the complexity of code handling /etc/hosts. 9732mDNSlocal void SetupLocalHostRecords(mDNS *const m) 9733{ 9734 char buffer[MAX_REVERSE_MAPPING_NAME]; 9735 domainname name; 9736 int i; 9737 struct in6_addr addr; 9738 mDNSu8 *ptr = addr.__u6_addr.__u6_addr8; 9739 9740 if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1) 9741 { 9742 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", 9743 ptr[3], ptr[2], ptr[1], ptr[0]); 9744 MakeDomainNameFromDNSNameString(&name, buffer); 9745 CreatePTRRecord(m, &name); 9746 } 9747 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed"); 9748 9749 if (inet_pton(AF_INET6, "::1", &addr) == 1) 9750 { 9751 for (i = 0; i < 16; i++) 9752 { 9753 static const char hexValues[] = "0123456789ABCDEF"; 9754 buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F]; 9755 buffer[i * 4 + 1] = '.'; 9756 buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4]; 9757 buffer[i * 4 + 3] = '.'; 9758 } 9759 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); 9760 MakeDomainNameFromDNSNameString(&name, buffer); 9761 CreatePTRRecord(m, &name); 9762 } 9763 else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed"); 9764} 9765 9766// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows: 9767// 1) query for b._dns-sd._udp.local on LocalOnly interface 9768// (.local manually generated via explicit callback) 9769// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>. 9770// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result> 9771// 4) result above should generate a callback from question in (1). result added to global list 9772// 5) global list delivered to client via GetSearchDomainList() 9773// 6) client calls to enumerate domains now go over LocalOnly interface 9774// (!!!KRS may add outgoing interface in addition) 9775 9776mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) 9777{ 9778 mStatus err; 9779 m->p->CFRunLoop = CFRunLoopGetCurrent(); 9780 9781 char HINFO_SWstring[256] = ""; 9782 mDNSMacOSXSystemBuildNumber(HINFO_SWstring); 9783 9784 err = mDNSHelperInit(); 9785 if (err) 9786 return err; 9787 9788 DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL); 9789 if (DynamicStoreQueue == NULL) 9790 { 9791 LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!"); 9792 return mStatus_NoMemoryErr; 9793 } 9794 9795 // Store mDNSResponder Platform 9796 if (OSXVers) 9797 { 9798 m->mDNS_plat = platform_OSX; 9799 } 9800 else if (iOSVers) 9801 { 9802 if (IsAppleTV()) 9803 m->mDNS_plat = platform_Atv; 9804 else 9805 m->mDNS_plat = platform_iOS; 9806 } 9807 else 9808 { 9809 m->mDNS_plat = platform_NonApple; 9810 } 9811 9812 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up. 9813 // 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. 9814 int i; 9815 for (i=0; i<100; i++) 9816 { 9817 domainlabel testlabel; 9818 testlabel.c[0] = 0; 9819 GetUserSpecifiedLocalHostName(&testlabel); 9820 if (testlabel.c[0]) break; 9821 usleep(50000); 9822 } 9823 9824 m->hostlabel.c[0] = 0; 9825 9826 int get_model[2] = { CTL_HW, HW_MODEL }; 9827 size_t len_model = sizeof(HINFO_HWstring_buffer); 9828 9829 // Normal Apple model names are of the form "iPhone2,1", and 9830 // internal code names are strings containing no commas, e.g. "N88AP". 9831 // We used to ignore internal code names, but Apple now uses these internal code names 9832 // even in released shipping products, so we no longer ignore strings containing no commas. 9833// if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ',')) 9834 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0) 9835 HINFO_HWstring = HINFO_HWstring_buffer; 9836 9837 // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation. 9838 // For names of the form "N88AP" containg no comma, we use the entire string. 9839 HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring); 9840 9841 if (mDNSPlatformInit_CanReceiveUnicast()) 9842 m->CanReceiveUnicastOn5353 = mDNStrue; 9843 9844 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring); 9845 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring); 9846 if (hlen + slen < 254) 9847 { 9848 m->HIHardware.c[0] = hlen; 9849 m->HISoftware.c[0] = slen; 9850 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen); 9851 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen); 9852 } 9853 9854 m->p->permanentsockets.port = MulticastDNSPort; 9855 m->p->permanentsockets.m = m; 9856 m->p->permanentsockets.sktv4 = -1; 9857 m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack; 9858 m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets; 9859 m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception"; 9860 m->p->permanentsockets.sktv6 = -1; 9861 m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack; 9862 m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets; 9863 m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception"; 9864 9865 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL); 9866 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL); 9867 9868 struct sockaddr_in s4; 9869 socklen_t n4 = sizeof(s4); 9870 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) 9871 LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno)); 9872 else 9873 m->UnicastPort4.NotAnInteger = s4.sin_port; 9874 9875 if (m->p->permanentsockets.sktv6 >= 0) 9876 { 9877 struct sockaddr_in6 s6; 9878 socklen_t n6 = sizeof(s6); 9879 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno)); 9880 else m->UnicastPort6.NotAnInteger = s6.sin6_port; 9881 } 9882 9883 m->p->InterfaceList = mDNSNULL; 9884 m->p->userhostlabel.c[0] = 0; 9885 m->p->usernicelabel.c[0] = 0; 9886 m->p->prevoldnicelabel.c[0] = 0; 9887 m->p->prevnewnicelabel.c[0] = 0; 9888 m->p->prevoldhostlabel.c[0] = 0; 9889 m->p->prevnewhostlabel.c[0] = 0; 9890 m->p->NotifyUser = 0; 9891 m->p->KeyChainTimer = 0; 9892 m->p->WakeAtUTC = 0; 9893 m->p->RequestReSleep = 0; 9894 // Assume that everything is good to begin with. If something is not working, 9895 // we will detect that when we start sending questions. 9896 m->p->v4answers = 1; 9897 m->p->v6answers = 1; 9898 m->p->DNSTrigger = 0; 9899 m->p->LastConfigGeneration = 0; 9900 9901#if APPLE_OSX_mDNSResponder 9902 uuid_generate(m->asl_uuid); 9903#endif 9904 9905 m->AutoTunnelRelayAddr = zerov6Addr; 9906 9907 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); 9908 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6); 9909 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL); 9910 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL); 9911 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); 9912 NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL); 9913 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix) 9914 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); } 9915 9916 err = WatchForNetworkChanges(m); 9917 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); } 9918 9919#if 0 // <rdar://problem/6751656> 9920 err = WatchForPMChanges(m); 9921 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); } 9922#endif 9923 9924 err = WatchForSysEvents(m); 9925 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); } 9926 9927 mDNSs32 utc = mDNSPlatformUTC(); 9928 m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); 9929 UpdateInterfaceList(m, utc); 9930 SetupActiveInterfaces(m, utc); 9931 9932 // Explicitly ensure that our Keychain operations utilize the system domain. 9933#ifndef NO_SECURITYFRAMEWORK 9934 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); 9935#endif 9936 9937 mDNS_Lock(m); 9938 SetDomainSecrets(m); 9939 SetLocalDomains(); 9940 mDNS_Unlock(m); 9941 9942#ifndef NO_SECURITYFRAMEWORK 9943 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m); 9944 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); } 9945#endif 9946 9947#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED 9948 LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support"); 9949#else 9950 IOPMConnection c; 9951 IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c); 9952 if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr); 9953 else 9954 { 9955 iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged); 9956 if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr); 9957 else 9958 { 9959#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 9960 IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue()); 9961 LogInfo("IOPMConnectionSetDispatchQueue is now running"); 9962#else 9963 iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 9964 if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr); 9965 LogInfo("IOPMConnectionScheduleWithRunLoop is now running"); 9966#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ 9967 } 9968 } 9969 m->p->IOPMConnection = iopmerr ? mDNSNULL : c; 9970 if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below 9971#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements 9972 { 9973 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier); 9974 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); } 9975 else 9976 { 9977#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 9978 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue()); 9979#else 9980 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); 9981#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */ 9982 } 9983 } 9984 9985#if APPLE_OSX_mDNSResponder 9986 // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind 9987 // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better) 9988 // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them 9989 // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop 9990 if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } 9991 else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } 9992 else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } 9993 else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; } 9994 else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; } 9995 else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; } 9996 else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; } 9997 else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; } 9998 else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; } 9999 else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; } 10000 else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; } 10001 LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d", 10002 HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures); 10003#endif // APPLE_OSX_mDNSResponder 10004 10005 // Currently this is not defined. SSL code will eventually fix this. If it becomes 10006 // critical, we will define this to workaround the bug in SSL. 10007#ifdef __SSL_NEEDS_SERIALIZATION__ 10008 SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL); 10009#else 10010 SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 10011#endif 10012 if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL"); 10013 10014 mDNSMacOSXUpdateEtcHosts(m); 10015 SetupLocalHostRecords(m); 10016 CUPInit(m); 10017 10018 return(mStatus_NoError); 10019} 10020 10021mDNSexport mStatus mDNSPlatformInit(mDNS *const m) 10022{ 10023#if MDNS_NO_DNSINFO 10024 LogMsg("Note: Compiled without Apple-specific Split-DNS support"); 10025#endif 10026 10027 // Adding interfaces will use this flag, so set it now. 10028 m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses; 10029 10030#if APPLE_OSX_mDNSResponder 10031 m->SPSBrowseCallback = UpdateSPSStatus; 10032#endif // APPLE_OSX_mDNSResponder 10033 10034 mStatus result = mDNSPlatformInit_setup(m); 10035 10036 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already 10037 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately 10038 if (result == mStatus_NoError) 10039 { 10040 mDNSCoreInitComplete(m, mStatus_NoError); 10041 10042#if !NO_D2D 10043 // We only initialize if mDNSCore successfully initialized. 10044 if (D2DInitialize) 10045 { 10046 D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ; 10047 if (ds != kD2DSuccess) 10048 LogMsg("D2DInitialiize failed: %d", ds); 10049 else 10050 LogMsg("D2DInitialize succeeded"); 10051 } 10052#endif // ! NO_D2D 10053 10054 } 10055 result = DNSSECCryptoInit(m); 10056 return(result); 10057} 10058 10059mDNSexport void mDNSPlatformClose(mDNS *const m) 10060{ 10061 if (m->p->PowerConnection) 10062 { 10063#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 10064 IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL); 10065#else 10066 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); 10067#endif 10068 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call 10069 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually: 10070 IODeregisterForSystemPower(&m->p->PowerNotifier); 10071 IOServiceClose ( m->p->PowerConnection); 10072 IONotificationPortDestroy ( m->p->PowerPortRef); 10073 m->p->PowerConnection = 0; 10074 } 10075 10076 if (m->p->Store) 10077 { 10078#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 10079 if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL)) 10080 LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed"); 10081#else 10082 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); 10083 CFRunLoopSourceInvalidate(m->p->StoreRLS); 10084 CFRelease(m->p->StoreRLS); 10085 m->p->StoreRLS = NULL; 10086#endif 10087 CFRelease(m->p->Store); 10088 m->p->Store = NULL; 10089 } 10090 10091 if (m->p->PMRLS) 10092 { 10093 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); 10094 CFRunLoopSourceInvalidate(m->p->PMRLS); 10095 CFRelease(m->p->PMRLS); 10096 m->p->PMRLS = NULL; 10097 } 10098 10099 if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; } 10100 10101#if !NO_D2D 10102 if (D2DTerminate) 10103 { 10104 D2DStatus ds = D2DTerminate(); 10105 if (ds != kD2DSuccess) 10106 LogMsg("D2DTerminate failed: %d", ds); 10107 else 10108 LogMsg("D2DTerminate succeeded"); 10109 } 10110#endif // ! NO_D2D 10111 10112 mDNSs32 utc = mDNSPlatformUTC(); 10113 MarkAllInterfacesInactive(m, utc); 10114 ClearInactiveInterfaces(m, utc); 10115 CloseSocketSet(&m->p->permanentsockets); 10116 10117#if APPLE_OSX_mDNSResponder 10118 // clean up tunnels 10119 while (m->TunnelClients) 10120 { 10121 ClientTunnel *cur = m->TunnelClients; 10122 LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c); 10123 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); 10124 AutoTunnelSetKeys(cur, mDNSfalse); 10125 m->TunnelClients = cur->next; 10126 freeL("ClientTunnel", cur); 10127 } 10128 10129 if (AnonymousRacoonConfig) 10130 { 10131 AnonymousRacoonConfig = mDNSNULL; 10132 LogInfo("mDNSPlatformClose: Deconfiguring autotunnel"); 10133 (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL); 10134 } 10135#endif // APPLE_OSX_mDNSResponder 10136} 10137 10138#if COMPILER_LIKES_PRAGMA_MARK 10139#pragma mark - 10140#pragma mark - General Platform Support Layer functions 10141#endif 10142 10143mDNSexport mDNSu32 mDNSPlatformRandomNumber(void) 10144{ 10145 return(arc4random()); 10146} 10147 10148mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000; 10149mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0; 10150 10151mDNSexport mStatus mDNSPlatformTimeInit(void) 10152{ 10153 // Notes: Typical values for mach_timebase_info: 10154 // tbi.numer = 1000 million 10155 // tbi.denom = 33 million 10156 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds; 10157 // numer / denom = nanoseconds per hardware clock tick (e.g. 30); 10158 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033) 10159 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333) 10160 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds 10161 // 10162 // Arithmetic notes: 10163 // tbi.denom is at least 1, and not more than 2^32-1. 10164 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t. 10165 // tbi.denom is at least 1, and not more than 2^32-1. 10166 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9. 10167 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz, 10168 // which is unlikely on any current or future Macintosh. 10169 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz. 10170 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code. 10171 struct mach_timebase_info tbi; 10172 kern_return_t result = mach_timebase_info(&tbi); 10173 if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer; 10174 return(result); 10175} 10176 10177mDNSexport mDNSs32 mDNSPlatformRawTime(void) 10178{ 10179 if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); } 10180 10181 static uint64_t last_mach_absolute_time = 0; 10182 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display 10183 uint64_t this_mach_absolute_time = mach_absolute_time(); 10184 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0) 10185 { 10186 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time); 10187 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time); 10188 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug() 10189 last_mach_absolute_time = this_mach_absolute_time; 10190 // Note: This bug happens all the time on 10.3 10191 NotifyOfElusiveBug("mach_absolute_time went backwards!", 10192 "This error occurs from time to time, often on newly released hardware, " 10193 "and usually the exact cause is different in each instance.\r\r" 10194 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” " 10195 "and assign it to Radar Component “Kernel” Version “X”."); 10196 } 10197 last_mach_absolute_time = this_mach_absolute_time; 10198 10199 return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor)); 10200} 10201 10202mDNSexport mDNSs32 mDNSPlatformUTC(void) 10203{ 10204 return time(NULL); 10205} 10206 10207// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves 10208mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; } 10209mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; } 10210mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); } 10211mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); } 10212mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); } 10213mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); } 10214mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); } 10215mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); } 10216mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *)) 10217{ 10218 return (qsort(base, nel, width, compar)); 10219} 10220#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING) 10221mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); } 10222#endif 10223mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); } 10224 10225mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason) 10226{ 10227 if (allowSleep && m->p->IOPMAssertion) 10228 { 10229 LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__); 10230 IOPMAssertionRelease(m->p->IOPMAssertion); 10231 m->p->IOPMAssertion = 0; 10232 } 10233 else if (!allowSleep) 10234 { 10235#ifdef kIOPMAssertionTypeNoIdleSleep 10236 if (m->p->IOPMAssertion) 10237 { 10238 IOPMAssertionRelease(m->p->IOPMAssertion); 10239 m->p->IOPMAssertion = 0; 10240 } 10241 10242 CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : ""); 10243 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion); 10244 if (assertionName) CFRelease(assertionName); 10245 LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__); 10246#endif 10247 } 10248} 10249 10250mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration) 10251{ 10252 mDNSu32 ifindex; 10253 10254 // Sanity check 10255 ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue); 10256 if (ifindex <= 0) 10257 { 10258 LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex); 10259 return; 10260 } 10261 mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration); 10262} 10263 10264mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) 10265{ 10266 NetworkInterfaceInfoOSX *info; 10267 10268 if (InterfaceID == mDNSInterface_P2P) 10269 return mDNStrue; 10270 10271 if ( (InterfaceID == mDNSInterface_Any) 10272 || (InterfaceID == mDNSInterfaceMark) 10273 || (InterfaceID == mDNSInterface_LocalOnly) 10274 || (InterfaceID == mDNSInterface_Unicast)) 10275 return mDNSfalse; 10276 10277 info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID); 10278 if (info == NULL) 10279 { 10280 // this log message can print when operations are stopped on an interface that has gone away 10281 LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID); 10282 return mDNSfalse; 10283 } 10284 10285 return (mDNSBool) info->D2DInterface; 10286} 10287 10288// Filter records send over P2P (D2D) type interfaces 10289// Note that the terms P2P and D2D are used synonymously in the current code and comments. 10290mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf) 10291{ 10292 // For an explicit match to a valid interface ID, return true. 10293 if (rr->resrec.InterfaceID == intf->InterfaceID) 10294 return mDNStrue; 10295 10296 // Only filtering records for D2D type interfaces, return true for all other interface types. 10297 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID)) 10298 return mDNStrue; 10299 10300 // If it's an AWDL interface the record must be explicitly marked to include AWDL. 10301 if (intf->InterfaceID == AWDLInterfaceID) 10302 { 10303 if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P) 10304 return mDNStrue; 10305 else 10306 return mDNSfalse; 10307 } 10308 10309 // Send record if it is explicitly marked to include all other P2P type interfaces. 10310 if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P) 10311 return mDNStrue; 10312 10313 // Don't send the record over this interface. 10314 return mDNSfalse; 10315} 10316 10317// Filter questions send over P2P (D2D) type interfaces. 10318mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf) 10319{ 10320 // For an explicit match to a valid interface ID, return true. 10321 if (q->InterfaceID == intf->InterfaceID) 10322 return mDNStrue; 10323 10324 // Only filtering questions for D2D type interfaces 10325 if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID)) 10326 return mDNStrue; 10327 10328 // If it's an AWDL interface the question must be explicitly marked to include AWDL. 10329 if (intf->InterfaceID == AWDLInterfaceID) 10330 { 10331 if (q->flags & kDNSServiceFlagsIncludeAWDL) 10332 return mDNStrue; 10333 else 10334 return mDNSfalse; 10335 } 10336 10337 // Sent question if it is explicitly marked to include all other P2P type interfaces. 10338 if (q->flags & kDNSServiceFlagsIncludeP2P) 10339 return mDNStrue; 10340 10341 // Don't send the question over this interface. 10342 return mDNSfalse; 10343} 10344 10345// Returns true unless record was received over the AWDL interface and 10346// the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny 10347// with the kDNSServiceFlagsIncludeAWDL flag set. 10348mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) 10349{ 10350 if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID)) 10351 return mDNStrue; 10352 10353 if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL)) 10354 { 10355 LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query", 10356 DNSTypeName(q->qtype), q->qname.c); 10357 return mDNSfalse; 10358 } 10359 10360 return mDNStrue; 10361} 10362 10363// formating time to RFC 4034 format 10364mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize) 10365{ 10366 struct tm tmTime; 10367 time_t t = (time_t)te; 10368 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using 10369 // gmtime_r first and then use strftime 10370 gmtime_r(&t, &tmTime); 10371 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime); 10372} 10373 10374mDNSexport mDNSs32 mDNSPlatformGetPID() 10375{ 10376 return getpid(); 10377} 10378 10379// Schedule a function asynchronously on the main queue 10380mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func) 10381{ 10382 // KQueueLock/Unlock is used for two purposes 10383 // 10384 // 1. We can't be running along with the KQueue thread and hence acquiring the lock 10385 // serializes the access to the "core" 10386 // 10387 // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes 10388 // up and calls udsserver_idle which schedules the messages across the uds socket. 10389 // If "func" delivers something to the uds socket from the dispatch thread, it will 10390 // not be delivered immediately if not for the Unlock. 10391 dispatch_async(dispatch_get_main_queue(), ^{ 10392 KQueueLock(m); 10393 func(m, context); 10394 KQueueUnlock(m, "mDNSPlatformDispatchAsync"); 10395#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM 10396 // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop 10397 // to handle any message that "func" might deliver. 10398 TriggerEventCompletion(); 10399#endif 10400 }); 10401} 10402 10403// definitions for device-info record construction 10404#define DEVINFO_MODEL "model=" 10405#define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL) 10406 10407#define OSX_VER "osxvers=" 10408#define OSX_VER_LEN strlen(OSX_VER) 10409#define VER_NUM_LEN 2 // 2 digits of version number added to base string 10410 10411// Bytes available in TXT record for model name after subtracting space for other 10412// fixed size strings and their length bytes. 10413#define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1)) 10414 10415// Initialize device-info TXT record contents and return total length of record data. 10416mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr) 10417{ 10418 mDNSu8 *bufferStart = ptr; 10419 mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN; 10420 10421 *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string 10422 ptr++; 10423 mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN); 10424 ptr += DEVINFO_MODEL_LEN; 10425 mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len); 10426 ptr += len; 10427 10428 // only include this string for OSX 10429 if (OSXVers) 10430 { 10431 char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf 10432 *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte 10433 ptr++; 10434 mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN); 10435 ptr += OSX_VER_LEN; 10436 // convert version number to ASCII, add 1 for terminating null byte written by snprintf() 10437 snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers); 10438 mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN); 10439 ptr += VER_NUM_LEN; 10440 } 10441 10442 return (ptr - bufferStart); 10443} 10444