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.358 2008/03/06 21:26:11 cheshire
34 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
36 Revision 1.357 2008/02/13 17:40:43 cheshire
37 <rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
39 Revision 1.356 2007/12/18 00:28:56 cheshire
40 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
41 Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
43 Revision 1.355 2007/12/17 22:29:22 cheshire
44 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
45 Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
47 Revision 1.354 2007/12/15 01:12:28 cheshire
48 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
50 Revision 1.353 2007/12/14 19:14:02 cheshire
51 Added (commented out) code for testing sleep/wake
53 Revision 1.352 2007/12/14 00:58:29 cheshire
54 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
55 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
56 until TLS/TCP deregistrations have completed (up to five seconds maximum)
58 Revision 1.351 2007/12/12 21:34:18 cheshire
59 Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
60 it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
61 confirmed that the bug is definitely fixed we'll remove the workaround altogether.
63 Revision 1.350 2007/12/07 00:45:58 cheshire
64 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
66 Revision 1.349 2007/12/04 22:00:54 cheshire
67 Fixed mistake in comment
69 Revision 1.348 2007/12/01 00:27:43 cheshire
70 Fixed compile warning: declaration of 'r' shadows a previous local
72 Revision 1.347 2007/11/02 22:00:13 cheshire
73 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
74 Need to hold the lock while calling SetDomainSecrets
76 Revision 1.346 2007/11/02 20:18:13 cheshire
77 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
79 Revision 1.345 2007/10/17 18:41:21 cheshire
80 For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
82 Revision 1.344 2007/09/29 01:06:17 mcguire
83 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
85 Revision 1.343 2007/09/24 05:02:41 cheshire
86 Debugging: In SIGINFO output, indicate explicitly when a given section is empty
88 Revision 1.342 2007/09/18 19:09:02 cheshire
89 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
91 Revision 1.341 2007/09/12 01:22:13 cheshire
92 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
94 Revision 1.340 2007/09/07 22:44:03 mcguire
95 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
97 Revision 1.339 2007/09/06 19:08:29 cheshire
98 LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
100 Revision 1.338 2007/09/05 23:34:27 mcguire
101 Revert logging change
103 Revision 1.337 2007/09/05 20:45:50 cheshire
104 Added list of KQSocketEventSources in SIGINFO output
106 Revision 1.336 2007/08/31 17:15:37 cheshire
107 Reordered startup log messages so that "mDNSResponder ... starting" is the first message
109 Revision 1.335 2007/08/31 02:00:16 cheshire
110 Added comment explaining use of zero-width non-breaking space character to tag literal strings
112 Revision 1.334 2007/08/24 23:40:24 cheshire
113 Added comment about FreeServiceInstance
115 Revision 1.333 2007/08/23 21:02:35 cheshire
116 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
118 Revision 1.332 2007/08/22 23:54:54 mcguire
119 <rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
121 Revision 1.331 2007/08/18 01:02:03 mcguire
122 <rdar://problem/5415593> No Bonjour services are getting registered at boot
124 Revision 1.330 2007/08/10 22:25:57 mkrochma
125 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
127 Revision 1.329 2007/08/08 22:34:58 mcguire
128 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
130 Revision 1.328 2007/07/27 22:43:37 cheshire
131 Improved mallocL/freeL "suspiciously large" debugging messages
133 Revision 1.327 2007/07/27 19:30:41 cheshire
134 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
135 to properly reflect tri-state nature of the possible responses
137 Revision 1.326 2007/07/24 17:23:33 cheshire
138 <rdar://problem/5357133> Add list validation checks for debugging
140 Revision 1.325 2007/07/11 23:43:43 cheshire
141 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
143 Revision 1.324 2007/07/11 22:44:40 cheshire
144 <rdar://problem/5328801> SIGHUP should purge the cache
146 Revision 1.323 2007/07/11 03:01:50 cheshire
147 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
149 Revision 1.322 2007/07/06 18:58:16 cheshire
150 Check m->NextScheduledNATOp in ShowTaskSchedulingError()
152 Revision 1.321 2007/07/02 21:54:20 cheshire
153 Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
155 Revision 1.320 2007/06/28 21:16:27 cheshire
156 Rename "m->nextevent" as more informative "m->NextuDNSEvent"
158 Revision 1.319 2007/06/22 20:47:08 cheshire
159 <rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
160 Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
162 Revision 1.318 2007/06/20 01:45:40 cheshire
163 When showing dormant interfaces, display last-seen IP address for that dormant interface
165 Revision 1.317 2007/06/20 01:10:12 cheshire
166 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
168 Revision 1.316 2007/06/19 19:27:11 cheshire
169 <rdar://problem/5141540> Sandbox mDNSResponder
170 Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
172 Revision 1.315 2007/06/15 21:54:51 cheshire
173 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
175 Revision 1.314 2007/06/15 19:23:17 cheshire
176 <rdar://problem/5254053> mDNSResponder renames my host without asking
177 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
179 Revision 1.313 2007/05/25 16:02:05 cheshire
180 When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
182 Revision 1.312 2007/05/22 19:07:21 cheshire
183 Add comment explaining RR_CACHE_SIZE calculation
185 Revision 1.311 2007/05/15 21:47:21 cheshire
186 Get rid of "#pragma unused(m)"
188 Revision 1.310 2007/05/08 00:56:17 cheshire
189 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
191 Revision 1.309 2007/04/30 21:33:38 cheshire
192 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
193 is iterating through the m->ServiceRegistrations list
195 Revision 1.308 2007/04/28 01:31:59 cheshire
196 Improve debugging support for catching memory corruption problems
198 Revision 1.307 2007/04/24 18:32:00 cheshire
199 Grab a copy of KQtask string pointer in case KQcallback deletes the task
201 Revision 1.306 2007/04/22 19:11:51 cheshire
202 Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
203 if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
204 from the project and just using simple vanilla C linked-list manipulation instead.
206 Revision 1.305 2007/04/22 06:02:03 cheshire
207 <rdar://problem/4615977> Query should immediately return failure when no server
209 Revision 1.304 2007/04/21 21:47:47 cheshire
210 <rdar://problem/4376383> Daemon: Add watchdog timer
212 Revision 1.303 2007/04/18 00:50:47 cheshire
213 <rdar://problem/5141540> Sandbox mDNSResponder
215 Revision 1.302 2007/04/07 01:01:48 cheshire
216 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
218 Revision 1.301 2007/04/05 19:13:48 cheshire
219 Use better name in SCPreferencesCreate
221 Revision 1.300 2007/04/04 21:22:18 cheshire
222 Suppress "Local Hostname changed" syslog message when name has not actually changed
224 Revision 1.299 2007/04/03 19:19:33 cheshire
225 Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
227 Revision 1.298 2007/03/30 21:51:45 cheshire
230 Revision 1.297 2007/03/27 22:47:19 cheshire
231 On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
233 Revision 1.296 2007/03/24 01:23:29 cheshire
234 Call validator for uDNS data structures
236 Revision 1.295 2007/03/20 23:32:49 cheshire
237 Minor textual tidying
239 Revision 1.294 2007/03/07 02:50:50 cheshire
240 <rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
242 Revision 1.293 2007/03/06 22:59:01 cheshire
243 <rdar://problem/4157921> Security: Null dereference possible in daemon.c
245 Revision 1.292 2007/02/28 21:55:10 cheshire
246 <rdar://problem/3862944> UI: Name conflict notifications should be localized
247 Additional fix: We were not getting our NotificationCallBackDismissed messages
248 because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
249 (We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
251 Revision 1.291 2007/02/28 03:51:24 cheshire
252 <rdar://problem/3862944> UI: Name conflict notifications should be localized
253 Moved curly quotes out of the literal text and into the localized text, so they
254 can be replaced with alternate characters as appropriate for other languages.
256 Revision 1.290 2007/02/14 01:58:19 cheshire
257 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
259 Revision 1.289 2007/02/07 19:32:00 cheshire
260 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
262 Revision 1.288 2007/02/07 01:01:24 cheshire
263 <rdar://problem/3956518> Need to go native with launchd
264 Additional refinements -- was unnecessarily calling launch_data_free()
266 Revision 1.287 2007/02/06 19:06:48 cheshire
267 <rdar://problem/3956518> Need to go native with launchd
269 Revision 1.286 2007/01/06 01:00:33 cheshire
270 Improved SIGINFO output
272 Revision 1.285 2007/01/05 08:30:47 cheshire
273 Trim excessive "$Log" checkin history from before 2006
274 (checkin history still available via "cvs log ..." of course)
276 Revision 1.284 2007/01/05 05:44:35 cheshire
277 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
278 so that mDNSPosix embedded clients will compile again
280 Revision 1.283 2007/01/04 23:11:14 cheshire
281 <rdar://problem/4720673> uDNS: Need to start caching unicast records
282 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
284 Revision 1.282 2006/12/21 00:09:45 cheshire
285 Use mDNSPlatformMemZero instead of bzero
287 Revision 1.281 2006/11/18 05:01:32 cheshire
288 Preliminary support for unifying the uDNS and mDNS code,
289 including caching of uDNS answers
291 Revision 1.280 2006/11/10 00:54:16 cheshire
292 <rdar://problem/4816598> Changing case of Computer Name doesn't work
294 Revision 1.279 2006/11/02 17:44:01 cheshire
295 No longer have a separate uDNS ActiveQueries list
297 Revision 1.278 2006/10/05 04:04:24 herscher
298 Remove embedded uDNS_info struct from DNSQuestion_struct
300 Revision 1.277 2006/09/21 21:01:24 cheshire
301 Change 'autorename' to more accurate name 'renameonmemfree'
303 Revision 1.276 2006/09/17 19:12:02 cheshire
304 Further changes for removal of uDNS_info substructure from mDNS_struct
306 Revision 1.275 2006/09/15 21:20:16 cheshire
307 Remove uDNS_info substructure from mDNS_struct
309 Revision 1.274 2006/08/14 23:24:39 cheshire
310 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
312 Revision 1.273 2006/07/30 05:43:19 cheshire
313 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
314 Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
316 Revision 1.272 2006/07/27 03:24:35 cheshire
317 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
318 Further refinement: Declare KQueueEntry parameter "const"
320 Revision 1.271 2006/07/27 02:59:26 cheshire
321 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
322 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
323 after releasing BigMutex, in case actions it took have resulted in new work for the
324 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
325 add new active interfaces to its list, and consequently schedule queries to be sent).
327 Revision 1.270 2006/07/25 17:16:36 mkrochma
328 Quick fix to solve kqueue related crashes and hangs
330 Revision 1.269 2006/07/22 06:11:37 cheshire
331 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
333 Revision 1.268 2006/07/15 02:01:32 cheshire
334 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
335 Fix broken "empty string" browsing
337 Revision 1.267 2006/07/07 01:09:10 cheshire
338 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
339 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
341 Revision 1.266 2006/07/05 23:34:53 cheshire
342 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
344 Revision 1.265 2006/06/29 07:32:08 cheshire
345 Added missing LogOperation logging for DNSServiceBrowse results
347 Revision 1.264 2006/06/29 05:33:30 cheshire
348 <rdar://problem/4607043> mDNSResponder conditional compilation options
350 Revision 1.263 2006/06/08 23:23:48 cheshire
351 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
353 Revision 1.262 2006/03/18 21:49:11 cheshire
354 Added comment in ShowTaskSchedulingError(mDNS *const m)
356 Revision 1.261 2006/01/06 01:22:28 cheshire
357 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
361 #include <mach/mach.h>
362 #include <mach/mach_error.h>
363 #include <servers/bootstrap.h>
364 #include <sys/types.h>
370 #include <sys/event.h>
373 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
375 #include "DNSServiceDiscoveryRequestServer.h"
376 #include "DNSServiceDiscoveryReply.h"
379 #include "DNSCommon.h"
380 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
382 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
384 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
387 //*************************************************************************************************************
390 static mDNS_PlatformSupport PlatformStorage
;
392 // Start off with a default cache of 16K (99 records)
393 // Each time we grow the cache we add another 99 records
394 // 99 * 164 = 16236 bytes.
395 // This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
396 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
397 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
399 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
400 static mach_port_t m_port
= MACH_PORT_NULL
;
401 static mach_port_t client_death_port
= MACH_PORT_NULL
;
402 static mach_port_t signal_port
= MACH_PORT_NULL
;
403 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
405 static dnssd_sock_t launchd_fd
= dnssd_InvalidSocket
;
407 // mDNS Mach Message Timeout, in milliseconds.
408 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
409 // fails to service its mach message queue, but long enough to give a well-written
410 // client a chance to service its mach message queue without getting cut off.
411 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
412 // even extra-slow clients a fair chance before we cut them off.
413 #define MDNS_MM_TIMEOUT 250
415 static int restarting_via_mach_init
= 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
416 static int started_via_launchdaemon
= 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
420 static CFRunLoopRef CFRunLoop
;
422 //*************************************************************************************************************
423 // Active client list structures
425 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
426 struct DNSServiceDomainEnumeration_struct
428 DNSServiceDomainEnumeration
*next
;
429 mach_port_t ClientMachPort
;
430 DNSQuestion dom
; // Question asking for domains
431 DNSQuestion def
; // Question asking for default domain
434 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
435 struct DNSServiceBrowserResult_struct
437 DNSServiceBrowserResult
*next
;
442 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
444 typedef struct DNSServiceBrowserQuestion
446 struct DNSServiceBrowserQuestion
*next
;
449 } DNSServiceBrowserQuestion
;
451 struct DNSServiceBrowser_struct
453 DNSServiceBrowser
*next
;
454 mach_port_t ClientMachPort
;
455 DNSServiceBrowserQuestion
*qlist
;
456 DNSServiceBrowserResult
*results
;
458 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
459 domainname type
; // registration type
462 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
463 struct DNSServiceResolver_struct
465 DNSServiceResolver
*next
;
466 mach_port_t ClientMachPort
;
472 // A single registered service: ServiceRecordSet + bookkeeping
473 // Note that we duplicate some fields from parent DNSServiceRegistration object
474 // to facilitate cleanup, when instances and parent may be deallocated at different times.
475 typedef struct ServiceInstance
477 struct ServiceInstance
*next
;
478 mach_port_t ClientMachPort
;
479 mDNSBool autoname
; // Set if this name is tied to the Computer Name
480 mDNSBool renameonmemfree
; // Set if we just got a name conflict and now need to automatically pick a new name
483 ServiceRecordSet srs
;
484 // Don't add any fields after ServiceRecordSet.
485 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
488 // A client-created service. May reference several ServiceInstance objects if default
489 // settings cause registration in multiple domains.
490 typedef struct DNSServiceRegistration
492 struct DNSServiceRegistration
*next
;
493 mach_port_t ClientMachPort
;
494 mDNSBool DefaultDomain
;
498 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
499 domainlabel name
; // used only if autoname is false
502 unsigned char txtinfo
[1024];
505 ServiceInstance
*regs
;
506 } DNSServiceRegistration
;
508 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
509 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
510 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
511 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
513 // We keep a list of client-supplied event sources in KQSocketEventSource records
514 typedef struct KQSocketEventSource
516 struct KQSocketEventSource
*next
;
519 } KQSocketEventSource
;
521 static KQSocketEventSource
*gEventSources
;
523 //*************************************************************************************************************
524 // General Utility Functions
526 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
528 char _malloc_options
[] = "AXZ";
530 mDNSexport
void LogMemCorruption(const char *format
, ...)
534 va_start(ptr
,format
);
535 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
537 LogMsg("!!!! %s !!!!", buffer
);
538 NotifyOfElusiveBug("Memory Corruption", buffer
);
540 *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
544 mDNSlocal
void validatelists(mDNS
*const m
)
547 KQSocketEventSource
*k
;
548 for (k
= gEventSources
; k
; k
=k
->next
)
549 if (k
->next
== (KQSocketEventSource
*)~0 || k
->fd
< 0)
550 LogMemCorruption("gEventSources: %p is garbage (%d)", k
, k
->fd
);
552 // Check Mach client lists
553 DNSServiceDomainEnumeration
*e
;
554 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
555 if (e
->next
== (DNSServiceDomainEnumeration
*)~0 || e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
556 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
558 DNSServiceBrowser
*b
;
559 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
560 if (b
->next
== (DNSServiceBrowser
*)~0 || b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
561 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
563 DNSServiceResolver
*l
;
564 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
565 if (l
->next
== (DNSServiceResolver
*)~0 || l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
566 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
568 DNSServiceRegistration
*r
;
569 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
570 if (r
->next
== (DNSServiceRegistration
*)~0 || r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
571 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
573 // Check Unix Domain Socket client lists (uds_daemon.c)
576 // Check core mDNS lists
578 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
580 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
581 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
582 if (rr
->resrec
.name
!= &rr
->namestorage
)
583 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
584 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
587 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
588 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
589 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
591 rr
= m
->NewLocalRecords
;
593 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
594 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
596 rr
= m
->CurrentRecord
;
598 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
599 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
602 for (q
= m
->Questions
; q
; q
=q
->next
)
603 if (q
->next
== (DNSQuestion
*)~0 || q
->ThisQInterval
== (mDNSs32
)~0)
604 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q
, q
->ThisQInterval
, q
->next
);
609 FORALL_CACHERECORDS(slot
, cg
, cr
)
611 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
612 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, cr
, cr
->resrec
.RecordType
);
613 if (cr
->CRActiveQuestion
)
615 for (q
= m
->Questions
; q
; q
=q
->next
) if (q
== cr
->CRActiveQuestion
) break;
616 if (!q
) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot
, cr
->CRActiveQuestion
, CRDisplayString(m
, cr
));
620 // Check core uDNS lists
621 udns_validatelists(m
);
623 // Check platform-layer lists
624 NetworkInterfaceInfoOSX
*i
;
625 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
626 if (i
->next
== (NetworkInterfaceInfoOSX
*)~0 || !i
->ifa_name
|| i
->ifa_name
== (char *)~0)
627 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i
, i
->ifa_name
);
630 for (t
= m
->TunnelClients
; t
; t
=t
->next
)
631 if (t
->next
== (ClientTunnel
*)~0 || t
->dstname
.c
[0] > 63)
632 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t
, t
->dstname
.c
[0]);
635 void *mallocL(char *msg
, unsigned int size
)
637 unsigned long *mem
= malloc(size
+8);
640 LogMsg("malloc( %s : %d ) failed", msg
, size
);
645 if (size
> 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg
, size
, &mem
[2]);
646 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
649 //mDNSPlatformMemZero(&mem[2], size);
650 memset(&mem
[2], 0xFF, size
);
651 validatelists(&mDNSStorage
);
656 void freeL(char *msg
, void *x
)
659 LogMsg("free( %s @ NULL )!", msg
);
662 unsigned long *mem
= ((unsigned long *)x
) - 2;
663 if (mem
[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
664 if (mem
[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg
, mem
[1], &mem
[2]);
665 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
666 //mDNSPlatformMemZero(mem, mem[1]+8);
667 memset(mem
, 0xFF, mem
[1]+8);
668 validatelists(&mDNSStorage
);
675 //*************************************************************************************************************
676 // Client Death Detection
678 // This gets called after ALL constituent records of the Service Record Set have been deregistered
679 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
681 ServiceRecordSet
*s
= &x
->srs
;
682 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
686 e
->r
.RecordContext
= e
;
689 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
692 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
693 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
695 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
696 freeL("ServiceInstance", x
);
699 // AbortClient finds whatever client is identified by the given Mach port,
700 // stops whatever operation that client was doing, and frees its memory.
701 // In the case of a service registration, the actual freeing may be deferred
702 // until we get the mStatus_MemFree message, if necessary
703 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
705 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
706 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
707 DNSServiceResolver
**l
= &DNSServiceResolverList
;
708 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
710 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
713 DNSServiceDomainEnumeration
*x
= *e
;
716 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
717 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
718 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
719 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
720 freeL("DNSServiceDomainEnumeration", x
);
724 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
727 DNSServiceBrowser
*x
= *b
;
728 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
733 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
734 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
735 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
738 freeL("DNSServiceBrowserQuestion", freePtr
);
742 DNSServiceBrowserResult
*t
= x
->results
;
743 x
->results
= x
->results
->next
;
744 freeL("DNSServiceBrowserResult", t
);
746 freeL("DNSServiceBrowser", x
);
750 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
753 DNSServiceResolver
*x
= *l
;
756 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
757 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
758 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
759 freeL("DNSServiceResolver", x
);
763 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
766 ServiceInstance
*si
= NULL
;
767 DNSServiceRegistration
*x
= *r
;
773 ServiceInstance
*instance
= si
;
775 instance
->renameonmemfree
= mDNSfalse
;
776 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
);
777 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
779 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
780 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
781 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
782 // the list, so we should go ahead and free the memory right now
783 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
786 freeL("DNSServiceRegistration", x
);
790 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
793 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
795 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
797 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
798 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
799 DNSServiceResolver
*l
= DNSServiceResolverList
;
800 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
801 DNSServiceBrowserQuestion
*qptr
;
803 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
804 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
805 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
806 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
808 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
811 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
812 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
814 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
818 for (si
= r
->regs
; si
; si
= si
->next
)
819 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
821 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
826 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
828 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
829 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
830 DNSServiceResolver
*l
= DNSServiceResolverList
;
831 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
832 DNSServiceBrowserQuestion
*qptr
;
834 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
835 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
836 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
837 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
838 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
841 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
842 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
844 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
845 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
846 return(e
|| b
|| l
|| r
);
849 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
851 KQueueLock(&mDNSStorage
);
852 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
853 (void)unusedport
; // Unused
854 (void)size
; // Unused
855 (void)info
; // Unused
856 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
858 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
859 AbortClient(deathMessage
->not_port
, NULL
);
861 /* Deallocate the send right that came in the dead name notification */
862 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
864 KQueueUnlock(&mDNSStorage
, "Mach AbortClient");
867 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
870 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
871 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
872 // If the port already died while we were thinking about it, then abort the operation right away
873 if (r
!= KERN_SUCCESS
)
874 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
877 //*************************************************************************************************************
878 // Domain Enumeration
880 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
882 kern_return_t status
;
883 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
884 DNSServiceDomainEnumerationReplyResultType rt
;
885 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
888 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
889 if (answer
->rrtype
!= kDNSType_PTR
) return;
890 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
894 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
895 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
899 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
903 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
904 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
905 !AddRecord
? "RemoveDomain" :
906 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
908 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
909 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
910 if (status
== MACH_SEND_TIMED_OUT
)
911 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
914 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
917 // Check client parameter
918 (void)unusedserver
; // Unused
919 mStatus err
= mStatus_NoError
;
920 const char *errormsg
= "Unknown";
921 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
922 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
924 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
925 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
927 // Allocate memory, and handle failure
928 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
929 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
931 // Set up object, and link into list
932 x
->ClientMachPort
= client
;
933 x
->next
= DNSServiceDomainEnumerationList
;
934 DNSServiceDomainEnumerationList
= x
;
936 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
939 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
940 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
941 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
943 // Succeeded: Wrap up and return
944 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
945 EnableDeathNotificationForClient(client
, x
);
946 return(mStatus_NoError
);
949 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
953 //*************************************************************************************************************
954 // Browse for services
956 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
960 if (answer
->rrtype
!= kDNSType_PTR
)
961 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
964 domainname type
, domain
;
965 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
967 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
968 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
972 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
973 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
975 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
976 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
978 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
979 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
982 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
983 DNSServiceBrowserResult
**p
= &browser
->results
;
984 while (*p
) p
= &(*p
)->next
;
987 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
988 browser
->ClientMachPort
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
991 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
993 mStatus err
= mStatus_NoError
;
994 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
996 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
998 if (SameDomainName(&ptr
->q
.qname
, d
))
999 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1002 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1003 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1004 AssignDomainName(&question
->domain
, d
);
1005 question
->next
= browser
->qlist
;
1006 browser
->qlist
= question
;
1007 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1008 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1009 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1013 mDNSexport
void machserver_automatic_browse_domain_changed(const domainname
*d
, mDNSBool add
)
1015 DNSServiceBrowser
*ptr
;
1016 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1018 if (ptr
->DefaultDomain
)
1022 mStatus err
= AddDomainToBrowser(ptr
, d
);
1023 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1027 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1030 if (SameDomainName(&(*q
)->domain
, d
))
1032 DNSServiceBrowserQuestion
*rem
= *q
;
1034 mDNS_StopQueryWithRemoves(&mDNSStorage
, &rem
->q
);
1035 freeL("DNSServiceBrowserQuestion", rem
);
1040 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1046 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1047 DNSCString regtype
, DNSCString domain
)
1049 // Check client parameter
1050 (void)unusedserver
; // Unused
1051 mStatus err
= mStatus_NoError
;
1052 const char *errormsg
= "Unknown";
1054 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1055 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1057 // Check other parameters
1060 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1061 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1062 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1063 { errormsg
= "Bad Service SubType"; goto badparam
; }
1064 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1066 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1067 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1069 // Allocate memory, and handle failure
1070 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1071 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1073 // Set up object, and link into list
1074 AssignDomainName(&x
->type
, &t
);
1075 x
->ClientMachPort
= client
;
1079 x
->next
= DNSServiceBrowserList
;
1080 DNSServiceBrowserList
= x
;
1084 // Start browser for an explicit domain
1085 x
->DefaultDomain
= mDNSfalse
;
1086 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1087 err
= AddDomainToBrowser(x
, &d
);
1088 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1092 DNameListElem
*sdPtr
;
1093 // Start browser on all domains
1094 x
->DefaultDomain
= mDNStrue
;
1095 if (!AutoBrowseDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1096 for (sdPtr
= AutoBrowseDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1098 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1101 // only terminally bail if .local fails
1102 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1103 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1104 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1109 // Succeeded: Wrap up and return
1110 EnableDeathNotificationForClient(client
, x
);
1111 return(mStatus_NoError
);
1114 err
= mStatus_BadParamErr
;
1116 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1120 //*************************************************************************************************************
1121 // Resolve Service Info
1123 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1125 kern_return_t status
;
1126 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1127 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1128 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1129 struct sockaddr_storage interface
;
1130 struct sockaddr_storage address
;
1132 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1135 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1137 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1139 mDNSPlatformMemZero(&interface
, sizeof(interface
));
1140 mDNSPlatformMemZero(&address
, sizeof(address
));
1142 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1144 struct sockaddr_in
*s
= (struct sockaddr_in
*)&interface
;
1145 s
->sin_len
= sizeof(*s
);
1146 s
->sin_family
= AF_INET
;
1148 s
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1150 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1152 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1153 sin6
->sin6_len
= sizeof(*sin6
);
1154 sin6
->sin6_family
= AF_INET6
;
1155 sin6
->sin6_flowinfo
= 0;
1156 sin6
->sin6_port
= 0;
1157 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1158 sin6
->sin6_scope_id
= ifx
->scope_id
;
1161 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1163 struct sockaddr_in
*s
= (struct sockaddr_in
*)&address
;
1164 s
->sin_len
= sizeof(*s
);
1165 s
->sin_family
= AF_INET
;
1166 s
->sin_port
= query
->info
->port
.NotAnInteger
;
1167 s
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1171 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1172 sin6
->sin6_len
= sizeof(*sin6
);
1173 sin6
->sin6_family
= AF_INET6
;
1174 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1175 sin6
->sin6_flowinfo
= 0;
1176 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1177 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1180 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1181 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1182 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1183 // ASCII-1 characters are used in the C-string as boundary markers,
1184 // to indicate the boundaries between the original constituent P-strings.
1185 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1188 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1192 pstrlen
= query
->info
->TXTinfo
[i
];
1195 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1197 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1198 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1199 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1200 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1201 if (status
== MACH_SEND_TIMED_OUT
)
1202 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1205 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1206 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1208 // Check client parameter
1209 (void)unusedserver
; // Unused
1210 mStatus err
= mStatus_NoError
;
1211 const char *errormsg
= "Unknown";
1212 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1213 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1215 // Check other parameters
1217 domainname t
, d
, srv
;
1218 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1219 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1220 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1221 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1223 // Allocate memory, and handle failure
1224 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1225 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1227 // Set up object, and link into list
1228 x
->ClientMachPort
= client
;
1229 x
->i
.InterfaceID
= mDNSInterface_Any
;
1231 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1232 x
->next
= DNSServiceResolverList
;
1233 DNSServiceResolverList
= x
;
1236 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1237 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1238 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1240 // Succeeded: Wrap up and return
1241 EnableDeathNotificationForClient(client
, x
);
1242 return(mStatus_NoError
);
1245 err
= mStatus_BadParamErr
;
1247 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1251 //*************************************************************************************************************
1254 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1256 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1259 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1261 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1263 if (result
== mStatus_NoError
)
1265 kern_return_t status
;
1266 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1267 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1268 if (status
== MACH_SEND_TIMED_OUT
)
1269 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1270 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1271 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1274 else if (result
== mStatus_NameConflict
)
1276 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1277 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1278 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1279 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1281 // On conflict for an autoname service, rename and reregister *all* autoname services
1282 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1283 m
->MainCallback(m
, mStatus_ConfigChanged
);
1285 else if (si
->autoname
)
1287 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1292 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1293 // of their registration in the usual way (which we will catch via client death notification).
1294 // If the Mach queue is full, we forcibly abort the client immediately.
1295 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1296 if (status
== MACH_SEND_TIMED_OUT
)
1297 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1301 else if (result
== mStatus_MemFree
)
1303 if (si
->renameonmemfree
) // We intentionally terminated registration so we could re-register with new name
1305 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1306 si
->renameonmemfree
= mDNSfalse
;
1307 si
->name
= m
->nicelabel
;
1308 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1312 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1313 DNSServiceRegistration
*r
;
1314 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1316 ServiceInstance
**sp
= &r
->regs
;
1319 if (*sp
== si
) { LogMsg("RegCallback: %##s Still in list; removing", srs
->RR_SRV
.resrec
.name
->c
); *sp
= (*sp
)->next
; break; }
1324 FreeServiceInstance(si
);
1328 else if (result
!= mStatus_NATTraversal
)
1329 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1332 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1335 ServiceInstance
*si
= NULL
;
1336 AuthRecord
*SubTypes
= NULL
;
1338 for (si
= x
->regs
; si
; si
= si
->next
)
1340 if (SameDomainName(&si
->domain
, domain
))
1341 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1344 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1345 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1347 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1348 if (!si
) return mStatus_NoMemoryErr
;
1350 si
->ClientMachPort
= x
->ClientMachPort
;
1351 si
->renameonmemfree
= mDNSfalse
;
1352 si
->autoname
= x
->autoname
;
1353 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1354 si
->domain
= *domain
;
1356 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
,
1357 x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1365 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1366 freeL("ServiceInstance", si
);
1371 mDNSexport
void machserver_automatic_registration_domain_changed(const domainname
*d
, mDNSBool add
)
1373 DNSServiceRegistration
*reg
;
1375 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1377 if (reg
->DefaultDomain
)
1380 AddServiceInstance(reg
, d
);
1383 ServiceInstance
**si
= ®
->regs
;
1386 if (SameDomainName(&(*si
)->domain
, d
))
1388 ServiceInstance
*s
= *si
;
1390 if (mDNS_DeregisterService(&mDNSStorage
, &s
->srs
)) FreeServiceInstance(s
); // only free memory synchronously on error
1395 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1401 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1402 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1404 (void)unusedserver
; // Unused
1405 mStatus err
= mStatus_NoError
;
1406 const char *errormsg
= "Unknown";
1408 // older versions of this code passed the port via mach IPC as an int.
1409 // we continue to pass it as 4 bytes to maintain binary compatibility,
1410 // but now ensure that the network byte order is preserved by using a struct
1412 port
.b
[0] = IpPort
.bytes
[2];
1413 port
.b
[1] = IpPort
.bytes
[3];
1415 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1416 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1418 // Check for sub-types after the service type
1419 size_t reglen
= strlen(regtype
) + 1;
1420 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1421 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1422 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1424 // Check other parameters
1428 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1429 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1430 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1431 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1432 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1434 unsigned char txtinfo
[1024] = "";
1435 unsigned int data_len
= 0;
1436 unsigned int size
= sizeof(RDataBody
);
1437 unsigned char *pstring
= &txtinfo
[data_len
];
1438 char *ptr
= txtRecord
;
1440 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1441 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1442 // Hence we have to convert the C-string to a P-string.
1443 // ASCII-1 characters are allowed in the C-string as boundary markers,
1444 // so that a single C-string can be used to represent one or more P-strings.
1447 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1448 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1450 pstring
= &txtinfo
[data_len
];
1456 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1457 pstring
[++pstring
[0]] = *ptr
++;
1462 if (size
< data_len
)
1465 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1466 // a port number of zero. When two instances of the protected client are allowed to run on one
1467 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1468 if (!mDNSIPPortIsZero(port
))
1470 int count
= CountExistingRegistrations(&srv
, port
);
1472 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1473 client
, count
+1, srv
.c
, mDNSVal16(port
));
1476 // Allocate memory, and handle failure
1477 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1478 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1479 mDNSPlatformMemZero(x
, sizeof(*x
));
1481 // Set up object, and link into list
1482 x
->ClientMachPort
= client
;
1483 x
->DefaultDomain
= !domain
[0];
1484 x
->autoname
= (!name
[0]);
1486 x
->NumSubTypes
= NumSubTypes
;
1487 memcpy(x
->regtype
, regtype
, reglen
);
1491 memcpy(x
->txtinfo
, txtinfo
, 1024);
1492 x
->txt_len
= data_len
;
1496 x
->next
= DNSServiceRegistrationList
;
1497 DNSServiceRegistrationList
= x
;
1499 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1500 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1502 err
= AddServiceInstance(x
, &d
);
1503 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1505 if (x
->DefaultDomain
)
1508 for (p
= AutoRegistrationDomains
; p
; p
= p
->next
)
1509 AddServiceInstance(x
, &p
->name
);
1512 // Succeeded: Wrap up and return
1513 EnableDeathNotificationForClient(client
, x
);
1514 return(mStatus_NoError
);
1517 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1519 err
= mStatus_BadParamErr
;
1521 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1522 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1526 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1529 if (result
== mStatus_NoError
)
1531 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
1532 LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1533 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1534 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1536 else if (result
== mStatus_NameConflict
)
1538 LogOperation("Local Hostname conflict for \"%#s.local\"", m
->hostlabel
.c
);
1539 if (!m
->p
->HostNameConflict
) m
->p
->HostNameConflict
= NonZeroTime(m
->timenow
);
1540 else if (m
->timenow
- m
->p
->HostNameConflict
> 60 * mDNSPlatformOneSecond
)
1542 // Tell the helper we've given up
1543 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, NULL
);
1546 else if (result
== mStatus_GrowCache
)
1548 // Allocate another chunk of cache storage
1549 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1550 //LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
1551 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1553 else if (result
== mStatus_ConfigChanged
)
1555 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
1556 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
1557 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
1559 // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
1560 DNSServiceRegistration
*r
;
1561 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1564 ServiceInstance
*si
;
1565 for (si
= r
->regs
; si
; si
= si
->next
)
1567 if (!SameDomainLabelCS(si
->name
.c
, m
->nicelabel
.c
))
1569 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1570 si
->renameonmemfree
= mDNStrue
;
1571 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1572 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1577 // Then we call into the UDS daemon code, to let it do the same
1578 udsserver_handle_configchange(m
);
1582 //*************************************************************************************************************
1583 // Add / Update / Remove records from existing Registration
1585 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1586 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1588 // Check client parameter
1590 mStatus err
= mStatus_NoError
;
1591 const char *errormsg
= "Unknown";
1592 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1593 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1594 ServiceInstance
*si
;
1596 (void)unusedserver
; // Unused
1597 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1598 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1600 // Check other parameters
1601 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1602 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1603 else size
= sizeof(RDataBody
);
1606 *reference
= (natural_t
)id
;
1607 for (si
= x
->regs
; si
; si
= si
->next
)
1609 // Allocate memory, and handle failure
1610 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1611 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1613 // Fill in type, length, and data of new record
1614 extra
->r
.resrec
.rrtype
= type
;
1615 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1616 extra
->r
.resrec
.rdlength
= data_len
;
1617 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1620 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1621 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1622 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1626 freeL("Extra Resource Record", extra
);
1627 errormsg
= "mDNS_AddRecordToService";
1631 extra
->ClientID
= id
;
1634 return mStatus_NoError
;
1637 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
? x
->name
.c
: (mDNSu8
*)"\x8""«NULL»", type
, data_len
, errormsg
, err
);
1638 return mStatus_UnknownErr
;
1641 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1644 if (OldRData
!= &rr
->rdatastorage
)
1645 freeL("Old RData", OldRData
);
1648 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1650 // Check client parameter
1651 mStatus err
= mStatus_NoError
;
1652 const char *errormsg
= "Unknown";
1653 const domainname
*name
= (const domainname
*)"";
1655 name
= srs
->RR_SRV
.resrec
.name
;
1657 unsigned int size
= sizeof(RDataBody
);
1658 if (size
< data_len
)
1661 // Allocate memory, and handle failure
1662 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1663 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1665 // Fill in new length, and data
1666 newrdata
->MaxRDLength
= size
;
1667 memcpy(&newrdata
->u
, data
, data_len
);
1669 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1670 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1671 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1672 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1675 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1676 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1678 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1681 errormsg
= "mDNS_Update";
1682 freeL("RData", newrdata
);
1685 return(mStatus_NoError
);
1688 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1692 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1693 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1695 // Check client parameter
1696 mStatus err
= mStatus_NoError
;
1697 const char *errormsg
= "Unknown";
1698 const domainname
*name
= (const domainname
*)"";
1699 ServiceInstance
*si
;
1701 (void)unusedserver
; // unused
1702 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1703 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1704 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1705 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1707 // Check other parameters
1708 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1710 for (si
= x
->regs
; si
; si
= si
->next
)
1712 AuthRecord
*r
= NULL
;
1714 // Find the record we're updating. NULL reference means update the primary TXT record
1715 if (!reference
) r
= &si
->srs
.RR_TXT
;
1718 ExtraResourceRecord
*ptr
;
1719 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1721 if ((natural_t
)ptr
->ClientID
== reference
)
1722 { r
= &ptr
->r
; break; }
1724 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1726 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1727 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1730 return mStatus_NoError
;
1733 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1737 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
1739 const domainname
*const name
= srs
->RR_SRV
.resrec
.name
;
1740 mStatus err
= mStatus_NoError
;
1743 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
1745 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
1746 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
1751 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1752 natural_t reference
)
1754 // Check client parameter
1755 (void)unusedserver
; // Unused
1756 mStatus err
= mStatus_NoError
;
1757 const char *errormsg
= "Unknown";
1758 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1759 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1760 ServiceInstance
*si
;
1762 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1763 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1765 for (si
= x
->regs
; si
; si
= si
->next
)
1767 ExtraResourceRecord
*e
;
1768 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
1770 if ((natural_t
)e
->ClientID
== reference
)
1772 err
= RemoveRecord(&si
->srs
, e
, client
);
1776 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
1779 return mStatus_NoError
;
1782 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
1786 //*************************************************************************************************************
1789 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1791 mig_reply_error_t
*request
= msg
;
1792 mig_reply_error_t
*reply
;
1793 mach_msg_return_t mr
;
1795 (void)port
; // Unused
1796 (void)size
; // Unused
1797 (void)info
; // Unused
1799 KQueueLock(&mDNSStorage
);
1801 /* allocate a reply buffer */
1802 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1804 /* call the MiG server routine */
1805 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1807 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1809 if (reply
->RetCode
== MIG_NO_REPLY
)
1812 * This return code is a little tricky -- it appears that the
1813 * demux routine found an error of some sort, but since that
1814 * error would not normally get returned either to the local
1815 * user or the remote one, we pretend it's ok.
1817 CFAllocatorDeallocate(NULL
, reply
);
1822 * destroy any out-of-line data in the request buffer but don't destroy
1823 * the reply port right (since we need that to send an error message).
1825 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
1826 mach_msg_destroy(&request
->Head
);
1829 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
1831 /* no reply port, so destroy the reply */
1832 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1833 mach_msg_destroy(&reply
->Head
);
1834 CFAllocatorDeallocate(NULL
, reply
);
1841 * We don't want to block indefinitely because the client
1842 * isn't receiving messages from the reply port.
1843 * If we have a send-once right for the reply port, then
1844 * this isn't a concern because the send won't block.
1845 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1846 * To avoid falling off the kernel's fast RPC path unnecessarily,
1847 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1850 options
= MACH_SEND_MSG
;
1851 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
1852 options
|= MACH_SEND_TIMEOUT
;
1854 mr
= mach_msg(&reply
->Head
, /* msg */
1855 options
, /* option */
1856 reply
->Head
.msgh_size
, /* send_size */
1858 MACH_PORT_NULL
, /* rcv_name */
1859 MACH_MSG_TIMEOUT_NONE
, /* timeout */
1860 MACH_PORT_NULL
); /* notify */
1862 /* Has a message error occurred? */
1865 case MACH_SEND_INVALID_DEST
:
1866 case MACH_SEND_TIMED_OUT
:
1867 /* the reply can't be delivered, so destroy it */
1868 mach_msg_destroy(&reply
->Head
);
1872 /* Includes success case. */
1876 CFAllocatorDeallocate(NULL
, reply
);
1879 KQueueUnlock(&mDNSStorage
, "Mach client event");
1882 mDNSlocal kern_return_t
registerBootstrapService()
1884 kern_return_t status
;
1885 mach_port_t service_send_port
, service_rcv_port
;
1887 debugf("Registering Bootstrap Service");
1890 * See if our service name is already registered and if we have privilege to check in.
1892 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1893 if (status
== KERN_SUCCESS
)
1896 * If so, we must be a followup instance of an already defined server. In that case,
1897 * the bootstrap port we inherited from our parent is the server's privilege port, so set
1898 * that in case we have to unregister later (which requires the privilege port).
1900 server_priv_port
= bootstrap_port
;
1901 restarting_via_mach_init
= TRUE
;
1903 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
1905 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
1906 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
1907 if (status
!= KERN_SUCCESS
) return status
;
1909 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
1910 if (status
!= KERN_SUCCESS
)
1912 mach_port_deallocate(mach_task_self(), server_priv_port
);
1916 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1917 if (status
!= KERN_SUCCESS
)
1919 mach_port_deallocate(mach_task_self(), server_priv_port
);
1920 mach_port_deallocate(mach_task_self(), service_send_port
);
1923 assert(service_send_port
== service_rcv_port
);
1927 * We have no intention of responding to requests on the service port. We are not otherwise
1928 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
1929 * So, we can dispose of all the rights we have for the service port. We don't destroy the
1930 * send right for the server's privileged bootstrap port - in case we have to unregister later.
1932 mach_port_destroy(mach_task_self(), service_rcv_port
);
1936 mDNSlocal kern_return_t
destroyBootstrapService()
1938 debugf("Destroying Bootstrap Service");
1939 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
1942 mDNSlocal
void ExitCallback(int sig
)
1944 (void)sig
; // Unused
1945 LogMsgIdent(mDNSResponderVersionString
, "stopping");
1947 debugf("ExitCallback");
1948 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
1949 destroyBootstrapService();
1951 debugf("ExitCallback: Aborting MIG clients");
1952 while (DNSServiceDomainEnumerationList
)
1953 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
1954 while (DNSServiceBrowserList
)
1955 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
1956 while (DNSServiceResolverList
)
1957 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
1958 while (DNSServiceRegistrationList
)
1959 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
1961 if (udsserver_exit(launchd_fd
) < 0) LogMsg("ExitCallback: udsserver_exit failed");
1963 debugf("ExitCallback: mDNS_StartExit");
1964 mDNS_StartExit(&mDNSStorage
);
1967 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
1968 mDNSlocal
void HandleSIG(int sig
)
1971 debugf("HandleSIG %d", sig
);
1972 mach_msg_header_t header
;
1973 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1974 header
.msgh_remote_port
= signal_port
;
1975 header
.msgh_local_port
= MACH_PORT_NULL
;
1976 header
.msgh_size
= sizeof(header
);
1977 header
.msgh_id
= sig
;
1978 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1980 LogMsg("HandleSIG %d: mach_msg_send failed", sig
);
1981 if (sig
== SIGTERM
|| sig
== SIGINT
) exit(-1);
1985 mDNSlocal
void CatchABRT(int sig
)
1987 LogMsg("Received SIGABRT %d", sig
);
1988 sleep(1); // Pause to make sure syslog gets the message
1989 while(1) *(long*)0 = 0; // Generate a CrashReporter stack trace so we can find out what library called abort();
1992 mDNSlocal
void INFOCallback(void)
1994 mDNSs32 utc
= mDNSPlatformUTC();
1995 DNSServiceDomainEnumeration
*e
;
1996 DNSServiceBrowser
*b
;
1997 DNSServiceResolver
*l
;
1998 DNSServiceRegistration
*r
;
1999 NetworkInterfaceInfoOSX
*i
;
2002 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2004 udsserver_info(&mDNSStorage
);
2006 LogMsgNoIdent("--------- Mach Clients ---------");
2007 if (!DNSServiceDomainEnumerationList
&& !DNSServiceBrowserList
&& !DNSServiceResolverList
&& !DNSServiceRegistrationList
)
2008 LogMsgNoIdent("<None>");
2011 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2012 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2014 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2016 DNSServiceBrowserQuestion
*qptr
;
2017 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2018 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2020 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2021 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2023 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2025 ServiceInstance
*si
;
2026 for (si
= r
->regs
; si
; si
= si
->next
)
2027 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
));
2031 LogMsgNoIdent("----- KQSocketEventSources -----");
2032 if (!gEventSources
) LogMsgNoIdent("<None>");
2035 KQSocketEventSource
*k
;
2036 for (k
= gEventSources
; k
; k
=k
->next
)
2037 LogMsgNoIdent("%3d %s", k
->fd
, k
->kqs
.KQtask
);
2040 LogMsgNoIdent("------ Network Interfaces ------");
2041 if (!mDNSStorage
.p
->InterfaceList
) LogMsgNoIdent("<None>");
2044 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2047 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds",
2048 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2049 &i
->ifinfo
.ip
, utc
- i
->LastSeen
);
2051 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a",
2052 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2053 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2054 i
->ifinfo
.IPv4Available
? "v4" : " ",
2055 i
->ifinfo
.IPv4Available
? (mDNSv4Addr
*)&i
->ifa_v4addr
: &zerov4Addr
,
2056 i
->ifinfo
.IPv6Available
? "v6" : " ",
2057 i
->ifinfo
.InterfaceID
,
2058 i
->ifinfo
.Advertise
? "Adv" : " ",
2059 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2064 LogMsgNoIdent("--------- DNS Servers ----------");
2065 if (!mDNSStorage
.DNSServers
) LogMsgNoIdent("<None>");
2068 for (s
= mDNSStorage
.DNSServers
; s
; s
= s
->next
)
2070 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)s
->interface
;
2071 LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
2072 s
->domain
.c
, ifx
? ifx
->ifa_name
: "", ifx
? " " : "", &s
->addr
, mDNSVal16(s
->port
),
2073 s
->teststate
== DNSServer_Untested
? "(Untested)" :
2074 s
->teststate
== DNSServer_Passed
? "" :
2075 s
->teststate
== DNSServer_Failed
? "(Failed)" :
2076 s
->teststate
== DNSServer_Disabled
? "(Disabled)" : "(Unknown state)");
2080 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
2081 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
2083 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2086 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2088 (void)port
; // Unused
2089 (void)size
; // Unused
2090 (void)info
; // Unused
2091 mach_msg_header_t
*msg_header
= (mach_msg_header_t
*)msg
;
2092 mDNS
*const m
= &mDNSStorage
;
2094 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
2096 switch(msg_header
->msgh_id
)
2102 LogMsg("SIGHUP: Purge cache");
2103 FORALL_CACHERECORDS(slot
, cg
, rr
) mDNS_PurgeCacheResourceRecord(m
, rr
);
2106 case SIGTERM
: ExitCallback(msg_header
->msgh_id
); break;
2107 case SIGINFO
: INFOCallback(); break;
2108 case SIGUSR1
: // mDNSCoreMachineSleep(m, !m->SleepState); break;
2109 LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2110 mDNSMacOSXNetworkChanged(m
);
2112 // Simulate KeychainChanged
2114 SetDomainSecrets(m
);
2118 case SIGUSR2
: SigLogLevel(); break;
2119 default: LogMsg("SignalCallback: Unknown signal %d", msg_header
->msgh_id
); break;
2121 KQueueUnlock(m
, "Unix Signal");
2124 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2125 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2127 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2130 CFMachPortRef s_port
;
2132 // If launchd already created our Mach port for us, then use that, else we create a new one of our own
2133 if (m_port
!= MACH_PORT_NULL
)
2134 s_port
= CFMachPortCreateWithPort(NULL
, m_port
, DNSserverCallback
, NULL
, NULL
);
2137 s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2138 m_port
= CFMachPortGetPort(s_port
);
2139 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2140 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2145 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2147 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2152 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2153 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2154 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2155 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2156 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2158 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2159 rrcachestorage
, RR_CACHE_SIZE
,
2160 mDNS_Init_AdvertiseLocalAddresses
,
2161 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2163 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2165 client_death_port
= CFMachPortGetPort(d_port
);
2166 signal_port
= CFMachPortGetPort(i_port
);
2168 CFRunLoop
= CFRunLoopGetCurrent();
2169 CFRunLoopAddSource(CFRunLoop
, d_rls
, kCFRunLoopDefaultMode
);
2170 CFRunLoopAddSource(CFRunLoop
, s_rls
, kCFRunLoopDefaultMode
);
2171 CFRunLoopAddSource(CFRunLoop
, i_rls
, kCFRunLoopDefaultMode
);
2175 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2179 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2181 mDNSs32 now
= mDNS_TimeNow(m
);
2183 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2185 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2186 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2187 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2188 // we then systematically lose our own looped-back packets.
2189 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2191 // KeyChain frequently fails to notify clients of change events. To work around this
2192 // we set a timer and periodically poll to detect if any changes have occurred.
2193 // Without this Back To My Mac just does't work for a large number of users.
2194 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
2195 if (m
->p
->KeyChainBugTimer
&& now
- m
->p
->KeyChainBugTimer
>= 0)
2197 m
->p
->KeyChainBugInterval
*= 2;
2198 m
->p
->KeyChainBugTimer
= NonZeroTime(now
+ m
->p
->KeyChainBugInterval
);
2199 if (m
->p
->KeyChainBugInterval
> 2 * mDNSPlatformOneSecond
) m
->p
->KeyChainBugTimer
= 0;
2201 SetDomainSecrets(m
);
2205 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2206 mDNSs32 nextevent
= mDNS_Execute(m
);
2208 if (m
->p
->NetworkChanged
)
2209 if (nextevent
- m
->p
->NetworkChanged
> 0)
2210 nextevent
= m
->p
->NetworkChanged
;
2212 if (m
->p
->KeyChainBugTimer
)
2213 if (nextevent
- m
->p
->KeyChainBugTimer
> 0)
2214 nextevent
= m
->p
->KeyChainBugTimer
;
2216 // 3. Deliver any waiting browse messages to clients
2217 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2221 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2222 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2223 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2224 DNSServiceBrowser
*x
= b
;
2226 if (x
->results
) // Try to deliver the list of results
2230 DNSServiceBrowserResult
*const r
= x
->results
;
2232 domainname type
, domain
;
2233 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2234 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2235 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2236 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2237 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2238 ConvertDomainNameToCString(&type
, ctype
);
2239 ConvertDomainNameToCString(&domain
, cdom
);
2240 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2241 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2242 // If we failed to send the mach message, try again in one second
2243 if (status
== MACH_SEND_TIMED_OUT
)
2245 if (nextevent
- now
> mDNSPlatformOneSecond
)
2246 nextevent
= now
+ mDNSPlatformOneSecond
;
2251 x
->lastsuccess
= now
;
2252 x
->results
= x
->results
->next
;
2253 freeL("DNSServiceBrowserResult", r
);
2256 // If this client hasn't read a single message in the last 60 seconds, abort it
2257 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2258 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2262 DNSServiceResolver
*l
;
2263 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2264 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2267 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2268 "This places considerable burden on the network.", l
->i
.name
.c
);
2271 if (m
->p
->NotifyUser
)
2273 if (m
->p
->NotifyUser
- now
< 0)
2275 if (!SameDomainLabelCS(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2277 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2278 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
2279 m
->p
->usernicelabel
= m
->nicelabel
;
2281 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2283 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2284 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
2285 m
->p
->HostNameConflict
= 0; // Clear our indicator, now name change has been successful
2286 m
->p
->userhostlabel
= m
->hostlabel
;
2288 m
->p
->NotifyUser
= 0;
2291 if (nextevent
- m
->p
->NotifyUser
> 0)
2292 nextevent
= m
->p
->NotifyUser
;
2298 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2302 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2304 // NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent
2306 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2307 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2308 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2309 if (m
->NewLocalOnlyQuestions
)
2310 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2311 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2312 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2313 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2314 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2315 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2316 #ifndef UNICAST_DISABLED
2317 if (m
->timenow
- m
->NextuDNSEvent
>= 0)
2318 LogMsg("Task Scheduling Error: NextuDNSEvent %d", m
->timenow
- m
->NextuDNSEvent
);
2320 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2321 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2322 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2323 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2324 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2325 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2326 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2327 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2328 if (m
->timenow
- m
->NextScheduledNATOp
>= 0)
2329 LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m
->timenow
- m
->NextScheduledNATOp
);
2331 mDNS_Unlock(&mDNSStorage
);
2334 mDNSlocal mDNSBool
ReadyForSleep(mDNS
*m
)
2338 // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server
2340 for (q
= m
->Questions
; q
; q
= q
->next
)
2341 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->ReqLease
== 0 && q
->tcp
) return(mDNSfalse
);
2343 // 2. Scan list of registered records
2345 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
2346 if (rr
->state
== regState_Refresh
&& rr
->tcp
) return(mDNSfalse
);
2348 // 2. Scan list of registered services
2349 ServiceRecordSet
*srs
;
2350 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
2351 if (srs
->state
== regState_NoTarget
&& srs
->tcp
) return(mDNSfalse
);
2356 mDNSlocal
void KQWokenFlushBytes(int fd
, __unused
short filter
, __unused
void *context
)
2358 // Read all of the bytes so we won't wake again.
2360 while (recv(fd
, buffer
, sizeof(buffer
), MSG_DONTWAIT
) > 0) continue;
2363 mDNSlocal
void * KQueueLoop(void *m_param
)
2368 #if USE_SELECT_WITH_KQUEUEFD
2371 const int multiplier
= 1000000 / mDNSPlatformOneSecond
;
2373 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
2376 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2377 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2379 // This is the main work loop:
2380 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2381 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2382 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2383 // (4) On wakeup we first process *all* events
2384 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2387 #define kEventsToReadAtOnce 1
2388 struct kevent new_events
[kEventsToReadAtOnce
];
2390 // Run mDNS_Execute to find out the time we next need to wake up
2391 mDNSs32 start
= mDNSPlatformRawTime();
2392 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
2393 mDNSs32 end
= mDNSPlatformRawTime();
2394 if (end
- start
>= WatchDogReportingThreshold
)
2395 LogOperation("WARNING: Idle task took %dms to complete", end
- start
);
2397 mDNSs32 now
= mDNS_TimeNow(m
);
2399 if (m
->ShutdownTime
)
2401 if (mDNS_ExitNow(m
, now
))
2403 LogOperation("mDNS_FinalExit");
2404 mDNS_FinalExit(&mDNSStorage
);
2405 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
2408 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
2409 nextTimerEvent
= m
->ShutdownTime
;
2412 if (m
->p
->SleepLimit
)
2414 mDNSBool ready
= ReadyForSleep(m
);
2415 if (ready
|| now
- m
->p
->SleepLimit
>= 0)
2417 LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m
->p
->SleepCookie
,
2418 ready
? "ready for sleep" : "giving up", now
, m
->p
->SleepLimit
- now
);
2419 m
->p
->SleepLimit
= 0;
2420 IOAllowPowerChange(m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2423 if (nextTimerEvent
- m
->p
->SleepLimit
>= 0)
2424 nextTimerEvent
= m
->p
->SleepLimit
;
2427 // Convert absolute wakeup time to a relative time from now
2428 mDNSs32 ticks
= nextTimerEvent
- now
;
2429 if (ticks
< 1) ticks
= 1;
2431 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2437 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2440 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2443 // Release the lock, and sleep until:
2444 // 1. Something interesting happens like a packet arriving, or
2445 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
2446 // 3. The timeout expires
2447 pthread_mutex_unlock(&PlatformStorage
.BigMutex
);
2449 #if USE_SELECT_WITH_KQUEUEFD
2450 struct timeval timeout
;
2451 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2452 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2453 FD_SET(KQueueFD
, &readfds
);
2454 if (select(KQueueFD
+1, &readfds
, NULL
, NULL
, &timeout
) < 0)
2455 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2457 struct timespec timeout
;
2458 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2459 timeout
.tv_nsec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2460 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
2461 // and have it work similarly to the way it does with nevents non-zero --
2462 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
2463 // In fact, what happens if you do this is that it just returns immediately. So, we have
2464 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
2465 if (kevent(KQueueFD
, NULL
, 0, new_events
, 1, &timeout
) < 0)
2466 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2469 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2470 // We have to ignore the event we may have been told about above, because that
2471 // was done without holding the lock, and between the time we woke up and the
2472 // time we reclaimed the lock the other thread could have done something that
2473 // makes the event no longer valid. Now we have the lock, we call kevent again
2474 // and this time we can safely process the events it tells us about.
2476 static const struct timespec zero_timeout
= { 0, 0 };
2478 while ((events_found
= kevent(KQueueFD
, NULL
, 0, new_events
, kEventsToReadAtOnce
, &zero_timeout
)) != 0)
2480 if (events_found
> kEventsToReadAtOnce
|| (events_found
< 0 && errno
!= EINTR
))
2482 // Not sure what to do here, our kqueue has failed us - this isn't ideal
2483 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno
, strerror(errno
));
2487 numevents
+= events_found
;
2490 for (i
= 0; i
< events_found
; i
++)
2492 const KQueueEntry
*const kqentry
= new_events
[i
].udata
;
2493 mDNSs32 stime
= mDNSPlatformRawTime();
2494 #if LogAllOperations || MDNS_DEBUGMSGS
2495 const char *const KQtask
= kqentry
->KQtask
; // Grab a copy in case KQcallback deletes the task
2497 kqentry
->KQcallback(new_events
[i
].ident
, new_events
[i
].filter
, kqentry
->KQcontext
);
2498 mDNSs32 etime
= mDNSPlatformRawTime();
2499 if (etime
- stime
>= WatchDogReportingThreshold
)
2500 LogOperation("WARNING: %s took %dms to complete", KQtask
, etime
- stime
);
2508 mDNSlocal
void LaunchdCheckin(void)
2510 launch_data_t msg
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
2511 launch_data_t resp
= launch_msg(msg
);
2512 launch_data_free(msg
);
2513 if (!resp
) { LogMsg("launch_msg returned NULL"); return; }
2515 if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
)
2517 int err
= launch_data_get_errno(resp
);
2518 // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
2519 if (err
!= EACCES
) LogMsg("launch_msg returned %d", err
);
2520 else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err
);
2524 launch_data_t skts
= launch_data_dict_lookup(resp
, LAUNCH_JOBKEY_SOCKETS
);
2525 if (!skts
) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
2528 launch_data_t skt
= launch_data_dict_lookup(skts
, "Listeners");
2529 if (!skt
) LogMsg("launch_data_dict_lookup Listeners returned NULL");
2532 launch_data_t s
= launch_data_array_get_index(skt
, 0);
2533 if (!s
) LogMsg("launch_data_array_get_index(skt, 0) returned NULL");
2536 launchd_fd
= launch_data_get_fd(s
);
2537 LogOperation("Launchd Unix Domain Socket: %d", launchd_fd
);
2538 // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
2539 chmod(MDNS_UDS_SERVERPATH
, S_IRUSR
|S_IWUSR
| S_IRGRP
|S_IWGRP
| S_IROTH
|S_IWOTH
);
2544 launch_data_t ports
= launch_data_dict_lookup(resp
, "MachServices");
2545 if (!ports
) LogMsg("launch_data_dict_lookup MachServices returned NULL");
2548 launch_data_t p
= launch_data_dict_lookup(ports
, "com.apple.mDNSResponder");
2549 if (!p
) LogOperation("launch_data_array_get_index(ports, 0) returned NULL");
2552 m_port
= launch_data_get_fd(p
);
2553 LogOperation("Launchd Mach Port: %d", m_port
);
2554 if (m_port
== ~0U) m_port
= MACH_PORT_NULL
;
2558 launch_data_free(resp
);
2561 mDNSlocal
void DropPrivileges(void)
2563 static const char login
[] = "_mdnsresponder";
2564 struct passwd
*pwd
= getpwnam(login
);
2566 LogMsg("Could not find account name \"%s\". Running as root.", login
);
2569 uid_t uid
= pwd
->pw_uid
;
2570 gid_t gid
= pwd
->pw_gid
;
2572 LogMsg("Started as root. Switching to userid \"%s\".", login
);
2574 if (unlink(MDNS_UDS_SERVERPATH
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, errno
, strerror(errno
));
2577 static char path
[] = "/var/run/mdns/mDNSResponder";
2578 char *p
= strrchr(path
, '/');
2580 if (mkdir(path
, 0755) < 0 && errno
!= EEXIST
) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2581 else if (chown(path
, uid
, gid
) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2585 if (unlink(path
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2586 else if (symlink(path
, MDNS_UDS_SERVERPATH
) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, path
, errno
, strerror(errno
));
2587 else LogOperation("DropPrivileges: Created subdirectory and symlink");
2591 if (0 != initgroups(login
, gid
)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login
, (unsigned long)gid
);
2592 if (0 != setgid(gid
)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
2593 if (0 != setuid(uid
)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid
);
2597 extern int sandbox_init(const char *profile
, uint64_t flags
, char **errorbuf
) __attribute__((weak_import
));
2599 mDNSexport
int main(int argc
, char **argv
)
2602 kern_return_t status
;
2603 pthread_t KQueueThread
;
2605 LogMsgIdent(mDNSResponderVersionString
, "starting");
2607 if (0 == geteuid()) DropPrivileges();
2609 for (i
=1; i
<argc
; i
++)
2611 if (!strcasecmp(argv
[i
], "-d" )) mDNS_DebugMode
= mDNStrue
;
2612 if (!strcasecmp(argv
[i
], "-launchd" )) started_via_launchdaemon
= mDNStrue
;
2613 if (!strcasecmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2616 signal(SIGHUP
, HandleSIG
); // (Debugging) Purge the cache to check for cache handling bugs
2617 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2618 signal(SIGABRT
, CatchABRT
); // For debugging -- SIGABRT should never happen
2619 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2620 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2621 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2622 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2623 signal(SIGUSR2
, HandleSIG
); // (Debugging) Change log level
2625 mDNSStorage
.p
= &PlatformStorage
; // Make sure mDNSStorage.p is set up, because validatelists uses it
2628 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2629 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2631 registerBootstrapService();
2632 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2633 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2634 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2637 // Avoid unnecessarily duplicating a file descriptor to itself
2638 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2639 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2640 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2641 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2645 // Create the kqueue, mutex and thread to support KQSockets
2646 KQueueFD
= kqueue();
2647 if (KQueueFD
== -1) { LogMsg("kqueue() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2649 i
= pthread_mutex_init(&PlatformStorage
.BigMutex
, NULL
);
2650 if (i
== -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2652 int fdpair
[2] = {0, 0};
2653 i
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
);
2654 if (i
== -1) { LogMsg("socketpair() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2656 // Socket pair returned us two identical sockets connected to each other
2657 // We will use the first socket to send the second socket. The second socket
2658 // will be added to the kqueue so it will wake when data is sent.
2659 static const KQueueEntry wakeKQEntry
= { KQWokenFlushBytes
, NULL
, "kqueue wakeup after CFRunLoop event" };
2660 PlatformStorage
.WakeKQueueLoopFD
= fdpair
[0];
2661 KQueueSet(fdpair
[1], EV_ADD
, EVFILT_READ
, &wakeKQEntry
);
2663 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
2665 LogMsg("Note: Compiled without Apple Sandbox support");
2668 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
2672 int sandbox_err
= sandbox_init("mDNSResponder", SANDBOX_NAMED
, &sandbox_msg
);
2673 if (sandbox_err
) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg
); sandbox_free_error(sandbox_msg
); }
2674 else LogOperation("Now running under Apple Sandbox restrictions");
2678 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2679 status
= mDNSDaemonInitialize();
2680 if (status
) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit
; }
2681 status
= udsserver_init(launchd_fd
);
2682 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2684 // Start the kqueue thread
2685 i
= pthread_create(&KQueueThread
, NULL
, KQueueLoop
, &mDNSStorage
);
2686 if (i
== -1) { LogMsg("pthread_create() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2691 LogMsg("ERROR: CFRunLoopRun Exiting.");
2692 mDNS_Close(&mDNSStorage
);
2695 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2698 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2702 // uds_daemon.c support routines /////////////////////////////////////////////
2704 // Arrange things so that callback is called with context when data appears on fd
2705 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2707 KQSocketEventSource
*newSource
= (KQSocketEventSource
*) mallocL("KQSocketEventSource", sizeof *newSource
);
2708 if (!newSource
) return mStatus_NoMemoryErr
;
2710 mDNSPlatformMemZero(newSource
, sizeof(*newSource
));
2712 newSource
->kqs
.KQcallback
= callback
;
2713 newSource
->kqs
.KQcontext
= context
;
2714 newSource
->kqs
.KQtask
= "UDS client";
2716 if (KQueueSet(fd
, EV_ADD
, EVFILT_READ
, &newSource
->kqs
) == 0)
2718 KQSocketEventSource
**p
= &gEventSources
;
2719 while (*p
) p
= &(*p
)->next
;
2721 return mStatus_NoError
;
2727 return mStatus_NoMemoryErr
;
2731 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2733 KQSocketEventSource
**p
= &gEventSources
;
2734 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
2737 KQSocketEventSource
*s
= *p
;
2739 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
2740 // causes the kernel to automatically remove any associated kevents
2742 freeL("KQSocketEventSource", s
);
2743 return mStatus_NoError
;
2745 return mStatus_NoSuchNameErr
;
2748 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2749 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2750 asm(".desc ___crashreporter_info__, 0x10");
2752 // For convenience when using the "strings" command, this is the last thing in the file
2753 // The "@(#) " pattern is a special prefix the "what" command looks for
2754 mDNSexport
const char mDNSResponderVersionString_SCCS
[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";