1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil -*-
3 * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <mach/mach.h>
19 #include <mach/mach_error.h>
20 #include <sys/types.h>
27 #include <launch_priv.h> // for launch_socket_service_check_in()
29 #include <sys/event.h>
32 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
35 #include <TargetConditionals.h>
38 #include "DNSCommon.h"
39 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
41 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
42 #include "xpc_services.h"
43 #include "xpc_service_dns_proxy.h"
44 #include "xpc_service_log_utility.h"
46 #include "posix_utilities.h" // for getLocalTimestamp()
48 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
52 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
53 #include "dnssd_server.h"
56 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
57 #include "mdns_managed_defaults.h"
58 #include "QuerierSupport.h"
61 // Used on OSX(10.11.x onwards) for manipulating mDNSResponder program arguments
62 #if APPLE_OSX_mDNSResponder
63 // plist file to read the user's preferences
64 #define kProgramArguments CFSTR("com.apple.mDNSResponder")
65 // possible arguments for external customers
66 #define kPreferencesKey_DebugLogging CFSTR("DebugLogging")
67 #define kPreferencesKey_UnicastPacketLogging CFSTR("UnicastPacketLogging")
68 #define kPreferencesKey_AlwaysAppendSearchDomains CFSTR("AlwaysAppendSearchDomains")
69 #define kPreferencesKey_EnableAllowExpired CFSTR("EnableAllowExpired")
70 #define kPreferencesKey_NoMulticastAdvertisements CFSTR("NoMulticastAdvertisements")
71 #define kPreferencesKey_StrictUnicastOrdering CFSTR("StrictUnicastOrdering")
72 #define kPreferencesKey_OfferSleepProxyService CFSTR("OfferSleepProxyService")
73 #define kPreferencesKey_UseInternalSleepProxy CFSTR("UseInternalSleepProxy")
75 #if ENABLE_BLE_TRIGGERED_BONJOUR
76 #define kPreferencesKey_EnableBLEBasedDiscovery CFSTR("EnableBLEBasedDiscovery")
77 #define kPreferencesKey_DefaultToBLETriggered CFSTR("DefaultToBLETriggered")
78 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
80 #if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
81 #define kPreferencesKey_PreallocateCacheMemory CFSTR("PreallocateCacheMemory")
83 #define kPreferencesKey_PQWorkaroundThreshold CFSTR("PQWorkaroundThreshold")
86 //*************************************************************************************************************
87 #if COMPILER_LIKES_PRAGMA_MARK
88 #pragma mark - Globals
91 static mDNS_PlatformSupport PlatformStorage
;
93 // Start off with a default cache of 32K (136 records of 240 bytes each)
94 // Each time we grow the cache we add another 136 records
95 // 136 * 240 = 32640 bytes.
96 // This fits in eight 4kB pages, with 128 bytes spare for memory block headers and similar overhead
97 #define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord))
98 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
99 struct CompileTimeAssertionChecks_RR_CACHE_SIZE
{ char a
[(RR_CACHE_SIZE
>= 136) ? 1 : -1]; };
100 #define kRRCacheGrowSize (sizeof(CacheEntity) * RR_CACHE_SIZE)
103 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
104 mDNSlocal
void PrepareForIdle(void *m_param
);
105 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
106 static mach_port_t signal_port
= MACH_PORT_NULL
;
107 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
109 static dnssd_sock_t
*launchd_fds
= mDNSNULL
;
110 static size_t launchd_fds_count
= 0;
112 static mDNSBool NoMulticastAdvertisements
= mDNSfalse
; // By default, advertise addresses (& other records) via multicast
114 extern mDNSBool StrictUnicastOrdering
;
115 extern mDNSBool AlwaysAppendSearchDomains
;
116 extern mDNSBool EnableAllowExpired
;
117 mDNSexport
void INFOCallback(void);
118 mDNSexport
void dump_state_to_fd(int fd
);
120 #if ENABLE_BLE_TRIGGERED_BONJOUR
121 extern mDNSBool EnableBLEBasedDiscovery
;
122 extern mDNSBool DefaultToBLETriggered
;
123 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
125 #if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
126 static mDNSBool PreallocateCacheMemory
= mDNSfalse
;
129 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
130 #define kRRCacheMemoryLimit 1000000 // For now, we limit the cache to at most 1MB on iOS devices.
133 // We keep a list of client-supplied event sources in KQSocketEventSource records
134 typedef struct KQSocketEventSource
136 struct KQSocketEventSource
*next
;
139 udsEventCallback callback
;
141 } KQSocketEventSource
;
143 static KQSocketEventSource
*gEventSources
;
145 //*************************************************************************************************************
146 #if COMPILER_LIKES_PRAGMA_MARK
148 #pragma mark - General Utility Functions
151 #if MDNS_MALLOC_DEBUGGING
152 void mDNSPlatformValidateLists()
154 mDNS
*const m
= &mDNSStorage
;
156 KQSocketEventSource
*k
;
157 for (k
= gEventSources
; k
; k
=k
->next
)
158 if (k
->next
== (KQSocketEventSource
*)~0 || k
->fd
< 0)
159 LogMemCorruption("gEventSources: %p is garbage (%d)", k
, k
->fd
);
161 // Check platform-layer lists
162 NetworkInterfaceInfoOSX
*i
;
163 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
164 if (i
->next
== (NetworkInterfaceInfoOSX
*)~0 || !i
->m
|| i
->m
== (mDNS
*)~0)
165 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i
, i
->ifinfo
.ifname
);
168 for (t
= m
->TunnelClients
; t
; t
=t
->next
)
169 if (t
->next
== (ClientTunnel
*)~0 || t
->dstname
.c
[0] > 63)
170 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t
, t
->dstname
.c
[0]);
172 #endif // MDNS_MALLOC_DEBUGGING
174 //*************************************************************************************************************
177 mDNSexport
void RecordUpdatedNiceLabel(mDNSs32 delay
)
179 mDNSStorage
.p
->NotifyUser
= NonZeroTime(mDNSStorage
.timenow
+ delay
);
182 mDNSlocal
void mDNSPreferencesSetNames(int key
, domainlabel
*old
, domainlabel
*new)
184 mDNS
*const m
= &mDNSStorage
;
185 domainlabel
*prevold
, *prevnew
;
188 case kmDNSComputerName
:
189 case kmDNSLocalHostName
:
190 if (key
== kmDNSComputerName
)
192 prevold
= &m
->p
->prevoldnicelabel
;
193 prevnew
= &m
->p
->prevnewnicelabel
;
197 prevold
= &m
->p
->prevoldhostlabel
;
198 prevnew
= &m
->p
->prevnewhostlabel
;
200 // There are a few cases where we need to invoke the helper.
202 // 1. If the "old" label and "new" label are not same, it means there is a conflict. We need
203 // to invoke the helper so that it pops up a dialogue to inform the user about the
206 // 2. If the "old" label and "new" label are same, it means the user has set the host/nice label
207 // through the preferences pane. We may have to inform the helper as it may have popped up
208 // a dialogue previously (due to a conflict) and it needs to suppress it now. We can avoid invoking
209 // the helper in this case if the previous values (old and new) that we told helper last time
210 // are same. If the previous old and new values are same, helper does not care.
212 // Note: "new" can be NULL when we have repeated conflicts and we are asking helper to give up. "old"
213 // is not called with NULL today, but this makes it future proof.
214 if (!old
|| !new || !SameDomainLabelCS(old
->c
, new->c
) ||
215 !SameDomainLabelCS(old
->c
, prevold
->c
) ||
216 !SameDomainLabelCS(new->c
, prevnew
->c
))
218 // Work around bug radar:21397654
219 #ifndef __clang_analyzer__
229 mDNSPreferencesSetName(key
, old
, new);
233 LogInfo("mDNSPreferencesSetNames not invoking helper %s %#s, %s %#s, old %#s, new %#s",
234 (key
== kmDNSComputerName
? "prevoldnicelabel" : "prevoldhostlabel"), prevold
->c
,
235 (key
== kmDNSComputerName
? "prevnewnicelabel" : "prevnewhostlabel"), prevnew
->c
,
240 LogMsg("mDNSPreferencesSetNames: unrecognized key: %d", key
);
245 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
247 if (result
== mStatus_NoError
)
249 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
250 LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
251 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
252 RecordUpdatedNiceLabel(mDNSPlatformOneSecond
);
254 else if (result
== mStatus_NameConflict
)
256 LogInfo("Local Hostname conflict for \"%#s.local\"", m
->hostlabel
.c
);
257 if (!m
->p
->HostNameConflict
) m
->p
->HostNameConflict
= NonZeroTime(m
->timenow
);
258 else if (m
->timenow
- m
->p
->HostNameConflict
> 60 * mDNSPlatformOneSecond
)
260 // Tell the helper we've given up
261 mDNSPreferencesSetNames(kmDNSLocalHostName
, &m
->p
->userhostlabel
, NULL
);
264 else if (result
== mStatus_GrowCache
)
266 // Allocate another chunk of cache storage
267 static unsigned int allocated
= 0;
268 #if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
269 if (allocated
>= kRRCacheMemoryLimit
) return; // For now we limit the cache to at most 1MB on iOS devices
271 allocated
+= kRRCacheGrowSize
;
272 // LogMsg("GrowCache %d * %d = %d; total so far %6u", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE, allocated);
273 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
274 //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
275 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
277 else if (result
== mStatus_ConfigChanged
)
279 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
280 mDNSPreferencesSetNames(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
281 mDNSPreferencesSetNames(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
283 // Then we call into the UDS daemon code, to let it do the same
284 udsserver_handle_configchange(m
);
289 //*************************************************************************************************************
290 #if COMPILER_LIKES_PRAGMA_MARK
292 #pragma mark - Startup, shutdown, and supporting code
295 mDNSlocal
void ExitCallback(int sig
)
298 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, PUB_S
" stopping", mDNSResponderVersionString
);
300 if (udsserver_exit() < 0)
302 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "ExitCallback: udsserver_exit failed");
305 debugf("ExitCallback: mDNS_StartExit");
306 mDNS_StartExit(&mDNSStorage
);
309 #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
311 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
312 mDNSlocal
void HandleSIG(int sig
)
314 kern_return_t status
;
315 mach_msg_header_t header
;
317 // WARNING: can't call syslog or fprintf from signal handler
318 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
319 header
.msgh_remote_port
= signal_port
;
320 header
.msgh_local_port
= MACH_PORT_NULL
;
321 header
.msgh_size
= sizeof(header
);
322 header
.msgh_id
= sig
;
324 status
= mach_msg(&header
, MACH_SEND_MSG
| MACH_SEND_TIMEOUT
, header
.msgh_size
,
325 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
327 if (status
!= MACH_MSG_SUCCESS
)
329 if (status
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
330 if (sig
== SIGTERM
|| sig
== SIGINT
) exit(-1);
334 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
336 mDNSexport
void dump_state_to_fd(int fd
)
338 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
339 mDNS
*const m
= &mDNSStorage
;
344 mDNSs32 utc
= mDNSPlatformUTC();
345 const mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
346 NetworkInterfaceInfoOSX
*i
;
347 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
351 char timestamp
[64]; // 64 is enough to store the UTC timestmp
353 LogToFD(fd
, "---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString
, OSXVers
? "OSXVers" : "iOSVers", OSXVers
? OSXVers
: iOSVers
);
354 getLocalTimestamp(timestamp
, sizeof(timestamp
));
355 LogToFD(fd
, "Date: %s", timestamp
);
356 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "---- BEGIN STATE LOG ---- (" PUB_S
")", timestamp
);
358 udsserver_info_dump_to_fd(fd
);
360 LogToFD(fd
, "----- Platform Timers -----");
361 LogTimerToFD(fd
, "m->NextCacheCheck ", mDNSStorage
.NextCacheCheck
);
362 LogTimerToFD(fd
, "m->NetworkChanged ", mDNSStorage
.NetworkChanged
);
363 LogTimerToFD(fd
, "m->p->NotifyUser ", mDNSStorage
.p
->NotifyUser
);
364 LogTimerToFD(fd
, "m->p->HostNameConflict ", mDNSStorage
.p
->HostNameConflict
);
365 LogTimerToFD(fd
, "m->p->KeyChainTimer ", mDNSStorage
.p
->KeyChainTimer
);
367 log_dnsproxy_info_to_fd(fd
, &mDNSStorage
);
369 LogToFD(fd
, "----- KQSocketEventSources -----");
370 if (!gEventSources
) LogToFD(fd
, "<None>");
373 KQSocketEventSource
*k
;
374 for (k
= gEventSources
; k
; k
=k
->next
)
375 LogToFD(fd
, "%3d %s %s", k
->fd
, k
->kqs
.KQtask
, k
->fd
== mDNSStorage
.uds_listener_skt
? "Listener for incoming UDS clients" : " ");
378 LogToFD(fd
, "------ Network Interfaces ------");
379 if (!mDNSStorage
.p
->InterfaceList
) LogToFD(fd
, "<None>");
382 LogToFD(fd
, " Struct addr Registered MAC BSSID Interface Address");
383 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
385 // Allow six characters for interface name, for names like "vmnet8"
387 LogToFD(fd
, "%p %2ld, %p, %s %-6s %.6a %.6a %#-14a dormant for %d seconds",
388 i
, i
->ifinfo
.InterfaceID
, i
->Registered
,
389 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, &i
->ifinfo
.MAC
, &i
->BSSID
,
390 &i
->ifinfo
.ip
, utc
- i
->LastSeen
);
393 const CacheRecord
*sps
[3];
394 FindSPSInCache(&mDNSStorage
, &i
->ifinfo
.NetWakeBrowse
, sps
);
395 LogToFD(fd
, "%p %2ld, %p, %s %-6s %.6a %.6a %s %s %s %s %s %s %#a",
396 i
, i
->ifinfo
.InterfaceID
, i
->Registered
,
397 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, &i
->ifinfo
.MAC
, &i
->BSSID
,
398 i
->ifinfo
.InterfaceActive
? "Active" : " ",
399 i
->ifinfo
.IPv4Available
? "v4" : " ",
400 i
->ifinfo
.IPv6Available
? "v6" : " ",
401 i
->ifinfo
.Advertise
? "A" : " ",
402 i
->ifinfo
.McastTxRx
? "M" : " ",
403 !(i
->ifinfo
.InterfaceActive
&& i
->ifinfo
.NetWake
) ? " " : !sps
[0] ? "p" : "P",
406 // Only print the discovered sleep proxies once for the lead/active interface of an interface set.
407 if (i
== i
->Registered
&& (sps
[0] || sps
[1] || sps
[2]))
409 LogToFD(fd
, " Sleep Proxy Metric Name");
410 if (sps
[0]) LogToFD(fd
, " %13d %#s", SPSMetric(sps
[0]->resrec
.rdata
->u
.name
.c
), sps
[0]->resrec
.rdata
->u
.name
.c
);
411 if (sps
[1]) LogToFD(fd
, " %13d %#s", SPSMetric(sps
[1]->resrec
.rdata
->u
.name
.c
), sps
[1]->resrec
.rdata
->u
.name
.c
);
412 if (sps
[2]) LogToFD(fd
, " %13d %#s", SPSMetric(sps
[2]->resrec
.rdata
->u
.name
.c
), sps
[2]->resrec
.rdata
->u
.name
.c
);
418 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
419 LogToFD(fd
, "----------- DNS Services -----------");
421 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
424 mdns_dns_service_manager_iterate(manager
,
425 ^ bool (const mdns_dns_service_t service
)
427 char *const desc
= mdns_copy_description(service
);
428 LogToFD(fd
, "%s", desc
? desc
: "<missing description>");
435 LogToFD(fd
, "--------- DNS Servers(%d) ----------", CountOfUnicastDNSServers(&mDNSStorage
));
436 if (!mDNSStorage
.DNSServers
) LogToFD(fd
, "<None>");
439 for (s
= mDNSStorage
.DNSServers
; s
; s
= s
->next
)
441 NetworkInterfaceInfoOSX
*ifx
= IfindexToInterfaceInfoOSX(s
->interface
);
442 LogToFD(fd
, "DNS Server %##s %s%s%#a:%d %d %s %d %d %sv4 %sv6 %scell %sexp %sconstrained %sCLAT46",
443 s
->domain
.c
, ifx
? ifx
->ifinfo
.ifname
: "", ifx
? " " : "", &s
->addr
, mDNSVal16(s
->port
),
444 s
->penaltyTime
? (s
->penaltyTime
- mDNS_TimeNow(&mDNSStorage
)) : 0, DNSScopeToString(s
->scopeType
),
445 s
->timeout
, s
->resGroupID
,
446 s
->usableA
? "" : "!",
447 s
->usableAAAA
? "" : "!",
448 s
->isCell
? "" : "!",
449 s
->isExpensive
? "" : "!",
450 s
->isConstrained
? "" : "!",
451 s
->isCLAT46
? "" : "!");
454 #endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
456 LogToFD(fd
, "v4answers %d", mDNSStorage
.p
->v4answers
);
457 LogToFD(fd
, "v6answers %d", mDNSStorage
.p
->v6answers
);
458 LogToFD(fd
, "Last DNS Trigger: %d ms ago", (now
- mDNSStorage
.p
->DNSTrigger
));
460 #if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
461 LogToFD(fd
, "-------- Interface Monitors --------");
462 const CFIndex n
= m
->p
->InterfaceMonitors
? CFArrayGetCount(m
->p
->InterfaceMonitors
) : 0;
465 for (CFIndex j
= 0; j
< n
; j
++)
467 mdns_interface_monitor_t monitor
= (mdns_interface_monitor_t
) CFArrayGetValueAtIndex(m
->p
->InterfaceMonitors
, j
);
468 char *description
= mdns_copy_description(monitor
);
471 LogToFD(fd
, "%s", description
);
476 LogToFD(fd
, "monitor %p (no description)", monitor
);
482 LogToFD(fd
, "No interface monitors");
486 LogToFD(fd
, "--------- Mcast Resolvers ----------");
487 if (!mDNSStorage
.McastResolvers
) LogToFD(fd
, "<None>");
490 for (mr
= mDNSStorage
.McastResolvers
; mr
; mr
= mr
->next
)
491 LogToFD(fd
, "Mcast Resolver %##s timeout %u", mr
->domain
.c
, mr
->timeout
);
494 LogToFD(fd
, "------------ Hostnames -------------");
495 if (!mDNSStorage
.Hostnames
) LogToFD(fd
, "<None>");
499 for (hi
= mDNSStorage
.Hostnames
; hi
; hi
= hi
->next
)
501 LogToFD(fd
, "%##s v4 %d %s", hi
->fqdn
.c
, hi
->arv4
.state
, ARDisplayString(&mDNSStorage
, &hi
->arv4
));
502 LogToFD(fd
, "%##s v6 %d %s", hi
->fqdn
.c
, hi
->arv6
.state
, ARDisplayString(&mDNSStorage
, &hi
->arv6
));
506 LogToFD(fd
, "--------------- FQDN ---------------");
507 if (!mDNSStorage
.FQDN
.c
[0]) LogToFD(fd
, "<None>");
510 LogToFD(fd
, "%##s", mDNSStorage
.FQDN
.c
);
513 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
517 // getLocalTimestamp(timestamp, sizeof(timestamp));
518 LogToFD(fd
, "Date: %s", timestamp
);
519 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "---- END STATE LOG ---- (" PUB_S
")", timestamp
);
520 LogToFD(fd
, "---- END STATE LOG ---- %s %s %d", mDNSResponderVersionString
, OSXVers
? "OSXVers" : "iOSVers", OSXVers
? OSXVers
: iOSVers
);
523 mDNSexport
void INFOCallback(void)
525 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_WARNING
,
526 "Sending SIGINFO to mDNSResponder daemon is deprecated. To trigger state dump, please use 'dns-sd -O', enter 'dns-sd -h' for more information");
529 // Writes the state out to the dynamic store and also affects the ASL filter level
530 mDNSexport
void UpdateDebugState()
535 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
538 LogMsg("UpdateDebugState: Could not create dict");
542 CFNumberRef numOne
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &one
);
545 LogMsg("UpdateDebugState: Could not create CFNumber one");
548 CFNumberRef numZero
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &zero
);
551 LogMsg("UpdateDebugState: Could not create CFNumber zero");
556 if (mDNS_LoggingEnabled
)
557 CFDictionarySetValue(dict
, CFSTR("VerboseLogging"), numOne
);
559 CFDictionarySetValue(dict
, CFSTR("VerboseLogging"), numZero
);
561 if (mDNS_PacketLoggingEnabled
)
562 CFDictionarySetValue(dict
, CFSTR("PacketLogging"), numOne
);
564 CFDictionarySetValue(dict
, CFSTR("PacketLogging"), numZero
);
566 if (mDNS_McastLoggingEnabled
)
567 CFDictionarySetValue(dict
, CFSTR("McastLogging"), numOne
);
569 CFDictionarySetValue(dict
, CFSTR("McastLogging"), numZero
);
571 if (mDNS_McastTracingEnabled
)
572 CFDictionarySetValue(dict
, CFSTR("McastTracing"), numOne
);
574 CFDictionarySetValue(dict
, CFSTR("McastTracing"), numZero
);
578 mDNSDynamicStoreSetConfig(kmDNSDebugState
, mDNSNULL
, dict
);
584 #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
586 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
588 (void)port
; // Unused
589 (void)size
; // Unused
590 (void)info
; // Unused
591 mach_msg_header_t
*msg_header
= (mach_msg_header_t
*)msg
;
592 mDNS
*const m
= &mDNSStorage
;
594 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
596 switch(msg_header
->msgh_id
)
602 LogMsg("SIGHUP: Purge cache");
604 FORALL_CACHERECORDS(slot
, cg
, rr
)
606 mDNS_PurgeCacheResourceRecord(m
, rr
);
608 // Restart unicast and multicast queries
609 mDNSCoreRestartQueries(m
);
613 case SIGTERM
: ExitCallback(msg_header
->msgh_id
); break;
614 case SIGINFO
: INFOCallback(); break;
616 #if APPLE_OSX_mDNSResponder
617 mDNS_LoggingEnabled
= 1;
618 LogMsg("SIGUSR1: Logging %s on Apple Platforms", mDNS_LoggingEnabled
? "Enabled" : "Disabled");
620 mDNS_LoggingEnabled
= mDNS_LoggingEnabled
? 0 : 1;
621 LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled
? "Enabled" : "Disabled");
623 WatchDogReportingThreshold
= mDNS_LoggingEnabled
? 50 : 250;
625 LogInfo("USR1 Logging Enabled");
628 #if APPLE_OSX_mDNSResponder
629 mDNS_PacketLoggingEnabled
= 1;
630 LogMsg("SIGUSR2: Packet Logging %s on Apple Platforms", mDNS_PacketLoggingEnabled
? "Enabled" : "Disabled");
632 mDNS_PacketLoggingEnabled
= mDNS_PacketLoggingEnabled
? 0 : 1;
633 LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled
? "Enabled" : "Disabled");
635 mDNS_McastTracingEnabled
= (mDNS_PacketLoggingEnabled
&& mDNS_McastLoggingEnabled
) ? mDNStrue
: mDNSfalse
;
636 LogInfo("SIGUSR2: Multicast Tracing is %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
639 case SIGPROF
: mDNS_McastLoggingEnabled
= mDNS_McastLoggingEnabled
? mDNSfalse
: mDNStrue
;
640 LogMsg("SIGPROF: Multicast Logging %s", mDNS_McastLoggingEnabled
? "Enabled" : "Disabled");
641 LogMcastStateInfo(mDNSfalse
, mDNStrue
, mDNStrue
);
642 mDNS_McastTracingEnabled
= (mDNS_PacketLoggingEnabled
&& mDNS_McastLoggingEnabled
) ? mDNStrue
: mDNSfalse
;
643 LogMsg("SIGPROF: Multicast Tracing is %s", mDNS_McastTracingEnabled
? "Enabled" : "Disabled");
646 case SIGTSTP
: mDNS_LoggingEnabled
= mDNS_PacketLoggingEnabled
= mDNS_McastLoggingEnabled
= mDNS_McastTracingEnabled
= mDNSfalse
;
647 LogMsg("All mDNSResponder Debug Logging/Tracing Disabled (USR1/USR2/PROF)");
651 default: LogMsg("SignalCallback: Unknown signal %d", msg_header
->msgh_id
); break;
653 KQueueUnlock("Unix Signal");
656 // MachServerName is com.apple.mDNSResponder (Supported only till 10.9.x)
657 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
661 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
662 rrcachestorage
, RR_CACHE_SIZE
,
663 !NoMulticastAdvertisements
,
664 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
668 LogMsg("Daemon start: mDNS_Init failed %d", err
);
672 #if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
673 if (PreallocateCacheMemory
)
675 const int growCount
= (kRRCacheMemoryLimit
+ kRRCacheGrowSize
- 1) / kRRCacheGrowSize
;
678 for (i
= 0; i
< growCount
; ++i
)
680 mDNS_StatusCallback(&mDNSStorage
, mStatus_GrowCache
);
685 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
686 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
687 signal_port
= CFMachPortGetPort(i_port
);
688 CFRunLoopAddSource(CFRunLoopGetMain(), i_rls
, kCFRunLoopDefaultMode
);
694 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
696 // SignalDispatch is mostly just a copy/paste of entire code block from SignalCallback above.
697 // The common code should be a subroutine, or we end up having to fix bugs in two places all the time.
698 // The same applies to mDNSDaemonInitialize, much of which is just a copy/paste of chunks
699 // of code from above. Alternatively we could remove the duplicated source code by having
700 // single routines, with the few differing parts bracketed with "#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM"
702 mDNSlocal
void SignalDispatch(dispatch_source_t source
)
704 int sig
= (int)dispatch_source_get_handle(source
);
705 mDNS
*const m
= &mDNSStorage
;
713 LogMsg("SIGHUP: Purge cache");
715 FORALL_CACHERECORDS(slot
, cg
, rr
)
717 mDNS_PurgeCacheResourceRecord(m
, rr
);
719 // Restart unicast and multicast queries
720 mDNSCoreRestartQueries(m
);
724 case SIGTERM
: ExitCallback(sig
); break;
725 case SIGINFO
: INFOCallback(); break;
726 case SIGUSR1
: mDNS_LoggingEnabled
= mDNS_LoggingEnabled
? 0 : 1;
727 LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled
? "Enabled" : "Disabled");
728 WatchDogReportingThreshold
= mDNS_LoggingEnabled
? 50 : 250;
731 case SIGUSR2
: mDNS_PacketLoggingEnabled
= mDNS_PacketLoggingEnabled
? 0 : 1;
732 LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled
? "Enabled" : "Disabled");
735 default: LogMsg("SignalCallback: Unknown signal %d", sig
); break;
737 KQueueUnlock("Unix Signal");
740 mDNSlocal
void mDNSSetupSignal(dispatch_queue_t queue
, int sig
)
742 signal(sig
, SIG_IGN
);
743 dispatch_source_t source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, sig
, 0, queue
);
747 dispatch_source_set_event_handler(source
, ^{SignalDispatch(source
);});
748 // Start processing signals
749 dispatch_resume(source
);
753 LogMsg("mDNSSetupSignal: Cannot setup signal %d", sig
);
757 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
760 dispatch_queue_t queue
= dispatch_get_main_queue();
762 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
763 rrcachestorage
, RR_CACHE_SIZE
,
764 !NoMulticastAdvertisements
,
765 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
769 LogMsg("Daemon start: mDNS_Init failed %d", err
);
773 mDNSSetupSignal(queue
, SIGHUP
);
774 mDNSSetupSignal(queue
, SIGINT
);
775 mDNSSetupSignal(queue
, SIGTERM
);
776 mDNSSetupSignal(queue
, SIGINFO
);
777 mDNSSetupSignal(queue
, SIGUSR1
);
778 mDNSSetupSignal(queue
, SIGUSR2
);
780 // Create a custom handler for doing the housekeeping work. This is either triggered
781 // by the timer or an event source
782 PlatformStorage
.custom
= dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD
, 0, 0, queue
);
783 if (PlatformStorage
.custom
== mDNSNULL
) {LogMsg("mDNSDaemonInitialize: Error creating custom source"); return -1;}
784 dispatch_source_set_event_handler(PlatformStorage
.custom
, ^{PrepareForIdle(&mDNSStorage
);});
785 dispatch_resume(PlatformStorage
.custom
);
787 // Create a timer source to trigger housekeeping work. The houskeeping work itself
788 // is done in the custom handler that we set below.
790 PlatformStorage
.timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, queue
);
791 if (PlatformStorage
.timer
== mDNSNULL
) {LogMsg("mDNSDaemonInitialize: Error creating timer source"); return -1;}
793 // As the API does not support one shot timers, we pass zero for the interval. In the custom handler, we
794 // always reset the time to the new time computed. In effect, we ignore the interval
795 dispatch_source_set_timer(PlatformStorage
.timer
, DISPATCH_TIME_NOW
, 1000ull * 1000000000, 0);
796 dispatch_source_set_event_handler(PlatformStorage
.timer
, ^{
797 dispatch_source_merge_data(PlatformStorage
.custom
, 1);
799 dispatch_resume(PlatformStorage
.timer
);
801 LogMsg("DaemonIntialize done successfully");
806 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
808 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
810 mDNSs32 now
= mDNS_TimeNow(m
);
812 // 1. If we need to set domain secrets, do so before handling the network change
814 // BTMM domains listed in DynStore Setup:/Network/BackToMyMac are added to the registration domains list,
815 // and we need to setup the associated AutoTunnel DomainAuthInfo entries before that happens.
816 if (m
->p
->KeyChainTimer
&& now
- m
->p
->KeyChainTimer
>= 0)
818 m
->p
->KeyChainTimer
= 0;
824 // 2. If we have network change events to handle, do them before calling mDNS_Execute()
826 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
827 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
828 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
829 // we then systematically lose our own looped-back packets.
830 if (m
->NetworkChanged
&& now
- m
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged();
832 if (m
->p
->RequestReSleep
&& now
- m
->p
->RequestReSleep
>= 0)
834 m
->p
->RequestReSleep
= 0;
835 mDNSPowerRequest(0, 0);
838 // 3. Call mDNS_Execute() to let mDNSCore do what it needs to do
839 mDNSs32 nextevent
= mDNS_Execute(m
);
841 if (m
->NetworkChanged
)
842 if (nextevent
- m
->NetworkChanged
> 0)
843 nextevent
= m
->NetworkChanged
;
845 if (m
->p
->KeyChainTimer
)
846 if (nextevent
- m
->p
->KeyChainTimer
> 0)
847 nextevent
= m
->p
->KeyChainTimer
;
849 if (m
->p
->RequestReSleep
)
850 if (nextevent
- m
->p
->RequestReSleep
> 0)
851 nextevent
= m
->p
->RequestReSleep
;
854 if (m
->p
->NotifyUser
)
856 if (m
->p
->NotifyUser
- now
< 0)
858 if (!SameDomainLabelCS(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
860 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
861 mDNSPreferencesSetNames(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
862 m
->p
->usernicelabel
= m
->nicelabel
;
864 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
866 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
867 mDNSPreferencesSetNames(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
868 m
->p
->HostNameConflict
= 0; // Clear our indicator, now name change has been successful
869 m
->p
->userhostlabel
= m
->hostlabel
;
871 m
->p
->NotifyUser
= 0;
874 if (nextevent
- m
->p
->NotifyUser
> 0)
875 nextevent
= m
->p
->NotifyUser
;
881 // Right now we consider *ALL* of our DHCP leases
882 // It might make sense to be a bit more selective and only consider the leases on interfaces
883 // (a) that are capable and enabled for wake-on-LAN, and
884 // (b) where we have found (and successfully registered with) a Sleep Proxy
885 // If we can't be woken for traffic on a given interface, then why keep waking to renew its lease?
886 mDNSlocal mDNSu32
DHCPWakeTime(void)
888 mDNSu32 e
= 24 * 3600; // Maximum maintenance wake interval is 24 hours
889 const CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
890 if (!now
) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed");
895 const void *pattern
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetDHCP
);
898 LogMsg("DHCPWakeTime: SCDynamicStoreKeyCreateNetworkServiceEntity failed\n");
901 CFArrayRef dhcpinfo
= CFArrayCreate(NULL
, (const void **)&pattern
, 1, &kCFTypeArrayCallBacks
);
905 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("DHCP-LEASES"), NULL
, NULL
);
908 CFDictionaryRef dict
= SCDynamicStoreCopyMultiple(store
, NULL
, dhcpinfo
);
911 ic
= CFDictionaryGetCount(dict
);
912 const void *vals
[ic
];
913 CFDictionaryGetKeysAndValues(dict
, NULL
, vals
);
915 for (j
= 0; j
< ic
; j
++)
917 const CFDictionaryRef dhcp
= (CFDictionaryRef
)vals
[j
];
920 const CFDateRef start
= DHCPInfoGetLeaseStartTime(dhcp
);
921 const CFDataRef lease
= DHCPInfoGetOptionData(dhcp
, 51); // Option 51 = IP Address Lease Time
922 if (!start
|| !lease
|| CFDataGetLength(lease
) < 4)
923 LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed "
924 "CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d",
925 j
, start
, lease
, lease
? CFDataGetLength(lease
) : 0);
928 const UInt8
*d
= CFDataGetBytePtr(lease
);
929 if (!d
) LogMsg("DHCPWakeTime: CFDataGetBytePtr %ld failed", (long)j
);
932 const mDNSu32 elapsed
= now
- CFDateGetAbsoluteTime(start
);
933 const mDNSu32 lifetime
= (mDNSs32
) ((mDNSs32
)d
[0] << 24 | (mDNSs32
)d
[1] << 16 | (mDNSs32
)d
[2] << 8 | d
[3]);
934 const mDNSu32 remaining
= lifetime
- elapsed
;
935 const mDNSu32 wake
= remaining
> 60 ? remaining
- remaining
/10 : 54; // Wake at 90% of the lease time
936 LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed
, lifetime
, remaining
, wake
);
937 if (e
> wake
) e
= wake
;
952 // We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it.
953 // For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour.
954 // If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping
955 // for a few seconds and then waking again is silly and annoying.
956 // If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease.
957 // Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still
958 // allowing us an adequate safety margin to renew our lease before we lose it.
960 mDNSlocal mDNSBool
AllowSleepNow(mDNSs32 now
)
962 mDNS
*const m
= &mDNSStorage
;
963 mDNSBool ready
= mDNSCoreReadyForSleep(m
, now
);
964 if (m
->SleepState
&& !ready
&& now
- m
->SleepLimit
< 0) return(mDNSfalse
);
967 int result
= kIOReturnSuccess
;
968 CFDictionaryRef opts
= NULL
;
970 // If the sleep request was cancelled, and we're no longer planning to sleep, don't need to
971 // do the stuff below, but we *DO* still need to acknowledge the sleep message we received.
973 LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m
->SleepLimit
- now
);
976 if (!m
->SystemWakeOnLANEnabled
|| !mDNSCoreHaveAdvertisedMulticastServices(m
))
977 LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services",
978 m
->SystemWakeOnLANEnabled
? "is" : "not",
979 mDNSCoreHaveAdvertisedMulticastServices(m
) ? "have" : "no");
982 mDNSs32 dhcp
= DHCPWakeTime();
983 LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp
);
984 mDNSNextWakeReason reason
= mDNSNextWakeReason_Null
;
985 mDNSs32 interval
= mDNSCoreIntervalToNextWake(m
, now
, &reason
) / mDNSPlatformOneSecond
;
989 reason
= mDNSNextWakeReason_DHCPLeaseRenewal
;
991 // If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of
992 // transient network problem) then schedule a wakeup in one hour to try again. Otherwise,
993 // a single SPS failure could result in a remote machine falling permanently asleep, requiring
994 // someone to go to the machine in person to wake it up again, which would be unacceptable.
995 if (!ready
&& interval
> 3600)
998 reason
= mDNSNextWakeReason_SleepProxyRegistrationRetry
;
1000 //interval = 48; // For testing
1002 #if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
1003 if (m
->p
->IOPMConnection
) // If lightweight-wake capability is available, use that
1005 CFStringRef reasonStr
;
1008 case mDNSNextWakeReason_NATPortMappingRenewal
:
1009 reasonStr
= CFSTR("NAT port mapping renewal");
1012 case mDNSNextWakeReason_RecordRegistrationRenewal
:
1013 reasonStr
= CFSTR("record registration renewal");
1016 case mDNSNextWakeReason_UpkeepWake
:
1017 reasonStr
= CFSTR("upkeep wake");
1020 case mDNSNextWakeReason_DHCPLeaseRenewal
:
1021 reasonStr
= CFSTR("DHCP lease renewal");
1024 case mDNSNextWakeReason_SleepProxyRegistrationRetry
:
1025 reasonStr
= CFSTR("sleep proxy registration retry");
1028 case mDNSNextWakeReason_Null
:
1030 reasonStr
= CFSTR("unspecified");
1033 const CFDateRef WakeDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
1034 if (!WakeDate
) LogMsg("ScheduleNextWake: CFDateCreate failed");
1037 const mDNSs32 reqs
= kIOPMSystemPowerStateCapabilityNetwork
;
1038 const CFNumberRef Requirements
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &reqs
);
1039 if (Requirements
== NULL
) LogMsg("ScheduleNextWake: CFNumberCreate failed");
1042 const void *OptionKeys
[3] = { kIOPMAckDHCPRenewWakeDate
, kIOPMAckSystemCapabilityRequirements
, kIOPMAckClientInfoKey
};
1043 const void *OptionVals
[3] = { WakeDate
, Requirements
, reasonStr
};
1044 opts
= CFDictionaryCreate(NULL
, OptionKeys
, OptionVals
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1045 if (!opts
) LogMsg("ScheduleNextWake: CFDictionaryCreate failed");
1046 CFRelease(Requirements
);
1048 CFRelease(WakeDate
);
1050 LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval
);
1052 else // else schedule the wakeup using the old API instead to
1055 // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
1056 // so we should put it back to sleep. To avoid frustrating the user, we always request at least
1057 // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep,
1058 // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine.
1062 result
= mDNSPowerRequest(1, interval
);
1064 if (result
== kIOReturnNotReady
)
1067 LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval
);
1068 // IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the
1069 // requested wake time is "too soon", but there's no API to find out what constitutes
1070 // "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady
1071 // we just have to iterate with successively longer intervals until it doesn't fail.
1072 // We preserve the value of "result" because if our original power request was deemed "too soon"
1073 // for the machine to get to sleep and wake back up again, we attempt to cancel the sleep request,
1074 // since the implication is that the system won't manage to be awake again at the time we need it.
1077 interval
+= (interval
< 20) ? 1 : ((interval
+3) / 4);
1078 r
= mDNSPowerRequest(1, interval
);
1080 while (r
== kIOReturnNotReady
);
1081 if (r
) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval
, r
, r
);
1082 else LogSPS("AllowSleepNow: Requested later wakeup in %d seconds; will also attempt IOCancelPowerChange", interval
);
1086 if (result
) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval
, result
, result
);
1087 else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval
);
1089 m
->p
->WakeAtUTC
= mDNSPlatformUTC() + interval
;
1093 m
->SleepState
= SleepState_Sleeping
;
1094 // Clear our interface list to empty state, ready to go to sleep
1095 // As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete
1096 mDNSMacOSXNetworkChanged();
1099 LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
1100 #if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
1101 (m
->p
->IOPMConnection
) ? "IOPMConnectionAcknowledgeEventWithOptions" :
1103 (result
== kIOReturnSuccess
) ? "IOAllowPowerChange" : "IOCancelPowerChange",
1104 m
->p
->SleepCookie
, ready
? "ready for sleep" : "giving up", now
, m
->SleepLimit
- now
);
1106 m
->SleepLimit
= 0; // Don't clear m->SleepLimit until after we've logged it above
1107 m
->TimeSlept
= mDNSPlatformUTC();
1109 #if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
1110 if (m
->p
->IOPMConnection
) IOPMConnectionAcknowledgeEventWithOptions(m
->p
->IOPMConnection
, (IOPMConnectionMessageToken
)m
->p
->SleepCookie
, opts
);
1113 if (result
== kIOReturnSuccess
) IOAllowPowerChange (m
->p
->PowerConnection
, m
->p
->SleepCookie
);
1114 else IOCancelPowerChange(m
->p
->PowerConnection
, m
->p
->SleepCookie
);
1116 if (opts
) CFRelease(opts
);
1120 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1122 mDNSexport
void TriggerEventCompletion()
1124 debugf("TriggerEventCompletion: Merge data");
1125 dispatch_source_merge_data(PlatformStorage
.custom
, 1);
1128 mDNSlocal
void PrepareForIdle(void *m_param
)
1131 int64_t time_offset
;
1132 dispatch_time_t dtime
;
1134 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
1136 // This is the main work loop:
1137 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
1138 // (2) Then we make sure we've delivered all waiting browse messages to our clients
1139 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
1141 debugf("PrepareForIdle: called");
1142 // Run mDNS_Execute to find out the time we next need to wake up
1143 mDNSs32 start
= mDNSPlatformRawTime();
1144 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
1145 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
1146 if (m
->DNSPushServers
!= mDNSNULL
)
1148 nextTimerEvent
= dso_idle(m
, nextTimerEvent
);
1151 mDNSs32 end
= mDNSPlatformRawTime();
1152 if (end
- start
>= WatchDogReportingThreshold
)
1154 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_WARNING
,
1155 "CustomSourceHandler: WARNING: Idle task took %d ms to complete", end
- start
);
1158 mDNSs32 now
= mDNS_TimeNow(m
);
1160 if (m
->ShutdownTime
)
1162 if (mDNSStorage
.ResourceRecords
)
1164 LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m
, mDNSStorage
.ResourceRecords
));
1165 if (mDNS_LoggingEnabled
) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
1167 if (mDNS_ExitNow(m
, now
))
1169 LogInfo("IdleLoop: mDNS_FinalExit");
1170 mDNS_FinalExit(&mDNSStorage
);
1171 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
1174 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
1175 nextTimerEvent
= m
->ShutdownTime
;
1179 if (!AllowSleepNow(now
))
1180 if (nextTimerEvent
- m
->SleepLimit
>= 0)
1181 nextTimerEvent
= m
->SleepLimit
;
1183 // Convert absolute wakeup time to a relative time from now
1184 mDNSs32 ticks
= nextTimerEvent
- now
;
1185 if (ticks
< 1) ticks
= 1;
1187 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
1193 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
1196 time_offset
= ((mDNSu32
)ticks
/ mDNSPlatformOneSecond
) * 1000000000 + (ticks
% mDNSPlatformOneSecond
) * multiplier
;
1197 dtime
= dispatch_time(DISPATCH_TIME_NOW
, time_offset
);
1198 dispatch_source_set_timer(PlatformStorage
.timer
, dtime
, 1000ull*1000000000, 0);
1199 debugf("PrepareForIdle: scheduling timer with ticks %d", ticks
);
1203 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1205 mDNSlocal
void KQWokenFlushBytes(int fd
, __unused
short filter
, __unused
void *context
, __unused mDNSBool encounteredEOF
)
1207 // Read all of the bytes so we won't wake again.
1209 while (recv(fd
, buffer
, sizeof(buffer
), MSG_DONTWAIT
) > 0) continue;
1212 mDNSlocal
void SetLowWater(const KQSocketSet
*const k
, const int r
)
1214 if (k
->sktv4
>=0 && setsockopt(k
->sktv4
, SOL_SOCKET
, SO_RCVLOWAT
, &r
, sizeof(r
)) < 0)
1215 LogMsg("SO_RCVLOWAT IPv4 %d error %d errno %d (%s)", k
->sktv4
, r
, errno
, strerror(errno
));
1216 if (k
->sktv6
>=0 && setsockopt(k
->sktv6
, SOL_SOCKET
, SO_RCVLOWAT
, &r
, sizeof(r
)) < 0)
1217 LogMsg("SO_RCVLOWAT IPv6 %d error %d errno %d (%s)", k
->sktv6
, r
, errno
, strerror(errno
));
1220 mDNSlocal
void * KQueueLoop(void *m_param
)
1225 #if USE_SELECT_WITH_KQUEUEFD
1228 const int multiplier
= 1000000 / mDNSPlatformOneSecond
;
1230 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
1233 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
1234 dnssd_server_init();
1236 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
1237 LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
1239 // This is the main work loop:
1240 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
1241 // (2) Then we make sure we've delivered all waiting browse messages to our clients
1242 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
1243 // (4) On wakeup we first process *all* events
1244 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
1247 #define kEventsToReadAtOnce 1
1248 struct kevent new_events
[kEventsToReadAtOnce
];
1250 // Run mDNS_Execute to find out the time we next need to wake up
1251 mDNSs32 start
= mDNSPlatformRawTime();
1252 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
1253 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
1254 dnssd_server_idle();
1256 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
1257 if (m
->DNSPushServers
!= mDNSNULL
)
1260 nextTimerEvent
= dso_idle(m
, m
->timenow
, nextTimerEvent
);
1264 mDNSs32 end
= mDNSPlatformRawTime();
1265 if (end
- start
>= WatchDogReportingThreshold
)
1267 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_WARNING
, "WARNING: Idle task took %d ms to complete", end
- start
);
1270 #if MDNS_MALLOC_DEBUGGING >= 1
1271 mDNSPlatformValidateLists();
1274 mDNSs32 now
= mDNS_TimeNow(m
);
1276 if (m
->ShutdownTime
)
1278 if (mDNSStorage
.ResourceRecords
)
1281 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
1283 LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m
, rr
));
1284 if (mDNS_LoggingEnabled
) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
1287 if (mDNS_ExitNow(m
, now
))
1289 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "mDNS_FinalExit");
1290 mDNS_FinalExit(&mDNSStorage
);
1291 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
1294 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
1295 nextTimerEvent
= m
->ShutdownTime
;
1299 if (!AllowSleepNow(now
))
1300 if (nextTimerEvent
- m
->SleepLimit
>= 0)
1301 nextTimerEvent
= m
->SleepLimit
;
1303 // Convert absolute wakeup time to a relative time from now
1304 mDNSs32 ticks
= nextTimerEvent
- now
;
1305 if (ticks
< 1) ticks
= 1;
1307 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
1313 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
1316 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
1319 // Release the lock, and sleep until:
1320 // 1. Something interesting happens like a packet arriving, or
1321 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
1322 // 3. The timeout expires
1323 pthread_mutex_unlock(&PlatformStorage
.BigMutex
);
1325 // If we woke up to receive a multicast, set low-water mark to dampen excessive wakeup rate
1326 if (m
->p
->num_mcasts
)
1328 SetLowWater(&m
->p
->permanentsockets
, 0x10000);
1329 if (ticks
> mDNSPlatformOneSecond
/ 8) ticks
= mDNSPlatformOneSecond
/ 8;
1332 #if USE_SELECT_WITH_KQUEUEFD
1333 struct timeval timeout
;
1334 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
1335 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
1336 FD_SET(KQueueFD
, &readfds
);
1337 if (select(KQueueFD
+1, &readfds
, NULL
, NULL
, &timeout
) < 0)
1338 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
1340 struct timespec timeout
;
1341 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
1342 timeout
.tv_nsec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
1343 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
1344 // and have it work similarly to the way it does with nevents non-zero --
1345 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
1346 // In fact, what happens if you do this is that it just returns immediately. So, we have
1347 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
1348 if (kevent(KQueueFD
, NULL
, 0, new_events
, 1, &timeout
) < 0)
1349 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
1352 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
1353 // We have to ignore the event we may have been told about above, because that
1354 // was done without holding the lock, and between the time we woke up and the
1355 // time we reclaimed the lock the other thread could have done something that
1356 // makes the event no longer valid. Now we have the lock, we call kevent again
1357 // and this time we can safely process the events it tells us about.
1359 // If we changed UDP socket low-water mark, restore it, so we will be told about every packet
1360 if (m
->p
->num_mcasts
)
1362 SetLowWater(&m
->p
->permanentsockets
, 1);
1363 m
->p
->num_mcasts
= 0;
1366 static const struct timespec zero_timeout
= { 0, 0 };
1368 while ((events_found
= kevent(KQueueFD
, NULL
, 0, new_events
, kEventsToReadAtOnce
, &zero_timeout
)) != 0)
1370 if (events_found
> kEventsToReadAtOnce
|| (events_found
< 0 && errno
!= EINTR
))
1372 const int kevent_errno
= errno
;
1373 // Not sure what to do here, our kqueue has failed us - this isn't ideal
1374 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", kevent_errno
, strerror(kevent_errno
));
1378 numevents
+= events_found
;
1381 for (i
= 0; i
< events_found
; i
++)
1383 const KQueueEntry
*const kqentry
= new_events
[i
].udata
;
1384 mDNSs32 stime
= mDNSPlatformRawTime();
1385 const char *const KQtask
= kqentry
->KQtask
; // Grab a copy in case KQcallback deletes the task
1386 kqentry
->KQcallback((int)new_events
[i
].ident
, new_events
[i
].filter
, kqentry
->KQcontext
, (new_events
[i
].flags
& EV_EOF
) != 0);
1387 mDNSs32 etime
= mDNSPlatformRawTime();
1388 if (etime
- stime
>= WatchDogReportingThreshold
)
1390 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_WARNING
,
1391 "WARNING: " PUB_S
" took %d ms to complete", KQtask
, etime
- stime
);
1400 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1402 mDNSlocal
size_t LaunchdCheckin(void)
1404 // Ask launchd for our socket
1405 int result
= launch_activate_socket("Listeners", &launchd_fds
, &launchd_fds_count
);
1406 if (result
!= 0) { LogMsg("launch_activate_socket() failed error %d (%s)", result
, strerror(result
)); }
1407 return launchd_fds_count
;
1411 extern int sandbox_init(const char *profile
, uint64_t flags
, char **errorbuf
) __attribute__((weak_import
));
1413 #if APPLE_OSX_mDNSResponder
1414 mDNSlocal mDNSBool
PreferencesGetValueBool(CFStringRef key
, mDNSBool defaultValue
)
1416 CFBooleanRef boolean
;
1417 mDNSBool result
= defaultValue
;
1419 boolean
= CFPreferencesCopyAppValue(key
, kProgramArguments
);
1420 if (boolean
!= NULL
)
1422 if (CFGetTypeID(boolean
) == CFBooleanGetTypeID())
1423 result
= CFBooleanGetValue(boolean
) ? mDNStrue
: mDNSfalse
;
1430 mDNSlocal
int PreferencesGetValueInt(CFStringRef key
, int defaultValue
)
1434 int result
= defaultValue
;
1436 number
= CFPreferencesCopyAppValue(key
, kProgramArguments
);
1439 if ((CFGetTypeID(number
) == CFNumberGetTypeID()) && CFNumberGetValue(number
, kCFNumberIntType
, &numberValue
))
1440 result
= numberValue
;
1448 mDNSlocal
void SandboxProcess(void)
1450 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
1452 LogMsg("Note: Compiled without Apple Sandbox support");
1453 #else // MDNS_NO_SANDBOX
1455 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
1459 uint64_t sandbox_flags
= SANDBOX_NAMED
;
1461 (void)confstr(_CS_DARWIN_USER_CACHE_DIR
, NULL
, 0);
1463 int sandbox_err
= sandbox_init("mDNSResponder", sandbox_flags
, &sandbox_msg
);
1466 LogMsg("WARNING: sandbox_init error %s", sandbox_msg
);
1467 // If we have errors in the sandbox during development, to prevent
1468 // exiting, uncomment the following line.
1469 //sandbox_free_error(sandbox_msg);
1471 errx(EX_OSERR
, "sandbox_init() failed: %s", sandbox_msg
);
1473 else LogInfo("Now running under Apple Sandbox restrictions");
1475 #endif // MDNS_NO_SANDBOX
1478 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
1479 #define MDNS_OS_LOG_CATEGORY_INIT(NAME) \
1482 mDNSLogCategory_ ## NAME = os_log_create("com.apple.mDNSResponder", # NAME ); \
1483 if (!mDNSLogCategory_ ## NAME ) \
1485 os_log_error(OS_LOG_DEFAULT, "Could NOT create the " # NAME " log handle in mDNSResponder"); \
1486 mDNSLogCategory_ ## NAME = OS_LOG_DEFAULT; \
1491 os_log_t mDNSLogCategory_Default
= NULL
;
1492 os_log_t mDNSLogCategory_mDNS
= NULL
;
1493 os_log_t mDNSLogCategory_uDNS
= NULL
;
1494 os_log_t mDNSLogCategory_SPS
= NULL
;
1495 os_log_t mDNSLogCategory_XPC
= NULL
;
1496 os_log_t mDNSLogCategory_Analytics
= NULL
;
1497 os_log_t mDNSLogCategory_DNSSEC
= NULL
;
1499 mDNSlocal
void init_logging(void)
1501 MDNS_OS_LOG_CATEGORY_INIT(Default
);
1502 MDNS_OS_LOG_CATEGORY_INIT(mDNS
);
1503 MDNS_OS_LOG_CATEGORY_INIT(uDNS
);
1504 MDNS_OS_LOG_CATEGORY_INIT(SPS
);
1505 MDNS_OS_LOG_CATEGORY_INIT(XPC
);
1506 MDNS_OS_LOG_CATEGORY_INIT(Analytics
);
1507 MDNS_OS_LOG_CATEGORY_INIT(DNSSEC
);
1511 mDNSexport
int main(int argc
, char **argv
)
1514 kern_return_t status
;
1517 bool useDebugSocket
= mDNSfalse
;
1518 bool useSandbox
= mDNStrue
;
1521 #if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
1525 mDNSMacOSXSystemBuildNumber(NULL
);
1526 LogMsg("%s starting %s %d", mDNSResponderVersionString
, OSXVers
? "OSXVers" : "iOSVers", OSXVers
? OSXVers
: iOSVers
);
1529 LogMsg("CacheRecord %5d", sizeof(CacheRecord
));
1530 LogMsg("CacheGroup %5d", sizeof(CacheGroup
));
1531 LogMsg("ResourceRecord %5d", sizeof(ResourceRecord
));
1532 LogMsg("RData_small %5d", sizeof(RData_small
));
1534 LogMsg("sizeof(CacheEntity) %5d", sizeof(CacheEntity
));
1535 LogMsg("RR_CACHE_SIZE %5d", RR_CACHE_SIZE
);
1536 LogMsg("block bytes used %5d", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1537 LogMsg("block bytes wasted %5d", 32*1024 - sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1543 LogMsg("mDNSResponder cannot be run as root !! Exiting..");
1548 for (i
=1; i
<argc
; i
++)
1550 if (!strcasecmp(argv
[i
], "-d" )) mDNS_DebugMode
= mDNStrue
;
1551 if (!strcasecmp(argv
[i
], "-NoMulticastAdvertisements")) NoMulticastAdvertisements
= mDNStrue
;
1552 if (!strcasecmp(argv
[i
], "-DisableSleepProxyClient" )) DisableSleepProxyClient
= mDNStrue
;
1553 if (!strcasecmp(argv
[i
], "-DebugLogging" )) mDNS_LoggingEnabled
= mDNStrue
;
1554 if (!strcasecmp(argv
[i
], "-UnicastPacketLogging" )) mDNS_PacketLoggingEnabled
= mDNStrue
;
1555 if (!strcasecmp(argv
[i
], "-OfferSleepProxyService" ))
1556 OfferSleepProxyService
= (i
+1 < argc
&& mDNSIsDigit(argv
[i
+1][0]) && mDNSIsDigit(argv
[i
+1][1]) && argv
[i
+1][2]==0) ? atoi(argv
[++i
]) : 100;
1557 if (!strcasecmp(argv
[i
], "-UseInternalSleepProxy" ))
1558 UseInternalSleepProxy
= (i
+1<argc
&& mDNSIsDigit(argv
[i
+1][0]) && argv
[i
+1][1]==0) ? atoi(argv
[++i
]) : 1;
1559 if (!strcasecmp(argv
[i
], "-StrictUnicastOrdering" )) StrictUnicastOrdering
= mDNStrue
;
1560 if (!strcasecmp(argv
[i
], "-AlwaysAppendSearchDomains")) AlwaysAppendSearchDomains
= mDNStrue
;
1561 if (!strcasecmp(argv
[i
], "-DisableAllowExpired" )) EnableAllowExpired
= mDNSfalse
;
1563 if (!strcasecmp(argv
[i
], "-UseDebugSocket")) useDebugSocket
= mDNStrue
;
1564 if (!strcasecmp(argv
[i
], "-NoSandbox")) useSandbox
= mDNSfalse
;
1569 #if APPLE_OSX_mDNSResponder
1570 /* Reads the external user's program arguments for mDNSResponder starting 10.11.x(El Capitan) on OSX. The options for external user are:
1571 DebugLogging, UnicastPacketLogging, NoMulticastAdvertisements, StrictUnicastOrdering and AlwaysAppendSearchDomains
1573 To turn ON the particular option, here is what the user should do (as an example of setting two options)
1574 1] sudo defaults write /Library/Preferences/com.apple.mDNSResponder.plist AlwaysAppendSearchDomains -bool YES
1575 2] sudo defaults write /Library/Preferences/com.apple.mDNSResponder.plist NoMulticastAdvertisements -bool YES
1578 To turn OFF all options, here is what the user should do
1579 1] sudo defaults delete /Library/Preferences/com.apple.mDNSResponder.plist
1582 To view the current options set, here is what the user should do
1583 1] plutil -p /Library/Preferences/com.apple.mDNSResponder.plist
1585 1] sudo defaults read /Library/Preferences/com.apple.mDNSResponder.plist
1589 // Currently on Fuji/Whitetail releases we are keeping the logging always enabled.
1590 // Hence mDNS_LoggingEnabled and mDNS_PacketLoggingEnabled is set to true below by default.
1592 mDNS_LoggingEnabled
= PreferencesGetValueBool(kPreferencesKey_DebugLogging
, mDNS_LoggingEnabled
);
1593 mDNS_PacketLoggingEnabled
= PreferencesGetValueBool(kPreferencesKey_UnicastPacketLogging
, mDNS_PacketLoggingEnabled
);
1596 mDNS_LoggingEnabled
= mDNStrue
;
1597 mDNS_PacketLoggingEnabled
= mDNStrue
;
1599 NoMulticastAdvertisements
= PreferencesGetValueBool(kPreferencesKey_NoMulticastAdvertisements
, NoMulticastAdvertisements
);
1600 StrictUnicastOrdering
= PreferencesGetValueBool(kPreferencesKey_StrictUnicastOrdering
, StrictUnicastOrdering
);
1601 AlwaysAppendSearchDomains
= PreferencesGetValueBool(kPreferencesKey_AlwaysAppendSearchDomains
, AlwaysAppendSearchDomains
);
1602 EnableAllowExpired
= PreferencesGetValueBool(kPreferencesKey_EnableAllowExpired
, EnableAllowExpired
);
1603 OfferSleepProxyService
= PreferencesGetValueInt(kPreferencesKey_OfferSleepProxyService
, OfferSleepProxyService
);
1604 UseInternalSleepProxy
= PreferencesGetValueInt(kPreferencesKey_UseInternalSleepProxy
, UseInternalSleepProxy
);
1606 #if ENABLE_BLE_TRIGGERED_BONJOUR
1607 EnableBLEBasedDiscovery
= PreferencesGetValueBool(kPreferencesKey_EnableBLEBasedDiscovery
, EnableBLEBasedDiscovery
);
1608 DefaultToBLETriggered
= PreferencesGetValueBool(kPreferencesKey_DefaultToBLETriggered
, DefaultToBLETriggered
);
1609 #endif // ENABLE_BLE_TRIGGERED_BONJOUR
1612 #if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
1613 PreallocateCacheMemory
= PreferencesGetValueBool(kPreferencesKey_PreallocateCacheMemory
, PreallocateCacheMemory
);
1615 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
1616 PQWorkaroundThreshold
= PreferencesGetValueInt(kPreferencesKey_PQWorkaroundThreshold
, PQWorkaroundThreshold
);
1617 CFDictionaryRef managedDefaults
= mdns_managed_defaults_create("com.apple.mDNSResponder", NULL
);
1618 if (managedDefaults
)
1620 PQWorkaroundThreshold
= mdns_managed_defaults_get_int_clamped(managedDefaults
,
1621 kPreferencesKey_PQWorkaroundThreshold
, PQWorkaroundThreshold
, NULL
);
1622 CFRelease(managedDefaults
);
1623 managedDefaults
= NULL
;
1627 // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
1628 if (NoMulticastAdvertisements
)
1629 LogMsg("-NoMulticastAdvertisements is set: Administratively prohibiting multicast advertisements");
1630 if (AlwaysAppendSearchDomains
)
1631 LogMsg("-AlwaysAppendSearchDomains is set");
1632 if (StrictUnicastOrdering
)
1633 LogMsg("-StrictUnicastOrdering is set");
1635 #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1637 signal(SIGHUP
, HandleSIG
); // (Debugging) Purge the cache to check for cache handling bugs
1638 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
1639 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
1640 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
1641 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
1642 signal(SIGUSR1
, HandleSIG
); // (Debugging) Enable Logging
1643 signal(SIGUSR2
, HandleSIG
); // (Debugging) Enable Packet Logging
1644 signal(SIGPROF
, HandleSIG
); // (Debugging) Toggle Multicast Logging
1645 signal(SIGTSTP
, HandleSIG
); // (Debugging) Disable all Debug Logging (USR1/USR2/PROF)
1647 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1649 mDNSStorage
.p
= &PlatformStorage
; // Make sure mDNSStorage.p is set up, because validatelists uses it
1651 #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1653 // Create the kqueue, mutex and thread to support KQSockets
1654 KQueueFD
= kqueue();
1657 const int kqueue_errno
= errno
;
1658 LogMsg("kqueue() failed errno %d (%s)", kqueue_errno
, strerror(kqueue_errno
));
1659 status
= kqueue_errno
;
1663 i
= pthread_mutex_init(&PlatformStorage
.BigMutex
, NULL
);
1664 if (i
!= 0) { LogMsg("pthread_mutex_init() failed error %d (%s)", i
, strerror(i
)); status
= i
; goto exit
; }
1666 int fdpair
[2] = {0, 0};
1667 i
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
);
1670 const int socketpair_errno
= errno
;
1671 LogMsg("socketpair() failed errno %d (%s)", socketpair_errno
, strerror(socketpair_errno
));
1672 status
= socketpair_errno
;
1676 // Socket pair returned us two identical sockets connected to each other
1677 // We will use the first socket to send the second socket. The second socket
1678 // will be added to the kqueue so it will wake when data is sent.
1679 static const KQueueEntry wakeKQEntry
= { KQWokenFlushBytes
, NULL
, "kqueue wakeup after CFRunLoop event" };
1681 PlatformStorage
.WakeKQueueLoopFD
= fdpair
[0];
1682 KQueueSet(fdpair
[1], EV_ADD
, EVFILT_READ
, &wakeKQEntry
);
1684 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1691 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
1692 status
= MetricsInit();
1693 if (status
) { LogMsg("Daemon start: MetricsInit failed (%d)", status
); }
1696 status
= mDNSDaemonInitialize();
1697 if (status
) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit
; }
1699 // Need to Start XPC Server Before LaunchdCheckin() (Reason: radar:11023750)
1702 if (!useDebugSocket
) {
1703 if (LaunchdCheckin() == 0)
1704 useDebugSocket
= mDNStrue
;
1707 SetDebugBoundPath();
1712 status
= udsserver_init(launchd_fds
, (mDNSu32
)launchd_fds_count
);
1713 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
1715 mDNSMacOSXNetworkChanged();
1718 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1719 LogInfo("Daemon Start: Using LibDispatch");
1720 // CFRunLoopRun runs both CFRunLoop sources and dispatch sources
1722 #else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1723 // Start the kqueue thread
1724 pthread_t KQueueThread
;
1725 i
= pthread_create(&KQueueThread
, NULL
, KQueueLoop
, &mDNSStorage
);
1726 if (i
!= 0) { LogMsg("pthread_create() failed error %d (%s)", i
, strerror(i
)); status
= i
; goto exit
; }
1730 LogMsg("ERROR: CFRunLoopRun Exiting.");
1731 mDNS_Close(&mDNSStorage
);
1733 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1735 LogMsg("%s exiting", mDNSResponderVersionString
);
1741 // uds_daemon.c support routines /////////////////////////////////////////////
1743 mDNSlocal
void kqUDSEventCallback(int fd
, short filter
, void *context
, mDNSBool encounteredEOF
)
1745 const KQSocketEventSource
*const source
= context
;
1746 (void)filter
; // unused
1747 (void)encounteredEOF
; // unused
1749 source
->callback(fd
, source
->context
);
1752 // Arrange things so that when data appears on fd, callback is called with context
1753 mDNSexport mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
, void **platform_data
)
1755 KQSocketEventSource
**p
= &gEventSources
;
1756 (void) platform_data
;
1757 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
1758 if (*p
) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd
); return mStatus_AlreadyRegistered
; }
1760 KQSocketEventSource
*newSource
= (KQSocketEventSource
*) callocL("KQSocketEventSource", sizeof(*newSource
));
1761 if (!newSource
) return mStatus_NoMemoryErr
;
1763 newSource
->next
= mDNSNULL
;
1765 newSource
->callback
= callback
;
1766 newSource
->context
= context
;
1767 newSource
->kqs
.KQcallback
= kqUDSEventCallback
;
1768 newSource
->kqs
.KQcontext
= newSource
;
1769 newSource
->kqs
.KQtask
= "UDS client";
1770 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1771 newSource
->kqs
.readSource
= mDNSNULL
;
1772 newSource
->kqs
.writeSource
= mDNSNULL
;
1773 newSource
->kqs
.fdClosed
= mDNSfalse
;
1774 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
1776 if (KQueueSet(fd
, EV_ADD
, EVFILT_READ
, &newSource
->kqs
) == 0)
1779 return mStatus_NoError
;
1782 LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd
, errno
, strerror(errno
));
1783 freeL("KQSocketEventSource", newSource
);
1784 return mStatus_BadParamErr
;
1787 int udsSupportReadFD(dnssd_sock_t fd
, char *buf
, int len
, int flags
, void *platform_data
)
1789 (void) platform_data
;
1790 return (int)recv(fd
, buf
, len
, flags
);
1793 mDNSexport mStatus
udsSupportRemoveFDFromEventLoop(int fd
, void *platform_data
) // Note: This also CLOSES the file descriptor
1795 KQSocketEventSource
**p
= &gEventSources
;
1796 (void) platform_data
;
1797 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
1800 KQSocketEventSource
*s
= *p
;
1802 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
1803 // causes the kernel to automatically remove any associated kevents
1804 mDNSPlatformCloseFD(&s
->kqs
, s
->fd
);
1805 freeL("KQSocketEventSource", s
);
1806 return mStatus_NoError
;
1808 LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd
);
1809 return mStatus_NoSuchNameErr
;
1813 #include "../unittests/daemon_ut.c"
1816 #if _BUILDING_XCODE_PROJECT_
1817 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
1818 const char *__crashreporter_info__
= mDNSResponderVersionString
;
1819 asm (".desc ___crashreporter_info__, 0x10");
1822 // For convenience when using the "strings" command, this is the last thing in the file
1823 // The "@(#) " pattern is a special prefix the "what" command looks for
1824 mDNSexport
const char mDNSResponderVersionString_SCCS
[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";