1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, 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 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
30 Change History (most recent first):
33 Revision 1.434 2009/06/27 00:55:27 cheshire
34 Added code for displaying the size of various structures like CacheRecord and CacheGroup
36 Revision 1.433 2009/06/25 23:36:57 cheshire
37 To facilitate testing, added command-line switch "-OfferSleepProxyService"
38 to re-enable the previously-supported mode of operation where we offer
39 sleep proxy service on desktop Macs that are set to never sleep.
41 Revision 1.432 2009/05/13 17:25:33 mkrochma
42 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
43 Sleep proxy client should only look for services being advertised via Multicast
45 Revision 1.431 2009/05/12 23:21:18 cheshire
46 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
47 Use mDNSCoreHaveAdvertisedServices routine to determine whether we should schedule a maintenance wake
49 Revision 1.430 2009/05/01 19:17:36 cheshire
50 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
52 Revision 1.429 2009/04/30 20:07:50 mcguire
53 <rdar://problem/6822674> Support multiple UDSs from launchd
55 Revision 1.428 2009/04/22 19:43:37 cheshire
56 To facilitate debugging, added -DebugLogging and -UnicastPacketLogging switches
57 as launch-time alternatives to sending SIGUSR1 and SIGUSR2 signals later
59 Revision 1.427 2009/04/22 01:19:57 jessic2
60 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
62 Revision 1.426 2009/04/20 19:25:26 cheshire
63 For readability, changed "nomulticastadvertisements" to "NoMulticastAdvertisements"
65 Revision 1.425 2009/04/20 19:17:19 cheshire
66 Added a comment explaining why we don't need our CatchABRT handler on 10.5 and later
68 Revision 1.424 2009/04/17 19:10:27 mcguire
69 <rdar://problem/6802833> May still ping-pong with kernel when a framework calls abort()
71 Revision 1.423 2009/04/16 16:03:08 mcguire
72 <rdar://problem/6792024> abort() causes high CPU usage instead of crash & restart
74 Revision 1.422 2009/04/11 01:43:28 jessic2
75 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
77 Revision 1.421 2009/04/11 00:20:06 jessic2
78 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
80 Revision 1.420 2009/03/20 23:53:03 jessic2
81 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
83 Revision 1.419 2009/03/20 21:30:04 cheshire
84 <rdar://problem/6705866> Crash passing invalid parameters to DNSServiceBrowserCreate()
85 Do not append a new question to the browser list until *after* we verify that mDNS_StartBrowse() succeeded
87 Revision 1.418 2009/03/17 21:32:15 cheshire
88 Improved "DHCPWakeTime: SCDynamicStoreCopyDHCPInfo failed" error message
90 Revision 1.417 2009/03/17 01:25:39 cheshire
91 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
92 In SIGINFO output, show three best Sleep Proxies
94 Revision 1.416 2009/02/21 01:47:36 cheshire
95 <rdar://problem/6600825> Race condition when sleep initiated and then immediately canceled
97 Revision 1.415 2009/02/21 01:45:33 cheshire
98 Move declaration of "mDNSs32 interval"
100 Revision 1.414 2009/02/14 00:05:32 cheshire
101 Left-justify interface names
103 Revision 1.413 2009/02/13 18:16:05 cheshire
104 Fixed some compile warnings
106 Revision 1.412 2009/02/13 06:34:41 cheshire
107 Converted LogOperation messages to LogInfo or LogSPS
109 Revision 1.411 2009/02/12 20:57:26 cheshire
110 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
112 Revision 1.410 2009/02/11 02:32:18 cheshire
113 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
115 Revision 1.409 2009/02/09 21:16:14 cheshire
116 Improved debugging messages
118 Revision 1.408 2009/02/07 06:08:44 cheshire
119 Commented out testing code
121 Revision 1.407 2009/02/07 02:57:31 cheshire
122 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
124 Revision 1.406 2009/02/06 03:06:49 mcguire
125 <rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
127 Revision 1.405 2009/02/04 23:00:28 cheshire
128 Move logic for deciding when to next wake up into a subroutine called AllowSleepNow
130 Revision 1.404 2009/02/02 22:18:32 cheshire
131 If we wake up and find no wireless network, don't just give up and go back to sleep and never try again
133 Revision 1.403 2009/01/15 21:58:18 cheshire
134 Stop using ifa_name field of NetworkInterfaceInfoOSX structure, because it will be going away
136 Revision 1.402 2009/01/07 23:08:18 cheshire
137 Updated debugging messages and comments
139 Revision 1.401 2008/12/17 05:05:26 cheshire
140 Fixed alignment of NAT mapping syslog messages
142 Revision 1.400 2008/12/10 19:30:57 cheshire
143 Use symbolic name OSXVers_10_3_Panther in version check instead of literal integer "7"
145 Revision 1.399 2008/12/10 02:13:04 cheshire
146 Fix alignment of SIGINFO output for longer interface names like "bridge0"
148 Revision 1.398 2008/12/04 21:08:51 mcguire
149 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
151 Revision 1.397 2008/12/04 02:18:50 cheshire
152 Improved sleep/wake debugging messages
154 Revision 1.396 2008/11/26 23:37:44 cheshire
155 Use SCDynamicStoreCopyDHCPInfo to compute desired wakeup time for our next DHCP lease renewal
157 Revision 1.395 2008/11/14 21:56:31 cheshire
158 Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
160 Revision 1.394 2008/11/14 02:20:03 cheshire
161 Include m->NextScheduledSPS in task scheduling calculations
163 Revision 1.393 2008/11/14 01:22:38 cheshire
164 Include SPS-registered records when computing the next required wakeup time
166 Revision 1.392 2008/11/11 01:55:16 cheshire
167 Improved comments; minium requested sleep is 60 seconds
169 Revision 1.391 2008/11/04 02:29:55 cheshire
170 Clear interface list before sleeping
172 Revision 1.390 2008/11/02 21:22:05 cheshire
173 Changed mallocL size parameter back to "unsigned int"
175 Revision 1.389 2008/11/02 21:14:58 cheshire
176 Fixes to make mallocL/freeL debugging checks work on 64-bit
178 Revision 1.388 2008/10/31 23:05:30 cheshire
179 Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c
181 Revision 1.387 2008/10/30 01:08:18 cheshire
182 After waking for network maintenance operations go back to sleep again
184 Revision 1.386 2008/10/29 22:03:39 cheshire
185 Compute correct required wakeup time for NAT traversals and uDNS-registered records
187 Revision 1.385 2008/10/28 20:40:13 cheshire
188 Now that the BPF code in mDNSMacOSX.c makes its own CFSocketCreateWithNative directly, the
189 udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop routines can go back to using kqueue
191 Revision 1.384 2008/10/27 22:22:59 cheshire
192 Extra sanity checking in udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop
194 Revision 1.383 2008/10/27 07:24:53 cheshire
195 Need a "usleep(1000)" (workaround for <rdar://problem/3585273>) to avoid crashes
197 Revision 1.382 2008/10/24 01:51:48 cheshire
198 Before going to sleep, request a future wakeup to renew NAT-PMP mappings, SPS registrations, etc.
200 Revision 1.381 2008/10/23 22:25:58 cheshire
201 Renamed field "id" to more descriptive "updateid"
203 Revision 1.380 2008/10/23 02:25:08 cheshire
204 Added locking in InternetSharingChanged()
206 Revision 1.379 2008/10/22 23:23:59 cheshire
207 Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
209 Revision 1.378 2008/10/22 19:55:35 cheshire
210 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
212 Revision 1.377 2008/10/22 17:17:22 cheshire
213 Need to open and close BPF fds when turning Sleep Proxy Server on and off
215 Revision 1.376 2008/10/22 01:42:39 cheshire
216 Before allowing sleep, delay until NetWakeResolve queries have completed
218 Revision 1.375 2008/10/20 22:31:31 cheshire
219 Instead of requesting a single BPF descriptor via mDNSRequestBPF(), call mDNSMacOSXNetworkChanged()
220 to signal that UDS is now available to handle BPF requests, and let it work out what it needs
222 Revision 1.374 2008/10/16 22:40:48 cheshire
223 Removed "usleep(100000);" from CFSCallBack()
225 Revision 1.373 2008/10/16 20:49:30 cheshire
226 When kevent/kqueue fails, fall back to using old CFSocket RunLoopSource instead
228 Revision 1.372 2008/10/15 00:03:21 cheshire
229 When finally going to sleep, update m->SleepState from SleepState_Transferring to SleepState_Sleeping
231 Revision 1.371 2008/10/14 19:09:53 cheshire
232 When going to sleep, delay sleep until we've got our acknowledgment from the SPS
234 Revision 1.370 2008/10/09 22:32:27 cheshire
235 Include MAC address in interface listing in SIGINFO output
237 Revision 1.369 2008/10/09 19:32:39 cheshire
238 Updated SIGINFO output to indicate whether we've found a sleep proxy server on a given interface
239 Hollow sun with rays "☼" indicates we're still looking; solid sun with rays "☀" indicates we found one
241 Revision 1.368 2008/10/03 21:23:17 mkrochma
242 Fix crash by not passing NULL to CFGetTypeID
244 Revision 1.367 2008/10/03 18:25:17 cheshire
245 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
247 Revision 1.366 2008/10/03 00:34:55 cheshire
248 <rdar://problem/6134215> Mac with Internet Sharing should also offer Sleep Proxy service
249 Start and stop Sleep Proxy service when user starts and stops Internet Sharing
251 Revision 1.365 2008/10/02 22:23:13 cheshire
252 Additional debugging message giving explanation if shutdown is delayed
254 Revision 1.364 2008/10/01 21:23:40 cheshire
255 In SIGINFO interface listing, indicate whether NetWake is set
257 Revision 1.363 2008/09/27 01:29:15 cheshire
258 Call mDNSRequestBPF() to request the helper to send us the BPF fd
260 Revision 1.362 2008/09/26 19:47:42 cheshire
261 Fixed locking error: lock is supposed to be held when calling mDNS_PurgeCacheResourceRecord
263 Revision 1.361 2008/09/15 23:52:30 cheshire
264 <rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
265 Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
267 Revision 1.360 2008/03/13 20:55:16 mcguire
268 <rdar://problem/5769316> fix deprecated warnings/errors
269 Additional cleanup: use a conditional macro instead of lots of #if
271 Revision 1.359 2008/03/12 23:02:58 mcguire
272 <rdar://problem/5769316> fix deprecated warnings/errors
274 Revision 1.358 2008/03/06 21:26:11 cheshire
275 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
277 Revision 1.357 2008/02/13 17:40:43 cheshire
278 <rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
280 Revision 1.356 2007/12/18 00:28:56 cheshire
281 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
282 Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
284 Revision 1.355 2007/12/17 22:29:22 cheshire
285 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
286 Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
288 Revision 1.354 2007/12/15 01:12:28 cheshire
289 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
291 Revision 1.353 2007/12/14 19:14:02 cheshire
292 Added (commented out) code for testing sleep/wake
294 Revision 1.352 2007/12/14 00:58:29 cheshire
295 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
296 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
297 until TLS/TCP deregistrations have completed (up to five seconds maximum)
299 Revision 1.351 2007/12/12 21:34:18 cheshire
300 Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
301 it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
302 confirmed that the bug is definitely fixed we'll remove the workaround altogether.
304 Revision 1.350 2007/12/07 00:45:58 cheshire
305 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
307 Revision 1.349 2007/12/04 22:00:54 cheshire
308 Fixed mistake in comment
310 Revision 1.348 2007/12/01 00:27:43 cheshire
311 Fixed compile warning: declaration of 'r' shadows a previous local
313 Revision 1.347 2007/11/02 22:00:13 cheshire
314 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
315 Need to hold the lock while calling SetDomainSecrets
317 Revision 1.346 2007/11/02 20:18:13 cheshire
318 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
320 Revision 1.345 2007/10/17 18:41:21 cheshire
321 For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
323 Revision 1.344 2007/09/29 01:06:17 mcguire
324 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
326 Revision 1.343 2007/09/24 05:02:41 cheshire
327 Debugging: In SIGINFO output, indicate explicitly when a given section is empty
329 Revision 1.342 2007/09/18 19:09:02 cheshire
330 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
332 Revision 1.341 2007/09/12 01:22:13 cheshire
333 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
335 Revision 1.340 2007/09/07 22:44:03 mcguire
336 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
338 Revision 1.339 2007/09/06 19:08:29 cheshire
339 LogClientOperations check needs to be "#if LogClientOperations || MDNS_DEBUGMSGS"
341 Revision 1.338 2007/09/05 23:34:27 mcguire
342 Revert logging change
344 Revision 1.337 2007/09/05 20:45:50 cheshire
345 Added list of KQSocketEventSources in SIGINFO output
347 Revision 1.336 2007/08/31 17:15:37 cheshire
348 Reordered startup log messages so that "mDNSResponder ... starting" is the first message
350 Revision 1.335 2007/08/31 02:00:16 cheshire
351 Added comment explaining use of zero-width non-breaking space character to tag literal strings
353 Revision 1.334 2007/08/24 23:40:24 cheshire
354 Added comment about FreeServiceInstance
356 Revision 1.333 2007/08/23 21:02:35 cheshire
357 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
359 Revision 1.332 2007/08/22 23:54:54 mcguire
360 <rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
362 Revision 1.331 2007/08/18 01:02:03 mcguire
363 <rdar://problem/5415593> No Bonjour services are getting registered at boot
365 Revision 1.330 2007/08/10 22:25:57 mkrochma
366 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
368 Revision 1.329 2007/08/08 22:34:58 mcguire
369 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
371 Revision 1.328 2007/07/27 22:43:37 cheshire
372 Improved mallocL/freeL "suspiciously large" debugging messages
374 Revision 1.327 2007/07/27 19:30:41 cheshire
375 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
376 to properly reflect tri-state nature of the possible responses
378 Revision 1.326 2007/07/24 17:23:33 cheshire
379 <rdar://problem/5357133> Add list validation checks for debugging
381 Revision 1.325 2007/07/11 23:43:43 cheshire
382 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
384 Revision 1.324 2007/07/11 22:44:40 cheshire
385 <rdar://problem/5328801> SIGHUP should purge the cache
387 Revision 1.323 2007/07/11 03:01:50 cheshire
388 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
390 Revision 1.322 2007/07/06 18:58:16 cheshire
391 Check m->NextScheduledNATOp in ShowTaskSchedulingError()
393 Revision 1.321 2007/07/02 21:54:20 cheshire
394 Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
396 Revision 1.320 2007/06/28 21:16:27 cheshire
397 Rename "m->nextevent" as more informative "m->NextuDNSEvent"
399 Revision 1.319 2007/06/22 20:47:08 cheshire
400 <rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
401 Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
403 Revision 1.318 2007/06/20 01:45:40 cheshire
404 When showing dormant interfaces, display last-seen IP address for that dormant interface
406 Revision 1.317 2007/06/20 01:10:12 cheshire
407 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
409 Revision 1.316 2007/06/19 19:27:11 cheshire
410 <rdar://problem/5141540> Sandbox mDNSResponder
411 Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
413 Revision 1.315 2007/06/15 21:54:51 cheshire
414 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
416 Revision 1.314 2007/06/15 19:23:17 cheshire
417 <rdar://problem/5254053> mDNSResponder renames my host without asking
418 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
420 Revision 1.313 2007/05/25 16:02:05 cheshire
421 When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
423 Revision 1.312 2007/05/22 19:07:21 cheshire
424 Add comment explaining RR_CACHE_SIZE calculation
426 Revision 1.311 2007/05/15 21:47:21 cheshire
427 Get rid of "#pragma unused(m)"
429 Revision 1.310 2007/05/08 00:56:17 cheshire
430 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
432 Revision 1.309 2007/04/30 21:33:38 cheshire
433 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
434 is iterating through the m->ServiceRegistrations list
436 Revision 1.308 2007/04/28 01:31:59 cheshire
437 Improve debugging support for catching memory corruption problems
439 Revision 1.307 2007/04/24 18:32:00 cheshire
440 Grab a copy of KQtask string pointer in case KQcallback deletes the task
442 Revision 1.306 2007/04/22 19:11:51 cheshire
443 Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
444 if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
445 from the project and just using simple vanilla C linked-list manipulation instead.
447 Revision 1.305 2007/04/22 06:02:03 cheshire
448 <rdar://problem/4615977> Query should immediately return failure when no server
450 Revision 1.304 2007/04/21 21:47:47 cheshire
451 <rdar://problem/4376383> Daemon: Add watchdog timer
453 Revision 1.303 2007/04/18 00:50:47 cheshire
454 <rdar://problem/5141540> Sandbox mDNSResponder
456 Revision 1.302 2007/04/07 01:01:48 cheshire
457 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
459 Revision 1.301 2007/04/05 19:13:48 cheshire
460 Use better name in SCPreferencesCreate
462 Revision 1.300 2007/04/04 21:22:18 cheshire
463 Suppress "Local Hostname changed" syslog message when name has not actually changed
465 Revision 1.299 2007/04/03 19:19:33 cheshire
466 Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
468 Revision 1.298 2007/03/30 21:51:45 cheshire
471 Revision 1.297 2007/03/27 22:47:19 cheshire
472 On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
474 Revision 1.296 2007/03/24 01:23:29 cheshire
475 Call validator for uDNS data structures
477 Revision 1.295 2007/03/20 23:32:49 cheshire
478 Minor textual tidying
480 Revision 1.294 2007/03/07 02:50:50 cheshire
481 <rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
483 Revision 1.293 2007/03/06 22:59:01 cheshire
484 <rdar://problem/4157921> Security: Null dereference possible in daemon.c
486 Revision 1.292 2007/02/28 21:55:10 cheshire
487 <rdar://problem/3862944> UI: Name conflict notifications should be localized
488 Additional fix: We were not getting our NotificationCallBackDismissed messages
489 because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
490 (We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
492 Revision 1.291 2007/02/28 03:51:24 cheshire
493 <rdar://problem/3862944> UI: Name conflict notifications should be localized
494 Moved curly quotes out of the literal text and into the localized text, so they
495 can be replaced with alternate characters as appropriate for other languages.
497 Revision 1.290 2007/02/14 01:58:19 cheshire
498 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
500 Revision 1.289 2007/02/07 19:32:00 cheshire
501 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
503 Revision 1.288 2007/02/07 01:01:24 cheshire
504 <rdar://problem/3956518> Need to go native with launchd
505 Additional refinements -- was unnecessarily calling launch_data_free()
507 Revision 1.287 2007/02/06 19:06:48 cheshire
508 <rdar://problem/3956518> Need to go native with launchd
510 Revision 1.286 2007/01/06 01:00:33 cheshire
511 Improved SIGINFO output
513 Revision 1.285 2007/01/05 08:30:47 cheshire
514 Trim excessive "$Log" checkin history from before 2006
515 (checkin history still available via "cvs log ..." of course)
517 Revision 1.284 2007/01/05 05:44:35 cheshire
518 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
519 so that mDNSPosix embedded clients will compile again
521 Revision 1.283 2007/01/04 23:11:14 cheshire
522 <rdar://problem/4720673> uDNS: Need to start caching unicast records
523 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
525 Revision 1.282 2006/12/21 00:09:45 cheshire
526 Use mDNSPlatformMemZero instead of bzero
528 Revision 1.281 2006/11/18 05:01:32 cheshire
529 Preliminary support for unifying the uDNS and mDNS code,
530 including caching of uDNS answers
532 Revision 1.280 2006/11/10 00:54:16 cheshire
533 <rdar://problem/4816598> Changing case of Computer Name doesn't work
535 Revision 1.279 2006/11/02 17:44:01 cheshire
536 No longer have a separate uDNS ActiveQueries list
538 Revision 1.278 2006/10/05 04:04:24 herscher
539 Remove embedded uDNS_info struct from DNSQuestion_struct
541 Revision 1.277 2006/09/21 21:01:24 cheshire
542 Change 'autorename' to more accurate name 'renameonmemfree'
544 Revision 1.276 2006/09/17 19:12:02 cheshire
545 Further changes for removal of uDNS_info substructure from mDNS_struct
547 Revision 1.275 2006/09/15 21:20:16 cheshire
548 Remove uDNS_info substructure from mDNS_struct
550 Revision 1.274 2006/08/14 23:24:39 cheshire
551 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
553 Revision 1.273 2006/07/30 05:43:19 cheshire
554 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
555 Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
557 Revision 1.272 2006/07/27 03:24:35 cheshire
558 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
559 Further refinement: Declare KQueueEntry parameter "const"
561 Revision 1.271 2006/07/27 02:59:26 cheshire
562 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
563 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
564 after releasing BigMutex, in case actions it took have resulted in new work for the
565 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
566 add new active interfaces to its list, and consequently schedule queries to be sent).
568 Revision 1.270 2006/07/25 17:16:36 mkrochma
569 Quick fix to solve kqueue related crashes and hangs
571 Revision 1.269 2006/07/22 06:11:37 cheshire
572 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
574 Revision 1.268 2006/07/15 02:01:32 cheshire
575 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
576 Fix broken "empty string" browsing
578 Revision 1.267 2006/07/07 01:09:10 cheshire
579 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
580 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
582 Revision 1.266 2006/07/05 23:34:53 cheshire
583 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
585 Revision 1.265 2006/06/29 07:32:08 cheshire
586 Added missing LogOperation logging for DNSServiceBrowse results
588 Revision 1.264 2006/06/29 05:33:30 cheshire
589 <rdar://problem/4607043> mDNSResponder conditional compilation options
591 Revision 1.263 2006/06/08 23:23:48 cheshire
592 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
594 Revision 1.262 2006/03/18 21:49:11 cheshire
595 Added comment in ShowTaskSchedulingError(mDNS *const m)
597 Revision 1.261 2006/01/06 01:22:28 cheshire
598 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
602 #include <mach/mach.h>
603 #include <mach/mach_error.h>
604 #include <servers/bootstrap.h>
605 #include <sys/types.h>
611 #include <sys/event.h>
614 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
615 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
617 #if TARGET_OS_EMBEDDED
618 #include <bootstrap_priv.h>
620 #define bootstrap_register(A,B,C) bootstrap_register2((A),(B),(C),0)
623 #include "DNSServiceDiscoveryRequestServer.h"
624 #include "DNSServiceDiscoveryReply.h"
627 #include "DNSCommon.h"
628 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
630 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
632 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
634 #include "safe_vproc.h"
636 //*************************************************************************************************************
637 #if COMPILER_LIKES_PRAGMA_MARK
638 #pragma mark - Globals
641 static mDNS_PlatformSupport PlatformStorage
;
643 // Start off with a default cache of 16K (99 records)
644 // Each time we grow the cache we add another 99 records
645 // 99 * 164 = 16236 bytes.
646 // This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
647 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
648 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
650 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
651 static mach_port_t m_port
= MACH_PORT_NULL
;
652 static mach_port_t client_death_port
= MACH_PORT_NULL
;
653 static mach_port_t signal_port
= MACH_PORT_NULL
;
654 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
656 static dnssd_sock_t
*launchd_fds
= mDNSNULL
;
657 static mDNSu32 launchd_fds_count
= 0;
659 // mDNS Mach Message Timeout, in milliseconds.
660 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
661 // fails to service its mach message queue, but long enough to give a well-written
662 // client a chance to service its mach message queue without getting cut off.
663 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
664 // even extra-slow clients a fair chance before we cut them off.
665 #define MDNS_MM_TIMEOUT 250
667 static int restarting_via_mach_init
= 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
668 static int started_via_launchdaemon
= 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
669 static mDNSBool advertise
= mDNS_Init_AdvertiseLocalAddresses
; // By default, advertise addresses (& other records) via multicast
671 //*************************************************************************************************************
672 #if COMPILER_LIKES_PRAGMA_MARK
674 #pragma mark - Active client list structures
677 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
678 struct DNSServiceDomainEnumeration_struct
680 DNSServiceDomainEnumeration
*next
;
681 mach_port_t ClientMachPort
;
682 DNSQuestion dom
; // Question asking for domains
683 DNSQuestion def
; // Question asking for default domain
686 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
687 struct DNSServiceBrowserResult_struct
689 DNSServiceBrowserResult
*next
;
694 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
696 typedef struct DNSServiceBrowserQuestion
698 struct DNSServiceBrowserQuestion
*next
;
701 } DNSServiceBrowserQuestion
;
703 struct DNSServiceBrowser_struct
705 DNSServiceBrowser
*next
;
706 mach_port_t ClientMachPort
;
707 DNSServiceBrowserQuestion
*qlist
;
708 DNSServiceBrowserResult
*results
;
710 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
711 domainname type
; // registration type
714 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
715 struct DNSServiceResolver_struct
717 DNSServiceResolver
*next
;
718 mach_port_t ClientMachPort
;
724 // A single registered service: ServiceRecordSet + bookkeeping
725 // Note that we duplicate some fields from parent DNSServiceRegistration object
726 // to facilitate cleanup, when instances and parent may be deallocated at different times.
727 typedef struct ServiceInstance
729 struct ServiceInstance
*next
;
730 mach_port_t ClientMachPort
;
731 mDNSBool autoname
; // Set if this name is tied to the Computer Name
732 mDNSBool renameonmemfree
; // Set if we just got a name conflict and now need to automatically pick a new name
735 ServiceRecordSet srs
;
736 // Don't add any fields after ServiceRecordSet.
737 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
740 // A client-created service. May reference several ServiceInstance objects if default
741 // settings cause registration in multiple domains.
742 typedef struct DNSServiceRegistration
744 struct DNSServiceRegistration
*next
;
745 mach_port_t ClientMachPort
;
746 mDNSBool DefaultDomain
;
750 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
751 domainlabel name
; // used only if autoname is false
754 unsigned char txtinfo
[1024];
757 ServiceInstance
*regs
;
758 } DNSServiceRegistration
;
760 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
761 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
762 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
763 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
765 // We keep a list of client-supplied event sources in KQSocketEventSource records
766 typedef struct KQSocketEventSource
768 struct KQSocketEventSource
*next
;
771 } KQSocketEventSource
;
773 static KQSocketEventSource
*gEventSources
;
775 //*************************************************************************************************************
776 #if COMPILER_LIKES_PRAGMA_MARK
778 #pragma mark - General Utility Functions
781 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
783 char _malloc_options
[] = "AXZ";
785 mDNSexport
void LogMemCorruption(const char *format
, ...)
789 va_start(ptr
,format
);
790 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
792 LogMsg("!!!! %s !!!!", buffer
);
793 NotifyOfElusiveBug("Memory Corruption", buffer
);
795 *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
799 mDNSlocal
void validatelists(mDNS
*const m
)
802 KQSocketEventSource
*k
;
803 for (k
= gEventSources
; k
; k
=k
->next
)
804 if (k
->next
== (KQSocketEventSource
*)~0 || k
->fd
< 0)
805 LogMemCorruption("gEventSources: %p is garbage (%d)", k
, k
->fd
);
807 // Check Mach client lists
808 DNSServiceDomainEnumeration
*e
;
809 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
810 if (e
->next
== (DNSServiceDomainEnumeration
*)~0 || e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
811 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
813 DNSServiceBrowser
*b
;
814 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
815 if (b
->next
== (DNSServiceBrowser
*)~0 || b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
816 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
818 DNSServiceResolver
*l
;
819 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
820 if (l
->next
== (DNSServiceResolver
*)~0 || l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
821 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
823 DNSServiceRegistration
*r
;
824 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
825 if (r
->next
== (DNSServiceRegistration
*)~0 || r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
826 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
828 // Check Unix Domain Socket client lists (uds_daemon.c)
831 // Check core mDNS lists
833 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
835 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
836 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
837 if (rr
->resrec
.name
!= &rr
->namestorage
)
838 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
839 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
842 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
843 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
844 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
846 rr
= m
->NewLocalRecords
;
848 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
849 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
851 rr
= m
->CurrentRecord
;
853 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
854 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
857 for (q
= m
->Questions
; q
; q
=q
->next
)
858 if (q
->next
== (DNSQuestion
*)~0 || q
->ThisQInterval
== (mDNSs32
)~0)
859 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q
, q
->ThisQInterval
, q
->next
);
864 FORALL_CACHERECORDS(slot
, cg
, cr
)
866 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
867 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, cr
, cr
->resrec
.RecordType
);
868 if (cr
->CRActiveQuestion
)
870 for (q
= m
->Questions
; q
; q
=q
->next
) if (q
== cr
->CRActiveQuestion
) break;
871 if (!q
) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot
, cr
->CRActiveQuestion
, CRDisplayString(m
, cr
));
875 // Check core uDNS lists
876 udns_validatelists(m
);
878 // Check platform-layer lists
879 NetworkInterfaceInfoOSX
*i
;
880 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
881 if (i
->next
== (NetworkInterfaceInfoOSX
*)~0 || !i
->m
|| i
->m
== (mDNS
*)~0)
882 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i
, i
->ifinfo
.ifname
);
885 for (t
= m
->TunnelClients
; t
; t
=t
->next
)
886 if (t
->next
== (ClientTunnel
*)~0 || t
->dstname
.c
[0] > 63)
887 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t
, t
->dstname
.c
[0]);
890 mDNSexport
void *mallocL(char *msg
, unsigned int size
)
892 // Allocate space for two words of sanity checking data before the requested block
893 mDNSu32
*mem
= malloc(sizeof(mDNSu32
) * 2 + size
);
895 { LogMsg("malloc( %s : %d ) failed", msg
, size
); return(NULL
); }
898 if (size
> 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg
, size
, &mem
[2]);
899 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
902 //mDNSPlatformMemZero(&mem[2], size);
903 memset(&mem
[2], 0xFF, size
);
904 validatelists(&mDNSStorage
);
909 mDNSexport
void freeL(char *msg
, void *x
)
912 LogMsg("free( %s @ NULL )!", msg
);
915 mDNSu32
*mem
= ((mDNSu32
*)x
) - 2;
916 if (mem
[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
917 if (mem
[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg
, mem
[1], &mem
[2]);
918 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
919 //mDNSPlatformMemZero(mem, sizeof(mDNSu32) * 2 + mem[1]);
920 memset(mem
, 0xFF, sizeof(mDNSu32
) * 2 + mem
[1]);
921 validatelists(&mDNSStorage
);
928 //*************************************************************************************************************
929 #if COMPILER_LIKES_PRAGMA_MARK
931 #pragma mark - Mach client request handlers
934 //*************************************************************************************************************
935 // Client Death Detection
937 // This gets called after ALL constituent records of the Service Record Set have been deregistered
938 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
940 ServiceRecordSet
*s
= &x
->srs
;
941 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
945 e
->r
.RecordContext
= e
;
948 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
951 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
952 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
954 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
955 freeL("ServiceInstance", x
);
958 // AbortClient finds whatever client is identified by the given Mach port,
959 // stops whatever operation that client was doing, and frees its memory.
960 // In the case of a service registration, the actual freeing may be deferred
961 // until we get the mStatus_MemFree message, if necessary
962 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
964 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
965 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
966 DNSServiceResolver
**l
= &DNSServiceResolverList
;
967 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
969 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
972 DNSServiceDomainEnumeration
*x
= *e
;
975 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
976 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
977 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
978 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
979 freeL("DNSServiceDomainEnumeration", x
);
983 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
986 DNSServiceBrowser
*x
= *b
;
987 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
992 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
993 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
994 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
997 freeL("DNSServiceBrowserQuestion", freePtr
);
1001 DNSServiceBrowserResult
*t
= x
->results
;
1002 x
->results
= x
->results
->next
;
1003 freeL("DNSServiceBrowserResult", t
);
1005 freeL("DNSServiceBrowser", x
);
1009 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
1012 DNSServiceResolver
*x
= *l
;
1015 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
1016 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
1017 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
1018 freeL("DNSServiceResolver", x
);
1022 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
1025 ServiceInstance
*si
= NULL
;
1026 DNSServiceRegistration
*x
= *r
;
1032 ServiceInstance
*instance
= si
;
1034 instance
->renameonmemfree
= mDNSfalse
;
1035 if (m
&& m
!= x
) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
), m
, x
);
1036 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
1038 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
1039 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
1040 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
1041 // the list, so we should go ahead and free the memory right now
1042 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
1045 freeL("DNSServiceRegistration", x
);
1049 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
1052 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
1054 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
1056 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1057 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1058 DNSServiceResolver
*l
= DNSServiceResolverList
;
1059 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1060 DNSServiceBrowserQuestion
*qptr
;
1062 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1063 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1064 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1065 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1067 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
1070 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1071 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
1073 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
1076 ServiceInstance
*si
;
1077 for (si
= r
->regs
; si
; si
= si
->next
)
1078 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
1080 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
1085 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
1087 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1088 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1089 DNSServiceResolver
*l
= DNSServiceResolverList
;
1090 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1091 DNSServiceBrowserQuestion
*qptr
;
1093 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1094 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1095 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1096 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1097 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1100 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1101 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1103 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1104 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1105 return(e
|| b
|| l
|| r
);
1108 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1110 KQueueLock(&mDNSStorage
);
1111 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1112 (void)unusedport
; // Unused
1113 (void)size
; // Unused
1114 (void)info
; // Unused
1115 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1117 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1118 AbortClient(deathMessage
->not_port
, NULL
);
1120 /* Deallocate the send right that came in the dead name notification */
1121 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1123 KQueueUnlock(&mDNSStorage
, "Mach AbortClient");
1126 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1129 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1130 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1131 // If the port already died while we were thinking about it, then abort the operation right away
1132 if (r
!= KERN_SUCCESS
)
1133 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1136 //*************************************************************************************************************
1137 // Domain Enumeration
1139 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
1141 kern_return_t status
;
1142 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1143 DNSServiceDomainEnumerationReplyResultType rt
;
1144 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1147 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1148 if (answer
->rrtype
!= kDNSType_PTR
) return;
1149 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1153 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1154 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1158 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1162 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1163 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1164 !AddRecord
? "RemoveDomain" :
1165 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1167 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1168 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1169 if (status
== MACH_SEND_TIMED_OUT
)
1170 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1173 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1176 // Check client parameter
1177 (void)unusedserver
; // Unused
1178 mStatus err
= mStatus_NoError
;
1179 const char *errormsg
= "Unknown";
1180 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1181 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1183 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1184 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1186 // Allocate memory, and handle failure
1187 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1188 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1190 // Set up object, and link into list
1191 x
->ClientMachPort
= client
;
1192 x
->next
= DNSServiceDomainEnumerationList
;
1193 DNSServiceDomainEnumerationList
= x
;
1195 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1198 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1199 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1200 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1202 // Succeeded: Wrap up and return
1203 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1204 EnableDeathNotificationForClient(client
, x
);
1205 return(mStatus_NoError
);
1208 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client
, regDom
, errormsg
, err
);
1212 //*************************************************************************************************************
1213 // Browse for services
1215 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
1219 if (answer
->rrtype
!= kDNSType_PTR
)
1220 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1223 domainname type
, domain
;
1224 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1226 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1227 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1231 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1232 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1234 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1235 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1237 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1238 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1241 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1242 DNSServiceBrowserResult
**p
= &browser
->results
;
1243 while (*p
) p
= &(*p
)->next
;
1246 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1247 browser
->ClientMachPort
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
1250 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1252 mStatus err
= mStatus_NoError
;
1253 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1255 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1257 if (SameDomainName(&ptr
->q
.qname
, d
))
1258 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1261 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1262 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1263 AssignDomainName(&question
->domain
, d
);
1264 question
->next
= browser
->qlist
;
1265 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1266 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1268 browser
->qlist
= question
;
1271 LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1272 freeL("DNSServiceBrowserQuestion", question
);
1277 mDNSexport
void machserver_automatic_browse_domain_changed(const domainname
*d
, mDNSBool add
)
1279 DNSServiceBrowser
*ptr
;
1280 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1282 if (ptr
->DefaultDomain
)
1286 mStatus err
= AddDomainToBrowser(ptr
, d
);
1287 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1291 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1294 if (SameDomainName(&(*q
)->domain
, d
))
1296 DNSServiceBrowserQuestion
*rem
= *q
;
1298 mDNS_StopQueryWithRemoves(&mDNSStorage
, &rem
->q
);
1299 freeL("DNSServiceBrowserQuestion", rem
);
1304 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1310 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1311 DNSCString regtype
, DNSCString domain
)
1313 // Check client parameter
1314 (void)unusedserver
; // Unused
1315 mStatus err
= mStatus_NoError
;
1316 const char *errormsg
= "Unknown";
1318 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1319 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1321 // Check other parameters
1324 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1325 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1326 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1327 { errormsg
= "Bad Service SubType"; goto badparam
; }
1328 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1330 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1331 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1333 // Allocate memory, and handle failure
1334 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1335 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1337 // Set up object, and link into list
1338 AssignDomainName(&x
->type
, &t
);
1339 x
->ClientMachPort
= client
;
1343 x
->next
= DNSServiceBrowserList
;
1344 DNSServiceBrowserList
= x
;
1348 // Start browser for an explicit domain
1349 x
->DefaultDomain
= mDNSfalse
;
1350 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1351 err
= AddDomainToBrowser(x
, &d
);
1352 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1356 DNameListElem
*sdPtr
;
1357 // Start browser on all domains
1358 x
->DefaultDomain
= mDNStrue
;
1359 if (!AutoBrowseDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1360 for (sdPtr
= AutoBrowseDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1362 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1365 // only terminally bail if .local fails
1366 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1367 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1368 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1373 // Succeeded: Wrap up and return
1374 EnableDeathNotificationForClient(client
, x
);
1375 return(mStatus_NoError
);
1378 err
= mStatus_BadParamErr
;
1380 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client
, regtype
, domain
, errormsg
, err
);
1384 //*************************************************************************************************************
1385 // Resolve Service Info
1387 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1389 kern_return_t status
;
1390 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1391 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1392 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1393 struct sockaddr_storage interface
;
1394 struct sockaddr_storage address
;
1396 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1399 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1401 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1403 mDNSPlatformMemZero(&interface
, sizeof(interface
));
1404 mDNSPlatformMemZero(&address
, sizeof(address
));
1406 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1408 struct sockaddr_in
*s
= (struct sockaddr_in
*)&interface
;
1409 s
->sin_len
= sizeof(*s
);
1410 s
->sin_family
= AF_INET
;
1412 s
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1414 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1416 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1417 sin6
->sin6_len
= sizeof(*sin6
);
1418 sin6
->sin6_family
= AF_INET6
;
1419 sin6
->sin6_flowinfo
= 0;
1420 sin6
->sin6_port
= 0;
1421 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1422 sin6
->sin6_scope_id
= ifx
->scope_id
;
1425 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1427 struct sockaddr_in
*s
= (struct sockaddr_in
*)&address
;
1428 s
->sin_len
= sizeof(*s
);
1429 s
->sin_family
= AF_INET
;
1430 s
->sin_port
= query
->info
->port
.NotAnInteger
;
1431 s
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1435 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1436 sin6
->sin6_len
= sizeof(*sin6
);
1437 sin6
->sin6_family
= AF_INET6
;
1438 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1439 sin6
->sin6_flowinfo
= 0;
1440 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1441 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1444 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1445 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1446 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1447 // ASCII-1 characters are used in the C-string as boundary markers,
1448 // to indicate the boundaries between the original constituent P-strings.
1449 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1452 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1456 pstrlen
= query
->info
->TXTinfo
[i
];
1459 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1461 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1462 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1463 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1464 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1465 if (status
== MACH_SEND_TIMED_OUT
)
1466 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1469 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1470 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1472 // Check client parameter
1473 (void)unusedserver
; // Unused
1474 mStatus err
= mStatus_NoError
;
1475 const char *errormsg
= "Unknown";
1476 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1477 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1479 // Check other parameters
1481 domainname t
, d
, srv
;
1482 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1483 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1484 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1485 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1487 // Allocate memory, and handle failure
1488 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1489 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1491 // Set up object, and link into list
1492 x
->ClientMachPort
= client
;
1493 x
->i
.InterfaceID
= mDNSInterface_Any
;
1495 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1496 x
->next
= DNSServiceResolverList
;
1497 DNSServiceResolverList
= x
;
1500 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1501 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1502 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1504 // Succeeded: Wrap up and return
1505 EnableDeathNotificationForClient(client
, x
);
1506 return(mStatus_NoError
);
1509 err
= mStatus_BadParamErr
;
1511 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client
, name
, regtype
, domain
, errormsg
, err
);
1515 //*************************************************************************************************************
1518 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1520 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1523 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1525 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1527 if (result
== mStatus_NoError
)
1529 kern_return_t status
;
1530 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1531 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1532 if (status
== MACH_SEND_TIMED_OUT
)
1533 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1534 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1535 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1538 else if (result
== mStatus_NameConflict
)
1540 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1541 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1542 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1543 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1545 // On conflict for an autoname service, rename and reregister *all* autoname services
1546 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1547 mDNS_ConfigChanged(m
);
1549 else if (si
->autoname
)
1551 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1556 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1557 // of their registration in the usual way (which we will catch via client death notification).
1558 // If the Mach queue is full, we forcibly abort the client immediately.
1559 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1560 if (status
== MACH_SEND_TIMED_OUT
)
1561 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1565 else if (result
== mStatus_MemFree
)
1567 if (si
->renameonmemfree
) // We intentionally terminated registration so we could re-register with new name
1569 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1570 si
->renameonmemfree
= mDNSfalse
;
1571 si
->name
= m
->nicelabel
;
1572 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1576 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1577 DNSServiceRegistration
*r
;
1578 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1580 ServiceInstance
**sp
= &r
->regs
;
1583 if (*sp
== si
) { LogMsg("RegCallback: %##s Still in list; removing", srs
->RR_SRV
.resrec
.name
->c
); *sp
= (*sp
)->next
; break; }
1588 FreeServiceInstance(si
);
1592 else if (result
!= mStatus_NATTraversal
)
1593 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1596 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1599 ServiceInstance
*si
= NULL
;
1600 AuthRecord
*SubTypes
= NULL
;
1602 for (si
= x
->regs
; si
; si
= si
->next
)
1604 if (SameDomainName(&si
->domain
, domain
))
1605 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1608 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1609 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1611 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1612 if (!si
) return mStatus_NoMemoryErr
;
1614 si
->ClientMachPort
= x
->ClientMachPort
;
1615 si
->renameonmemfree
= mDNSfalse
;
1616 si
->autoname
= x
->autoname
;
1617 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1618 si
->domain
= *domain
;
1620 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
,
1621 x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1629 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1630 freeL("ServiceInstance", si
);
1635 mDNSexport
void machserver_automatic_registration_domain_changed(const domainname
*d
, mDNSBool add
)
1637 DNSServiceRegistration
*reg
;
1639 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1641 if (reg
->DefaultDomain
)
1644 AddServiceInstance(reg
, d
);
1647 ServiceInstance
**si
= ®
->regs
;
1650 if (SameDomainName(&(*si
)->domain
, d
))
1652 ServiceInstance
*s
= *si
;
1654 if (mDNS_DeregisterService(&mDNSStorage
, &s
->srs
)) FreeServiceInstance(s
); // only free memory synchronously on error
1659 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1665 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1666 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1668 (void)unusedserver
; // Unused
1669 mStatus err
= mStatus_NoError
;
1670 const char *errormsg
= "Unknown";
1672 // older versions of this code passed the port via mach IPC as an int.
1673 // we continue to pass it as 4 bytes to maintain binary compatibility,
1674 // but now ensure that the network byte order is preserved by using a struct
1676 port
.b
[0] = IpPort
.bytes
[2];
1677 port
.b
[1] = IpPort
.bytes
[3];
1679 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1680 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1682 // Check for sub-types after the service type
1683 size_t reglen
= strlen(regtype
) + 1;
1684 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1685 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1686 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1688 // Check other parameters
1692 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1693 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1694 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1695 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1696 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1698 unsigned char txtinfo
[1024] = "";
1699 unsigned int data_len
= 0;
1700 unsigned int size
= sizeof(RDataBody
);
1701 unsigned char *pstring
= &txtinfo
[data_len
];
1702 char *ptr
= txtRecord
;
1704 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1705 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1706 // Hence we have to convert the C-string to a P-string.
1707 // ASCII-1 characters are allowed in the C-string as boundary markers,
1708 // so that a single C-string can be used to represent one or more P-strings.
1711 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1712 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1714 pstring
= &txtinfo
[data_len
];
1720 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1721 pstring
[++pstring
[0]] = *ptr
++;
1726 if (size
< data_len
)
1729 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1730 // a port number of zero. When two instances of the protected client are allowed to run on one
1731 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1732 if (!mDNSIPPortIsZero(port
))
1734 int count
= CountExistingRegistrations(&srv
, port
);
1736 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1737 client
, count
+1, srv
.c
, mDNSVal16(port
));
1740 // Allocate memory, and handle failure
1741 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1742 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1743 mDNSPlatformMemZero(x
, sizeof(*x
));
1745 // Set up object, and link into list
1746 x
->ClientMachPort
= client
;
1747 x
->DefaultDomain
= !domain
[0];
1748 x
->autoname
= (!name
[0]);
1750 x
->NumSubTypes
= NumSubTypes
;
1751 memcpy(x
->regtype
, regtype
, reglen
);
1755 memcpy(x
->txtinfo
, txtinfo
, 1024);
1756 x
->txt_len
= data_len
;
1760 x
->next
= DNSServiceRegistrationList
;
1761 DNSServiceRegistrationList
= x
;
1763 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1764 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1766 err
= AddServiceInstance(x
, &d
);
1767 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1769 if (x
->DefaultDomain
)
1772 for (p
= AutoRegistrationDomains
; p
; p
= p
->next
)
1773 AddServiceInstance(x
, &p
->name
);
1776 // Succeeded: Wrap up and return
1777 EnableDeathNotificationForClient(client
, x
);
1778 return(mStatus_NoError
);
1781 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1783 err
= mStatus_BadParamErr
;
1785 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)",
1786 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1790 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1793 if (result
== mStatus_NoError
)
1795 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
1796 LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1797 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1798 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1800 else if (result
== mStatus_NameConflict
)
1802 LogInfo("Local Hostname conflict for \"%#s.local\"", m
->hostlabel
.c
);
1803 if (!m
->p
->HostNameConflict
) m
->p
->HostNameConflict
= NonZeroTime(m
->timenow
);
1804 else if (m
->timenow
- m
->p
->HostNameConflict
> 60 * mDNSPlatformOneSecond
)
1806 // Tell the helper we've given up
1807 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, NULL
);
1810 else if (result
== mStatus_GrowCache
)
1812 // Allocate another chunk of cache storage
1813 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1814 //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
1815 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1817 else if (result
== mStatus_ConfigChanged
)
1819 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
1820 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
1821 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
1823 // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
1824 DNSServiceRegistration
*r
;
1825 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1828 ServiceInstance
*si
;
1829 for (si
= r
->regs
; si
; si
= si
->next
)
1831 if (!SameDomainLabelCS(si
->name
.c
, m
->nicelabel
.c
))
1833 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1834 si
->renameonmemfree
= mDNStrue
;
1835 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1836 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1841 // Then we call into the UDS daemon code, to let it do the same
1842 udsserver_handle_configchange(m
);
1846 //*************************************************************************************************************
1847 // Add / Update / Remove records from existing Registration
1849 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1850 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1852 // Check client parameter
1854 mStatus err
= mStatus_NoError
;
1855 const char *errormsg
= "Unknown";
1856 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1857 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1858 ServiceInstance
*si
;
1860 (void)unusedserver
; // Unused
1861 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1862 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1864 // Check other parameters
1865 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1866 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1867 else size
= sizeof(RDataBody
);
1870 *reference
= (natural_t
)id
;
1871 for (si
= x
->regs
; si
; si
= si
->next
)
1873 // Allocate memory, and handle failure
1874 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1875 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1877 // Fill in type, length, and data of new record
1878 extra
->r
.resrec
.rrtype
= type
;
1879 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1880 extra
->r
.resrec
.rdlength
= data_len
;
1881 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1884 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1885 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1886 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1890 freeL("Extra Resource Record", extra
);
1891 errormsg
= "mDNS_AddRecordToService";
1895 extra
->ClientID
= id
;
1898 return mStatus_NoError
;
1901 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client
, x
? x
->name
.c
: (mDNSu8
*)"\x8""«NULL»", type
, data_len
, errormsg
, err
);
1902 return mStatus_UnknownErr
;
1905 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1908 if (OldRData
!= &rr
->rdatastorage
)
1909 freeL("Old RData", OldRData
);
1912 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1914 // Check client parameter
1915 mStatus err
= mStatus_NoError
;
1916 const char *errormsg
= "Unknown";
1917 const domainname
*name
= (const domainname
*)"";
1919 name
= srs
->RR_SRV
.resrec
.name
;
1921 unsigned int size
= sizeof(RDataBody
);
1922 if (size
< data_len
)
1925 // Allocate memory, and handle failure
1926 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1927 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1929 // Fill in new length, and data
1930 newrdata
->MaxRDLength
= size
;
1931 memcpy(&newrdata
->u
, data
, data_len
);
1933 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1934 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1935 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1936 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1939 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1940 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1942 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1945 errormsg
= "mDNS_Update";
1946 freeL("RData", newrdata
);
1949 return(mStatus_NoError
);
1952 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client
, name
->c
, data_len
, errormsg
, err
);
1956 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1957 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1959 // Check client parameter
1960 mStatus err
= mStatus_NoError
;
1961 const char *errormsg
= "Unknown";
1962 const domainname
*name
= (const domainname
*)"";
1963 ServiceInstance
*si
;
1965 (void)unusedserver
; // unused
1966 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1967 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1968 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1969 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1971 // Check other parameters
1972 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1974 for (si
= x
->regs
; si
; si
= si
->next
)
1976 AuthRecord
*r
= NULL
;
1978 // Find the record we're updating. NULL reference means update the primary TXT record
1979 if (!reference
) r
= &si
->srs
.RR_TXT
;
1982 ExtraResourceRecord
*ptr
;
1983 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1985 if ((natural_t
)ptr
->ClientID
== reference
)
1986 { r
= &ptr
->r
; break; }
1988 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1990 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1991 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1994 return mStatus_NoError
;
1997 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2001 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2003 const domainname
*const name
= srs
->RR_SRV
.resrec
.name
;
2004 mStatus err
= mStatus_NoError
;
2007 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2009 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2010 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2015 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2016 natural_t reference
)
2018 // Check client parameter
2019 (void)unusedserver
; // Unused
2020 mStatus err
= mStatus_NoError
;
2021 const char *errormsg
= "Unknown";
2022 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2023 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2024 ServiceInstance
*si
;
2026 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2027 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2029 for (si
= x
->regs
; si
; si
= si
->next
)
2031 ExtraResourceRecord
*e
;
2032 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2034 if ((natural_t
)e
->ClientID
== reference
)
2036 err
= RemoveRecord(&si
->srs
, e
, client
);
2040 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2043 return mStatus_NoError
;
2046 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client
, reference
, errormsg
, err
);
2050 //*************************************************************************************************************
2051 #if COMPILER_LIKES_PRAGMA_MARK
2053 #pragma mark - Startup, shutdown, and supporting code
2056 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2058 mig_reply_error_t
*request
= msg
;
2059 mig_reply_error_t
*reply
;
2060 mach_msg_return_t mr
;
2062 (void)port
; // Unused
2063 (void)size
; // Unused
2064 (void)info
; // Unused
2066 KQueueLock(&mDNSStorage
);
2068 /* allocate a reply buffer */
2069 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2071 /* call the MiG server routine */
2072 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2074 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2076 if (reply
->RetCode
== MIG_NO_REPLY
)
2079 * This return code is a little tricky -- it appears that the
2080 * demux routine found an error of some sort, but since that
2081 * error would not normally get returned either to the local
2082 * user or the remote one, we pretend it's ok.
2084 CFAllocatorDeallocate(NULL
, reply
);
2089 * destroy any out-of-line data in the request buffer but don't destroy
2090 * the reply port right (since we need that to send an error message).
2092 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2093 mach_msg_destroy(&request
->Head
);
2096 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2098 /* no reply port, so destroy the reply */
2099 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2100 mach_msg_destroy(&reply
->Head
);
2101 CFAllocatorDeallocate(NULL
, reply
);
2108 * We don't want to block indefinitely because the client
2109 * isn't receiving messages from the reply port.
2110 * If we have a send-once right for the reply port, then
2111 * this isn't a concern because the send won't block.
2112 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2113 * To avoid falling off the kernel's fast RPC path unnecessarily,
2114 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2117 options
= MACH_SEND_MSG
;
2118 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2119 options
|= MACH_SEND_TIMEOUT
;
2121 mr
= mach_msg(&reply
->Head
, /* msg */
2122 options
, /* option */
2123 reply
->Head
.msgh_size
, /* send_size */
2125 MACH_PORT_NULL
, /* rcv_name */
2126 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2127 MACH_PORT_NULL
); /* notify */
2129 /* Has a message error occurred? */
2132 case MACH_SEND_INVALID_DEST
:
2133 case MACH_SEND_TIMED_OUT
:
2134 /* the reply can't be delivered, so destroy it */
2135 mach_msg_destroy(&reply
->Head
);
2139 /* Includes success case. */
2143 CFAllocatorDeallocate(NULL
, reply
);
2146 KQueueUnlock(&mDNSStorage
, "Mach client event");
2149 mDNSlocal kern_return_t
registerBootstrapService()
2151 kern_return_t status
;
2152 mach_port_t service_send_port
, service_rcv_port
;
2154 debugf("Registering Bootstrap Service");
2157 * See if our service name is already registered and if we have privilege to check in.
2159 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2160 if (status
== KERN_SUCCESS
)
2163 * If so, we must be a followup instance of an already defined server. In that case,
2164 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2165 * that in case we have to unregister later (which requires the privilege port).
2167 server_priv_port
= bootstrap_port
;
2168 restarting_via_mach_init
= TRUE
;
2170 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2172 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2173 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2174 if (status
!= KERN_SUCCESS
) return status
;
2176 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2177 if (status
!= KERN_SUCCESS
)
2179 mach_port_deallocate(mach_task_self(), server_priv_port
);
2183 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2184 if (status
!= KERN_SUCCESS
)
2186 mach_port_deallocate(mach_task_self(), server_priv_port
);
2187 mach_port_deallocate(mach_task_self(), service_send_port
);
2190 assert(service_send_port
== service_rcv_port
);
2194 * We have no intention of responding to requests on the service port. We are not otherwise
2195 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2196 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2197 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2199 mach_port_destroy(mach_task_self(), service_rcv_port
);
2203 mDNSlocal kern_return_t
destroyBootstrapService()
2205 debugf("Destroying Bootstrap Service");
2206 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2209 mDNSlocal
void ExitCallback(int sig
)
2211 (void)sig
; // Unused
2212 LogMsg("%s stopping", mDNSResponderVersionString
);
2214 debugf("ExitCallback");
2215 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2216 destroyBootstrapService();
2218 debugf("ExitCallback: Aborting MIG clients");
2219 while (DNSServiceDomainEnumerationList
)
2220 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2221 while (DNSServiceBrowserList
)
2222 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2223 while (DNSServiceResolverList
)
2224 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2225 while (DNSServiceRegistrationList
)
2226 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2228 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2230 debugf("ExitCallback: mDNS_StartExit");
2231 mDNS_StartExit(&mDNSStorage
);
2234 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2235 mDNSlocal
void HandleSIG(int sig
)
2237 // WARNING: can't call syslog or fprintf from signal handler
2238 mach_msg_header_t header
;
2239 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2240 header
.msgh_remote_port
= signal_port
;
2241 header
.msgh_local_port
= MACH_PORT_NULL
;
2242 header
.msgh_size
= sizeof(header
);
2243 header
.msgh_id
= sig
;
2244 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2245 if (sig
== SIGTERM
|| sig
== SIGINT
) exit(-1);
2248 mDNSlocal
void CatchABRT(int sig
)
2250 // WARNING: can't call syslog or fprintf from signal handler
2251 // We want a CrashReporter stack trace so we can find out what library called abort()
2252 // So that we will crash, unblock all signals (that abort() may have blocked)
2255 sigprocmask(SIG_UNBLOCK
, &mask
, NULL
);
2257 while(1) *(long*)0 = 0;
2260 mDNSlocal
void INFOCallback(void)
2262 mDNSs32 utc
= mDNSPlatformUTC();
2263 DNSServiceDomainEnumeration
*e
;
2264 DNSServiceBrowser
*b
;
2265 DNSServiceResolver
*l
;
2266 DNSServiceRegistration
*r
;
2267 NetworkInterfaceInfoOSX
*i
;
2270 LogMsg("---- BEGIN STATE LOG ----");
2272 udsserver_info(&mDNSStorage
);
2274 LogMsgNoIdent("--------- Mach Clients ---------");
2275 if (!DNSServiceDomainEnumerationList
&& !DNSServiceBrowserList
&& !DNSServiceResolverList
&& !DNSServiceRegistrationList
)
2276 LogMsgNoIdent("<None>");
2279 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2280 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2282 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2284 DNSServiceBrowserQuestion
*qptr
;
2285 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2286 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2288 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2289 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2291 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2293 ServiceInstance
*si
;
2294 for (si
= r
->regs
; si
; si
= si
->next
)
2295 LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si
->ClientMachPort
, si
->srs
.RR_SRV
.resrec
.name
->c
, mDNSVal16(si
->srs
.RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2299 LogMsgNoIdent("----- KQSocketEventSources -----");
2300 if (!gEventSources
) LogMsgNoIdent("<None>");
2303 KQSocketEventSource
*k
;
2304 for (k
= gEventSources
; k
; k
=k
->next
)
2305 LogMsgNoIdent("%3d %s", k
->fd
, k
->kqs
.KQtask
);
2308 LogMsgNoIdent("------ Network Interfaces ------");
2309 if (!mDNSStorage
.p
->InterfaceList
) LogMsgNoIdent("<None>");
2312 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2314 // Allow six characters for interface name, for names like "vmnet8"
2316 LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
2317 i
->ifinfo
.InterfaceID
,
2318 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, i
->scope_id
, &i
->ifinfo
.MAC
, &i
->BSSID
,
2319 &i
->ifinfo
.ip
, utc
- i
->LastSeen
);
2322 const CacheRecord
*sps
[3];
2323 FindSPSInCache(&mDNSStorage
, &i
->ifinfo
.NetWakeBrowse
, sps
);
2324 LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a",
2325 i
->ifinfo
.InterfaceID
,
2326 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, i
->scope_id
, &i
->ifinfo
.MAC
, &i
->BSSID
,
2327 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2328 i
->ifinfo
.IPv4Available
? "v4" : " ",
2329 i
->ifinfo
.IPv4Available
? (mDNSv4Addr
*)&i
->ifa_v4addr
: &zerov4Addr
,
2330 i
->ifinfo
.IPv6Available
? "v6" : " ",
2331 i
->ifinfo
.Advertise
? "⊙" : " ",
2332 i
->ifinfo
.McastTxRx
? "⇆" : " ",
2333 !(i
->ifinfo
.InterfaceActive
&& i
->ifinfo
.NetWake
) ? " " : !sps
[0] ? "☼" : "☀",
2336 if (sps
[0]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[0]->resrec
.rdata
->u
.name
.c
), sps
[0]->resrec
.rdata
->u
.name
.c
);
2337 if (sps
[1]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[1]->resrec
.rdata
->u
.name
.c
), sps
[1]->resrec
.rdata
->u
.name
.c
);
2338 if (sps
[2]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[2]->resrec
.rdata
->u
.name
.c
), sps
[2]->resrec
.rdata
->u
.name
.c
);
2343 LogMsgNoIdent("--------- DNS Servers ----------");
2344 if (!mDNSStorage
.DNSServers
) LogMsgNoIdent("<None>");
2347 for (s
= mDNSStorage
.DNSServers
; s
; s
= s
->next
)
2349 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)s
->interface
;
2350 LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
2351 s
->domain
.c
, ifx
? ifx
->ifinfo
.ifname
: "", ifx
? " " : "", &s
->addr
, mDNSVal16(s
->port
),
2352 s
->teststate
== DNSServer_Untested
? "(Untested)" :
2353 s
->teststate
== DNSServer_Passed
? "" :
2354 s
->teststate
== DNSServer_Failed
? "(Failed)" :
2355 s
->teststate
== DNSServer_Disabled
? "(Disabled)" : "(Unknown state)");
2359 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
2360 LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32
)now
, now
);
2362 LogMsg("---- END STATE LOG ----");
2365 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2367 (void)port
; // Unused
2368 (void)size
; // Unused
2369 (void)info
; // Unused
2370 mach_msg_header_t
*msg_header
= (mach_msg_header_t
*)msg
;
2371 mDNS
*const m
= &mDNSStorage
;
2373 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
2375 switch(msg_header
->msgh_id
)
2381 LogMsg("SIGHUP: Purge cache");
2383 FORALL_CACHERECORDS(slot
, cg
, rr
) mDNS_PurgeCacheResourceRecord(m
, rr
);
2384 // Restart unicast and multicast queries
2385 mDNSCoreRestartQueries(m
);
2389 case SIGTERM
: ExitCallback(msg_header
->msgh_id
); break;
2390 case SIGINFO
: INFOCallback(); break;
2391 case SIGUSR1
: mDNS_LoggingEnabled
= mDNS_LoggingEnabled
? 0 : 1;
2392 LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled
? "Enabled" : "Disabled");
2393 WatchDogReportingThreshold
= mDNS_LoggingEnabled
? 50 : 250;
2395 case SIGUSR2
: mDNS_PacketLoggingEnabled
= mDNS_PacketLoggingEnabled
? 0 : 1;
2396 LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled
? "Enabled" : "Disabled");
2398 default: LogMsg("SignalCallback: Unknown signal %d", msg_header
->msgh_id
); break;
2400 KQueueUnlock(m
, "Unix Signal");
2403 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2404 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2406 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2409 CFMachPortRef s_port
;
2411 // If launchd already created our Mach port for us, then use that, else we create a new one of our own
2412 if (m_port
!= MACH_PORT_NULL
)
2413 s_port
= CFMachPortCreateWithPort(NULL
, m_port
, DNSserverCallback
, NULL
, NULL
);
2416 s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2417 m_port
= CFMachPortGetPort(s_port
);
2418 char *MachServerName
= OSXVers
< OSXVers_10_3_Panther
? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2419 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2424 LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
2426 LogMsg("bootstrap_register() failed: %s %d", mach_error_string(status
), status
);
2431 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2432 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2433 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2434 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2435 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2437 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2438 rrcachestorage
, RR_CACHE_SIZE
,
2440 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2442 if (err
) { LogMsg("Daemon start: mDNS_Init failed %d", err
); return(err
); }
2444 client_death_port
= CFMachPortGetPort(d_port
);
2445 signal_port
= CFMachPortGetPort(i_port
);
2447 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, d_rls
, kCFRunLoopDefaultMode
);
2448 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, s_rls
, kCFRunLoopDefaultMode
);
2449 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, i_rls
, kCFRunLoopDefaultMode
);
2453 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2457 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2459 mDNSs32 now
= mDNS_TimeNow(m
);
2461 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2463 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2464 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2465 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2466 // we then systematically lose our own looped-back packets.
2467 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2469 if (m
->p
->RequestReSleep
&& now
- m
->p
->RequestReSleep
>= 0) { m
->p
->RequestReSleep
= 0; mDNSPowerRequest(0, 0); }
2471 // KeyChain frequently fails to notify clients of change events. To work around this
2472 // we set a timer and periodically poll to detect if any changes have occurred.
2473 // Without this Back To My Mac just does't work for a large number of users.
2474 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
2475 if (m
->p
->KeyChainBugTimer
&& now
- m
->p
->KeyChainBugTimer
>= 0)
2477 m
->p
->KeyChainBugInterval
*= 2;
2478 m
->p
->KeyChainBugTimer
= NonZeroTime(now
+ m
->p
->KeyChainBugInterval
);
2479 if (m
->p
->KeyChainBugInterval
> 2 * mDNSPlatformOneSecond
) m
->p
->KeyChainBugTimer
= 0;
2481 SetDomainSecrets(m
);
2485 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2486 mDNSs32 nextevent
= mDNS_Execute(m
);
2488 if (m
->p
->NetworkChanged
)
2489 if (nextevent
- m
->p
->NetworkChanged
> 0)
2490 nextevent
= m
->p
->NetworkChanged
;
2492 if (m
->p
->KeyChainBugTimer
)
2493 if (nextevent
- m
->p
->KeyChainBugTimer
> 0)
2494 nextevent
= m
->p
->KeyChainBugTimer
;
2496 if (m
->p
->RequestReSleep
)
2497 if (nextevent
- m
->p
->RequestReSleep
> 0)
2498 nextevent
= m
->p
->RequestReSleep
;
2500 // 3. Deliver any waiting browse messages to clients
2501 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2505 // Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2506 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2507 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2508 DNSServiceBrowser
*x
= b
;
2510 if (x
->results
) // Try to deliver the list of results
2514 DNSServiceBrowserResult
*const r
= x
->results
;
2516 domainname type
, domain
;
2517 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2518 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2519 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2520 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2521 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2522 ConvertDomainNameToCString(&type
, ctype
);
2523 ConvertDomainNameToCString(&domain
, cdom
);
2524 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2525 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2526 // If we failed to send the mach message, try again in one second
2527 if (status
== MACH_SEND_TIMED_OUT
)
2529 if (nextevent
- now
> mDNSPlatformOneSecond
)
2530 nextevent
= now
+ mDNSPlatformOneSecond
;
2535 x
->lastsuccess
= now
;
2536 x
->results
= x
->results
->next
;
2537 freeL("DNSServiceBrowserResult", r
);
2540 // If this client hasn't read a single message in the last 60 seconds, abort it
2541 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2542 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2546 DNSServiceResolver
*l
;
2547 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2548 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2551 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2552 "This places considerable burden on the network.", l
->i
.name
.c
);
2555 if (m
->p
->NotifyUser
)
2557 if (m
->p
->NotifyUser
- now
< 0)
2559 if (!SameDomainLabelCS(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2561 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2562 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
2563 m
->p
->usernicelabel
= m
->nicelabel
;
2565 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2567 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2568 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
2569 m
->p
->HostNameConflict
= 0; // Clear our indicator, now name change has been successful
2570 m
->p
->userhostlabel
= m
->hostlabel
;
2572 m
->p
->NotifyUser
= 0;
2575 if (nextevent
- m
->p
->NotifyUser
> 0)
2576 nextevent
= m
->p
->NotifyUser
;
2582 // Right now we consider *ALL* of our DHCP leases
2583 // It might make sense to be a bit more selective and only consider the leases on interfaces
2584 // (a) that are capable and enabled for wake-on-LAN, and
2585 // (b) where we have found (and successfully registered with) a Sleep Proxy
2586 // If we can't be woken for traffic on a given interface, then why keep waking to renew its lease?
2587 mDNSlocal mDNSu32
DHCPWakeTime(void)
2589 mDNSu32 e
= 24 * 3600; // Maximum maintenance wake interval is 24 hours
2590 const CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
2591 if (!now
) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed");
2594 const SCPreferencesRef prefs
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder:DHCPWakeTime"), NULL
);
2595 if (!prefs
) LogMsg("DHCPWakeTime: SCPreferencesCreate failed");
2598 const SCNetworkSetRef currentset
= SCNetworkSetCopyCurrent(prefs
);
2599 if (!currentset
) LogMsg("DHCPWakeTime: SCNetworkSetCopyCurrent failed");
2602 const CFArrayRef services
= SCNetworkSetCopyServices(currentset
);
2603 if (!services
) LogMsg("DHCPWakeTime: SCNetworkSetCopyServices failed");
2607 for (i
= 0; i
< CFArrayGetCount(services
); i
++)
2609 const SCNetworkServiceRef service
= CFArrayGetValueAtIndex(services
, i
);
2610 if (!service
) LogMsg("DHCPWakeTime: CFArrayGetValueAtIndex %d failed", i
);
2613 const CFStringRef serviceid
= SCNetworkServiceGetServiceID(service
);
2614 if (!serviceid
) LogMsg("DHCPWakeTime: SCNetworkServiceGetServiceID %d failed", i
);
2617 // Note: It's normal for this call to return NULL, for interfaces not using DHCP
2618 const CFDictionaryRef dhcp
= SCDynamicStoreCopyDHCPInfo(NULL
, serviceid
);
2621 const CFDateRef start
= DHCPInfoGetLeaseStartTime(dhcp
);
2622 const CFDataRef lease
= DHCPInfoGetOptionData(dhcp
, 51); // Option 51 = IP Address Lease Time
2623 if (!start
|| !lease
|| CFDataGetLength(lease
) < 4)
2624 LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed "
2625 "CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d",
2626 i
, start
, lease
, lease
? CFDataGetLength(lease
) : 0);
2629 const UInt8
*d
= CFDataGetBytePtr(lease
);
2630 if (!d
) LogMsg("DHCPWakeTime: CFDataGetBytePtr %d failed", i
);
2633 const mDNSu32 elapsed
= now
- CFDateGetAbsoluteTime(start
);
2634 const mDNSu32 lifetime
= (mDNSs32
) ((mDNSs32
)d
[0] << 24 | (mDNSs32
)d
[1] << 16 | (mDNSs32
)d
[2] << 8 | d
[3]);
2635 const mDNSu32 remaining
= lifetime
- elapsed
;
2636 const mDNSu32 wake
= remaining
> 60 ? remaining
- remaining
/10 : 54; // Wake at 90% of the lease time
2637 LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed
, lifetime
, remaining
, wake
);
2638 if (e
> wake
) e
= wake
;
2646 CFRelease(services
);
2648 CFRelease(currentset
);
2656 // We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it.
2657 // For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour.
2658 // If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping
2659 // for a few seconds and then waking again is silly and annoying.
2660 // If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease.
2661 // Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still
2662 // allowing us an adequate safety margin to renew our lease before we lose it.
2664 mDNSlocal mDNSBool
AllowSleepNow(mDNS
*const m
, mDNSs32 now
)
2666 mDNSBool ready
= mDNSCoreReadyForSleep(m
);
2667 if (m
->SleepState
&& !ready
&& now
- m
->SleepLimit
< 0) return(mDNSfalse
);
2669 m
->p
->WakeAtUTC
= 0;
2670 int result
= kIOReturnSuccess
;
2671 CFDictionaryRef opts
= NULL
;
2673 // If the sleep request was cancelled, and we're no longer planning to sleep, don't need to
2674 // do the stuff below, but we *DO* still need to acknowledge the sleep message we received.
2676 LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m
->SleepLimit
- now
);
2679 if (!m
->SystemWakeOnLANEnabled
|| !mDNSCoreHaveAdvertisedMulticastServices(m
))
2680 LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services",
2681 m
->SystemWakeOnLANEnabled
? "is" : "not",
2682 mDNSCoreHaveAdvertisedMulticastServices(m
) ? "have" : "no");
2685 mDNSs32 dhcp
= DHCPWakeTime();
2686 LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp
);
2687 mDNSs32 interval
= mDNSCoreIntervalToNextWake(m
, now
) / mDNSPlatformOneSecond
;
2688 if (interval
> dhcp
) interval
= dhcp
;
2690 // If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of
2691 // transient network problem) then schedule a wakeup in one hour to try again. Otherwise,
2692 // a single SPS failure could result in a remote machine falling permanently asleep, requiring
2693 // someone to go to the machine in person to wake it up again, which would be unacceptable.
2694 if (!ready
&& interval
> 3600) interval
= 3600;
2696 //interval = 48; // For testing
2698 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2699 if (m
->p
->IOPMConnection
) // If lightweight-wake capability is available, use that
2701 const CFDateRef WakeDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
2702 if (!WakeDate
) LogMsg("ScheduleNextWake: CFDateCreate failed");
2705 const mDNSs32 reqs
= kIOPMSystemPowerStateCapabilityNetwork
;
2706 const CFNumberRef Requirements
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &reqs
);
2707 if (!Requirements
) LogMsg("ScheduleNextWake: CFNumberCreate failed");
2710 const void *OptionKeys
[2] = { CFSTR("WakeDate"), CFSTR("Requirements") };
2711 const void *OptionVals
[2] = { WakeDate
, Requirements
};
2712 opts
= CFDictionaryCreate(NULL
, (void*)OptionKeys
, (void*)OptionVals
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2713 if (!opts
) LogMsg("ScheduleNextWake: CFDictionaryCreate failed");
2714 CFRelease(Requirements
);
2716 CFRelease(WakeDate
);
2718 LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval
);
2720 else // else schedule the wakeup using the old API instead to
2723 // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
2724 // so we should put it back to sleep. To avoid frustrating the user, we always request at least
2725 // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep,
2726 // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine.
2727 if (interval
< 60) interval
= 60;
2729 result
= mDNSPowerRequest(1, interval
);
2731 if (result
== kIOReturnNotReady
)
2733 LogMsg("Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval
);
2734 // IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the
2735 // requested wake time is "too soon", but there's no API to find out what constitutes
2736 // "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady
2737 // we just have to iterate with successively longer intervals until it doesn't fail.
2738 // Additionally, if our power request is deemed "too soon" for the machine to get to
2739 // sleep and wake back up again, we attempt to cancel the sleep request, since the
2740 // implication is that the system won't manage to be awake again at the time we need it.
2743 interval
+= (interval
< 20) ? 1 : ((interval
+3) / 4);
2744 result
= mDNSPowerRequest(1, interval
);
2746 while (result
== kIOReturnNotReady
);
2749 if (result
) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval
, result
, result
);
2750 else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval
);
2751 m
->p
->WakeAtUTC
= mDNSPlatformUTC() + interval
;
2755 // Clear our interface list to empty state, ready to go to sleep
2756 // As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete
2757 m
->SleepState
= SleepState_Sleeping
;
2758 mDNSMacOSXNetworkChanged(m
);
2761 LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
2762 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2763 (m
->p
->IOPMConnection
) ? "IOPMConnectionAcknowledgeEventWithOptions" :
2765 (result
== kIOReturnSuccess
) ? "IOAllowPowerChange" : "IOCancelPowerChange",
2766 m
->p
->SleepCookie
, ready
? "ready for sleep" : "giving up", now
, m
->SleepLimit
- now
);
2768 m
->SleepLimit
= 0; // Don't clear m->SleepLimit until after we've logged it above
2770 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2771 if (m
->p
->IOPMConnection
) IOPMConnectionAcknowledgeEventWithOptions(m
->p
->IOPMConnection
, m
->p
->SleepCookie
, opts
);
2774 if (result
== kIOReturnSuccess
) IOAllowPowerChange (m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2775 else IOCancelPowerChange(m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2777 if (opts
) CFRelease(opts
);
2781 mDNSlocal
void KQWokenFlushBytes(int fd
, __unused
short filter
, __unused
void *context
)
2783 // Read all of the bytes so we won't wake again.
2785 while (recv(fd
, buffer
, sizeof(buffer
), MSG_DONTWAIT
) > 0) continue;
2788 mDNSlocal
void * KQueueLoop(void *m_param
)
2793 #if USE_SELECT_WITH_KQUEUEFD
2796 const int multiplier
= 1000000 / mDNSPlatformOneSecond
;
2798 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
2801 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2802 LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2804 // This is the main work loop:
2805 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2806 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2807 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2808 // (4) On wakeup we first process *all* events
2809 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2812 #define kEventsToReadAtOnce 1
2813 struct kevent new_events
[kEventsToReadAtOnce
];
2815 // Run mDNS_Execute to find out the time we next need to wake up
2816 mDNSs32 start
= mDNSPlatformRawTime();
2817 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
2818 mDNSs32 end
= mDNSPlatformRawTime();
2819 if (end
- start
>= WatchDogReportingThreshold
)
2820 LogInfo("WARNING: Idle task took %dms to complete", end
- start
);
2822 mDNSs32 now
= mDNS_TimeNow(m
);
2824 if (m
->ShutdownTime
)
2826 if (mDNSStorage
.ResourceRecords
)
2828 LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m
, mDNSStorage
.ResourceRecords
));
2829 if (mDNS_LoggingEnabled
) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
2831 if (mDNSStorage
.ServiceRegistrations
)
2832 LogInfo("Cannot exit yet; ServiceRegistrations still exists: %s", ARDisplayString(m
, &mDNSStorage
.ServiceRegistrations
->RR_SRV
));
2833 if (mDNS_ExitNow(m
, now
))
2835 if (!mDNSStorage
.ResourceRecords
&& !mDNSStorage
.ServiceRegistrations
)
2836 safe_vproc_transaction_end();
2837 LogInfo("mDNS_FinalExit");
2838 mDNS_FinalExit(&mDNSStorage
);
2839 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
2842 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
2843 nextTimerEvent
= m
->ShutdownTime
;
2847 if (!AllowSleepNow(m
, now
))
2848 if (nextTimerEvent
- m
->SleepLimit
>= 0)
2849 nextTimerEvent
= m
->SleepLimit
;
2851 // Convert absolute wakeup time to a relative time from now
2852 mDNSs32 ticks
= nextTimerEvent
- now
;
2853 if (ticks
< 1) ticks
= 1;
2855 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2861 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2864 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2867 // Release the lock, and sleep until:
2868 // 1. Something interesting happens like a packet arriving, or
2869 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
2870 // 3. The timeout expires
2871 pthread_mutex_unlock(&PlatformStorage
.BigMutex
);
2873 #if USE_SELECT_WITH_KQUEUEFD
2874 struct timeval timeout
;
2875 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2876 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2877 FD_SET(KQueueFD
, &readfds
);
2878 if (select(KQueueFD
+1, &readfds
, NULL
, NULL
, &timeout
) < 0)
2879 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2881 struct timespec timeout
;
2882 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2883 timeout
.tv_nsec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2884 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
2885 // and have it work similarly to the way it does with nevents non-zero --
2886 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
2887 // In fact, what happens if you do this is that it just returns immediately. So, we have
2888 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
2889 if (kevent(KQueueFD
, NULL
, 0, new_events
, 1, &timeout
) < 0)
2890 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2893 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2894 // We have to ignore the event we may have been told about above, because that
2895 // was done without holding the lock, and between the time we woke up and the
2896 // time we reclaimed the lock the other thread could have done something that
2897 // makes the event no longer valid. Now we have the lock, we call kevent again
2898 // and this time we can safely process the events it tells us about.
2900 static const struct timespec zero_timeout
= { 0, 0 };
2902 while ((events_found
= kevent(KQueueFD
, NULL
, 0, new_events
, kEventsToReadAtOnce
, &zero_timeout
)) != 0)
2904 if (events_found
> kEventsToReadAtOnce
|| (events_found
< 0 && errno
!= EINTR
))
2906 // Not sure what to do here, our kqueue has failed us - this isn't ideal
2907 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno
, strerror(errno
));
2911 numevents
+= events_found
;
2914 for (i
= 0; i
< events_found
; i
++)
2916 const KQueueEntry
*const kqentry
= new_events
[i
].udata
;
2917 mDNSs32 stime
= mDNSPlatformRawTime();
2918 const char *const KQtask
= kqentry
->KQtask
; // Grab a copy in case KQcallback deletes the task
2919 kqentry
->KQcallback(new_events
[i
].ident
, new_events
[i
].filter
, kqentry
->KQcontext
);
2920 mDNSs32 etime
= mDNSPlatformRawTime();
2921 if (etime
- stime
>= WatchDogReportingThreshold
)
2922 LogInfo("WARNING: %s took %dms to complete", KQtask
, etime
- stime
);
2930 mDNSlocal
void LaunchdCheckin(void)
2932 launch_data_t msg
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
2933 launch_data_t resp
= launch_msg(msg
);
2934 launch_data_free(msg
);
2935 if (!resp
) { LogMsg("launch_msg returned NULL"); return; }
2937 if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
)
2939 int err
= launch_data_get_errno(resp
);
2940 // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
2941 if (err
!= EACCES
) LogMsg("launch_msg returned %d", err
);
2942 else LogInfo("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err
);
2946 launch_data_t skts
= launch_data_dict_lookup(resp
, LAUNCH_JOBKEY_SOCKETS
);
2947 if (!skts
) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
2950 launch_data_t skt
= launch_data_dict_lookup(skts
, "Listeners");
2951 if (!skt
) LogMsg("launch_data_dict_lookup Listeners returned NULL");
2954 launchd_fds_count
= launch_data_array_get_count(skt
);
2955 if (launchd_fds_count
== 0) LogMsg("launch_data_array_get_count(skt) returned 0");
2958 launchd_fds
= mallocL("LaunchdCheckin", sizeof(dnssd_sock_t
) * launchd_fds_count
);
2959 if (!launchd_fds
) LogMsg("LaunchdCheckin: malloc failed");
2963 for(i
= 0; i
< launchd_fds_count
; i
++)
2965 launch_data_t s
= launch_data_array_get_index(skt
, i
);
2968 launchd_fds
[i
] = dnssd_InvalidSocket
;
2969 LogMsg("launch_data_array_get_index(skt, %d) returned NULL", i
);
2973 launchd_fds
[i
] = launch_data_get_fd(s
);
2974 LogInfo("Launchd Unix Domain Socket [%d]: %d", i
, launchd_fds
[i
]);
2978 // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
2979 chmod(MDNS_UDS_SERVERPATH
, S_IRUSR
|S_IWUSR
| S_IRGRP
|S_IWGRP
| S_IROTH
|S_IWOTH
);
2984 launch_data_t ports
= launch_data_dict_lookup(resp
, "MachServices");
2985 if (!ports
) LogMsg("launch_data_dict_lookup MachServices returned NULL");
2988 launch_data_t p
= launch_data_dict_lookup(ports
, "com.apple.mDNSResponder");
2989 if (!p
) LogInfo("launch_data_dict_lookup(ports, \"com.apple.mDNSResponder\") returned NULL");
2992 m_port
= launch_data_get_fd(p
);
2993 LogInfo("Launchd Mach Port: %d", m_port
);
2994 if (m_port
== ~0U) m_port
= MACH_PORT_NULL
;
2998 launch_data_free(resp
);
3001 mDNSlocal
void DropPrivileges(void)
3003 static const char login
[] = "_mdnsresponder";
3004 struct passwd
*pwd
= getpwnam(login
);
3006 LogMsg("Could not find account name \"%s\". Running as root.", login
);
3009 uid_t uid
= pwd
->pw_uid
;
3010 gid_t gid
= pwd
->pw_gid
;
3012 LogMsg("Started as root. Switching to userid \"%s\".", login
);
3014 if (unlink(MDNS_UDS_SERVERPATH
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, errno
, strerror(errno
));
3017 static char path
[] = "/var/run/mdns/mDNSResponder";
3018 char *p
= strrchr(path
, '/');
3020 if (mkdir(path
, 0755) < 0 && errno
!= EEXIST
) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3021 else if (chown(path
, uid
, gid
) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3025 if (unlink(path
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3026 else if (symlink(path
, MDNS_UDS_SERVERPATH
) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, path
, errno
, strerror(errno
));
3027 else LogInfo("DropPrivileges: Created subdirectory and symlink");
3031 if (0 != initgroups(login
, gid
)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login
, (unsigned long)gid
);
3032 if (0 != setgid(gid
)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
3033 if (0 != setuid(uid
)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid
);
3037 extern int sandbox_init(const char *profile
, uint64_t flags
, char **errorbuf
) __attribute__((weak_import
));
3039 mDNSexport
int main(int argc
, char **argv
)
3042 kern_return_t status
;
3043 pthread_t KQueueThread
;
3045 LogMsg("%s starting", mDNSResponderVersionString
);
3048 LogMsg("CacheRecord %d", sizeof(CacheRecord
));
3049 LogMsg("CacheGroup %d", sizeof(CacheGroup
));
3050 LogMsg("ResourceRecord %d", sizeof(ResourceRecord
));
3051 LogMsg("RData_small %d", sizeof(RData_small
));
3053 LogMsg("sizeof(CacheEntity) %d", sizeof(CacheEntity
));
3054 LogMsg("RR_CACHE_SIZE %d", RR_CACHE_SIZE
);
3055 LogMsg("block usage %d", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
3056 LogMsg("block wastage %d", 16*1024 - sizeof(CacheEntity
) * RR_CACHE_SIZE
);
3059 safe_vproc_transaction_begin();
3061 if (0 == geteuid()) DropPrivileges();
3063 for (i
=1; i
<argc
; i
++)
3065 if (!strcasecmp(argv
[i
], "-d" )) mDNS_DebugMode
= mDNStrue
;
3066 if (!strcasecmp(argv
[i
], "-launchd" )) started_via_launchdaemon
= mDNStrue
;
3067 if (!strcasecmp(argv
[i
], "-launchdaemon" )) started_via_launchdaemon
= mDNStrue
;
3068 if (!strcasecmp(argv
[i
], "-NoMulticastAdvertisements")) advertise
= mDNS_Init_DontAdvertiseLocalAddresses
;
3069 if (!strcasecmp(argv
[i
], "-DebugLogging" )) mDNS_LoggingEnabled
= mDNStrue
;
3070 if (!strcasecmp(argv
[i
], "-UnicastPacketLogging" )) mDNS_PacketLoggingEnabled
= mDNStrue
;
3071 if (!strcasecmp(argv
[i
], "-OfferSleepProxyService" ))
3072 OfferSleepProxyService
= (i
+1<argc
&& mDNSIsDigit(argv
[i
+1][0]) && mDNSIsDigit(argv
[i
+1][1]) && argv
[i
+1][2]==0) ? atoi(argv
[++i
]) : 80;
3075 // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
3076 if (!advertise
) LogMsg("Administratively prohibiting multicast advertisements");
3078 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
3080 signal(SIGHUP
, HandleSIG
); // (Debugging) Purge the cache to check for cache handling bugs
3081 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
3082 // On 10.5 and later, the default action for SIGABRT is to generate a crash report, so we only need our CatchABRT handler on 10.4
3083 if (OSXVers
<= OSXVers_10_4_Tiger
)
3085 LogInfo("Adding SIGABRT handler");
3086 signal(SIGABRT
, CatchABRT
); // For debugging -- SIGABRT should never happen
3088 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
3089 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
3090 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
3091 signal(SIGUSR1
, HandleSIG
); // (Debugging) Enable Logging
3092 signal(SIGUSR2
, HandleSIG
); // (Debugging) Enable Packet Logging
3094 mDNSStorage
.p
= &PlatformStorage
; // Make sure mDNSStorage.p is set up, because validatelists uses it
3097 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
3098 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
3100 registerBootstrapService();
3101 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
3102 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
3103 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
3106 // Avoid unnecessarily duplicating a file descriptor to itself
3107 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3108 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3109 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3110 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
3114 // Create the kqueue, mutex and thread to support KQSockets
3115 KQueueFD
= kqueue();
3116 if (KQueueFD
== -1) { LogMsg("kqueue() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3118 i
= pthread_mutex_init(&PlatformStorage
.BigMutex
, NULL
);
3119 if (i
== -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3121 int fdpair
[2] = {0, 0};
3122 i
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
);
3123 if (i
== -1) { LogMsg("socketpair() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3125 // Socket pair returned us two identical sockets connected to each other
3126 // We will use the first socket to send the second socket. The second socket
3127 // will be added to the kqueue so it will wake when data is sent.
3128 static const KQueueEntry wakeKQEntry
= { KQWokenFlushBytes
, NULL
, "kqueue wakeup after CFRunLoop event" };
3129 PlatformStorage
.WakeKQueueLoopFD
= fdpair
[0];
3130 KQueueSet(fdpair
[1], EV_ADD
, EVFILT_READ
, &wakeKQEntry
);
3132 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
3134 LogMsg("Note: Compiled without Apple Sandbox support");
3137 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
3141 int sandbox_err
= sandbox_init("mDNSResponder", SANDBOX_NAMED
, &sandbox_msg
);
3142 if (sandbox_err
) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg
); sandbox_free_error(sandbox_msg
); }
3143 else LogInfo("Now running under Apple Sandbox restrictions");
3147 status
= mDNSDaemonInitialize();
3148 if (status
) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit
; }
3150 status
= udsserver_init(launchd_fds
, launchd_fds_count
);
3151 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
3153 mDNSMacOSXNetworkChanged(&mDNSStorage
);
3155 // Start the kqueue thread
3156 i
= pthread_create(&KQueueThread
, NULL
, KQueueLoop
, &mDNSStorage
);
3157 if (i
== -1) { LogMsg("pthread_create() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3162 LogMsg("ERROR: CFRunLoopRun Exiting.");
3163 mDNS_Close(&mDNSStorage
);
3166 LogMsg("%s exiting", mDNSResponderVersionString
);
3169 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
3173 // uds_daemon.c support routines /////////////////////////////////////////////
3175 // Arrange things so that when data appears on fd, callback is called with context
3176 mDNSexport mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
3178 KQSocketEventSource
**p
= &gEventSources
;
3179 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
3180 if (*p
) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd
); return mStatus_AlreadyRegistered
; }
3182 KQSocketEventSource
*newSource
= (KQSocketEventSource
*) mallocL("KQSocketEventSource", sizeof *newSource
);
3183 if (!newSource
) return mStatus_NoMemoryErr
;
3185 newSource
->next
= mDNSNULL
;
3187 newSource
->kqs
.KQcallback
= callback
;
3188 newSource
->kqs
.KQcontext
= context
;
3189 newSource
->kqs
.KQtask
= "UDS client";
3191 if (KQueueSet(fd
, EV_ADD
, EVFILT_READ
, &newSource
->kqs
) == 0)
3194 return mStatus_NoError
;
3197 LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd
, errno
, strerror(errno
));
3198 freeL("KQSocketEventSource", newSource
);
3199 return mStatus_BadParamErr
;
3202 mDNSexport mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
3204 KQSocketEventSource
**p
= &gEventSources
;
3205 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
3208 KQSocketEventSource
*s
= *p
;
3210 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
3211 // causes the kernel to automatically remove any associated kevents
3213 freeL("KQSocketEventSource", s
);
3214 return mStatus_NoError
;
3216 LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd
);
3217 return mStatus_NoSuchNameErr
;
3220 #if _BUILDING_XCODE_PROJECT_
3221 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
3222 const char *__crashreporter_info__
= mDNSResponderVersionString
;
3223 asm(".desc ___crashreporter_info__, 0x10");
3226 // For convenience when using the "strings" command, this is the last thing in the file
3227 // The "@(#) " pattern is a special prefix the "what" command looks for
3228 mDNSexport
const char mDNSResponderVersionString_SCCS
[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";