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.360 2008/03/13 20:55:16 mcguire
34 <rdar://problem/5769316> fix deprecated warnings/errors
35 Additional cleanup: use a conditional macro instead of lots of #if
37 Revision 1.359 2008/03/12 23:02:58 mcguire
38 <rdar://problem/5769316> fix deprecated warnings/errors
40 Revision 1.358 2008/03/06 21:26:11 cheshire
41 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
43 Revision 1.357 2008/02/13 17:40:43 cheshire
44 <rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
46 Revision 1.356 2007/12/18 00:28:56 cheshire
47 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
48 Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
50 Revision 1.355 2007/12/17 22:29:22 cheshire
51 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
52 Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
54 Revision 1.354 2007/12/15 01:12:28 cheshire
55 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
57 Revision 1.353 2007/12/14 19:14:02 cheshire
58 Added (commented out) code for testing sleep/wake
60 Revision 1.352 2007/12/14 00:58:29 cheshire
61 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
62 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
63 until TLS/TCP deregistrations have completed (up to five seconds maximum)
65 Revision 1.351 2007/12/12 21:34:18 cheshire
66 Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
67 it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
68 confirmed that the bug is definitely fixed we'll remove the workaround altogether.
70 Revision 1.350 2007/12/07 00:45:58 cheshire
71 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
73 Revision 1.349 2007/12/04 22:00:54 cheshire
74 Fixed mistake in comment
76 Revision 1.348 2007/12/01 00:27:43 cheshire
77 Fixed compile warning: declaration of 'r' shadows a previous local
79 Revision 1.347 2007/11/02 22:00:13 cheshire
80 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
81 Need to hold the lock while calling SetDomainSecrets
83 Revision 1.346 2007/11/02 20:18:13 cheshire
84 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
86 Revision 1.345 2007/10/17 18:41:21 cheshire
87 For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
89 Revision 1.344 2007/09/29 01:06:17 mcguire
90 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
92 Revision 1.343 2007/09/24 05:02:41 cheshire
93 Debugging: In SIGINFO output, indicate explicitly when a given section is empty
95 Revision 1.342 2007/09/18 19:09:02 cheshire
96 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
98 Revision 1.341 2007/09/12 01:22:13 cheshire
99 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
101 Revision 1.340 2007/09/07 22:44:03 mcguire
102 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
104 Revision 1.339 2007/09/06 19:08:29 cheshire
105 LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
107 Revision 1.338 2007/09/05 23:34:27 mcguire
108 Revert logging change
110 Revision 1.337 2007/09/05 20:45:50 cheshire
111 Added list of KQSocketEventSources in SIGINFO output
113 Revision 1.336 2007/08/31 17:15:37 cheshire
114 Reordered startup log messages so that "mDNSResponder ... starting" is the first message
116 Revision 1.335 2007/08/31 02:00:16 cheshire
117 Added comment explaining use of zero-width non-breaking space character to tag literal strings
119 Revision 1.334 2007/08/24 23:40:24 cheshire
120 Added comment about FreeServiceInstance
122 Revision 1.333 2007/08/23 21:02:35 cheshire
123 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
125 Revision 1.332 2007/08/22 23:54:54 mcguire
126 <rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
128 Revision 1.331 2007/08/18 01:02:03 mcguire
129 <rdar://problem/5415593> No Bonjour services are getting registered at boot
131 Revision 1.330 2007/08/10 22:25:57 mkrochma
132 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
134 Revision 1.329 2007/08/08 22:34:58 mcguire
135 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
137 Revision 1.328 2007/07/27 22:43:37 cheshire
138 Improved mallocL/freeL "suspiciously large" debugging messages
140 Revision 1.327 2007/07/27 19:30:41 cheshire
141 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
142 to properly reflect tri-state nature of the possible responses
144 Revision 1.326 2007/07/24 17:23:33 cheshire
145 <rdar://problem/5357133> Add list validation checks for debugging
147 Revision 1.325 2007/07/11 23:43:43 cheshire
148 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
150 Revision 1.324 2007/07/11 22:44:40 cheshire
151 <rdar://problem/5328801> SIGHUP should purge the cache
153 Revision 1.323 2007/07/11 03:01:50 cheshire
154 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
156 Revision 1.322 2007/07/06 18:58:16 cheshire
157 Check m->NextScheduledNATOp in ShowTaskSchedulingError()
159 Revision 1.321 2007/07/02 21:54:20 cheshire
160 Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
162 Revision 1.320 2007/06/28 21:16:27 cheshire
163 Rename "m->nextevent" as more informative "m->NextuDNSEvent"
165 Revision 1.319 2007/06/22 20:47:08 cheshire
166 <rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
167 Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
169 Revision 1.318 2007/06/20 01:45:40 cheshire
170 When showing dormant interfaces, display last-seen IP address for that dormant interface
172 Revision 1.317 2007/06/20 01:10:12 cheshire
173 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
175 Revision 1.316 2007/06/19 19:27:11 cheshire
176 <rdar://problem/5141540> Sandbox mDNSResponder
177 Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
179 Revision 1.315 2007/06/15 21:54:51 cheshire
180 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
182 Revision 1.314 2007/06/15 19:23:17 cheshire
183 <rdar://problem/5254053> mDNSResponder renames my host without asking
184 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
186 Revision 1.313 2007/05/25 16:02:05 cheshire
187 When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
189 Revision 1.312 2007/05/22 19:07:21 cheshire
190 Add comment explaining RR_CACHE_SIZE calculation
192 Revision 1.311 2007/05/15 21:47:21 cheshire
193 Get rid of "#pragma unused(m)"
195 Revision 1.310 2007/05/08 00:56:17 cheshire
196 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
198 Revision 1.309 2007/04/30 21:33:38 cheshire
199 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
200 is iterating through the m->ServiceRegistrations list
202 Revision 1.308 2007/04/28 01:31:59 cheshire
203 Improve debugging support for catching memory corruption problems
205 Revision 1.307 2007/04/24 18:32:00 cheshire
206 Grab a copy of KQtask string pointer in case KQcallback deletes the task
208 Revision 1.306 2007/04/22 19:11:51 cheshire
209 Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
210 if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
211 from the project and just using simple vanilla C linked-list manipulation instead.
213 Revision 1.305 2007/04/22 06:02:03 cheshire
214 <rdar://problem/4615977> Query should immediately return failure when no server
216 Revision 1.304 2007/04/21 21:47:47 cheshire
217 <rdar://problem/4376383> Daemon: Add watchdog timer
219 Revision 1.303 2007/04/18 00:50:47 cheshire
220 <rdar://problem/5141540> Sandbox mDNSResponder
222 Revision 1.302 2007/04/07 01:01:48 cheshire
223 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
225 Revision 1.301 2007/04/05 19:13:48 cheshire
226 Use better name in SCPreferencesCreate
228 Revision 1.300 2007/04/04 21:22:18 cheshire
229 Suppress "Local Hostname changed" syslog message when name has not actually changed
231 Revision 1.299 2007/04/03 19:19:33 cheshire
232 Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
234 Revision 1.298 2007/03/30 21:51:45 cheshire
237 Revision 1.297 2007/03/27 22:47:19 cheshire
238 On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
240 Revision 1.296 2007/03/24 01:23:29 cheshire
241 Call validator for uDNS data structures
243 Revision 1.295 2007/03/20 23:32:49 cheshire
244 Minor textual tidying
246 Revision 1.294 2007/03/07 02:50:50 cheshire
247 <rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
249 Revision 1.293 2007/03/06 22:59:01 cheshire
250 <rdar://problem/4157921> Security: Null dereference possible in daemon.c
252 Revision 1.292 2007/02/28 21:55:10 cheshire
253 <rdar://problem/3862944> UI: Name conflict notifications should be localized
254 Additional fix: We were not getting our NotificationCallBackDismissed messages
255 because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
256 (We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
258 Revision 1.291 2007/02/28 03:51:24 cheshire
259 <rdar://problem/3862944> UI: Name conflict notifications should be localized
260 Moved curly quotes out of the literal text and into the localized text, so they
261 can be replaced with alternate characters as appropriate for other languages.
263 Revision 1.290 2007/02/14 01:58:19 cheshire
264 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
266 Revision 1.289 2007/02/07 19:32:00 cheshire
267 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
269 Revision 1.288 2007/02/07 01:01:24 cheshire
270 <rdar://problem/3956518> Need to go native with launchd
271 Additional refinements -- was unnecessarily calling launch_data_free()
273 Revision 1.287 2007/02/06 19:06:48 cheshire
274 <rdar://problem/3956518> Need to go native with launchd
276 Revision 1.286 2007/01/06 01:00:33 cheshire
277 Improved SIGINFO output
279 Revision 1.285 2007/01/05 08:30:47 cheshire
280 Trim excessive "$Log" checkin history from before 2006
281 (checkin history still available via "cvs log ..." of course)
283 Revision 1.284 2007/01/05 05:44:35 cheshire
284 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
285 so that mDNSPosix embedded clients will compile again
287 Revision 1.283 2007/01/04 23:11:14 cheshire
288 <rdar://problem/4720673> uDNS: Need to start caching unicast records
289 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
291 Revision 1.282 2006/12/21 00:09:45 cheshire
292 Use mDNSPlatformMemZero instead of bzero
294 Revision 1.281 2006/11/18 05:01:32 cheshire
295 Preliminary support for unifying the uDNS and mDNS code,
296 including caching of uDNS answers
298 Revision 1.280 2006/11/10 00:54:16 cheshire
299 <rdar://problem/4816598> Changing case of Computer Name doesn't work
301 Revision 1.279 2006/11/02 17:44:01 cheshire
302 No longer have a separate uDNS ActiveQueries list
304 Revision 1.278 2006/10/05 04:04:24 herscher
305 Remove embedded uDNS_info struct from DNSQuestion_struct
307 Revision 1.277 2006/09/21 21:01:24 cheshire
308 Change 'autorename' to more accurate name 'renameonmemfree'
310 Revision 1.276 2006/09/17 19:12:02 cheshire
311 Further changes for removal of uDNS_info substructure from mDNS_struct
313 Revision 1.275 2006/09/15 21:20:16 cheshire
314 Remove uDNS_info substructure from mDNS_struct
316 Revision 1.274 2006/08/14 23:24:39 cheshire
317 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
319 Revision 1.273 2006/07/30 05:43:19 cheshire
320 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
321 Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
323 Revision 1.272 2006/07/27 03:24:35 cheshire
324 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
325 Further refinement: Declare KQueueEntry parameter "const"
327 Revision 1.271 2006/07/27 02:59:26 cheshire
328 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
329 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
330 after releasing BigMutex, in case actions it took have resulted in new work for the
331 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
332 add new active interfaces to its list, and consequently schedule queries to be sent).
334 Revision 1.270 2006/07/25 17:16:36 mkrochma
335 Quick fix to solve kqueue related crashes and hangs
337 Revision 1.269 2006/07/22 06:11:37 cheshire
338 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
340 Revision 1.268 2006/07/15 02:01:32 cheshire
341 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
342 Fix broken "empty string" browsing
344 Revision 1.267 2006/07/07 01:09:10 cheshire
345 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
346 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
348 Revision 1.266 2006/07/05 23:34:53 cheshire
349 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
351 Revision 1.265 2006/06/29 07:32:08 cheshire
352 Added missing LogOperation logging for DNSServiceBrowse results
354 Revision 1.264 2006/06/29 05:33:30 cheshire
355 <rdar://problem/4607043> mDNSResponder conditional compilation options
357 Revision 1.263 2006/06/08 23:23:48 cheshire
358 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
360 Revision 1.262 2006/03/18 21:49:11 cheshire
361 Added comment in ShowTaskSchedulingError(mDNS *const m)
363 Revision 1.261 2006/01/06 01:22:28 cheshire
364 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
368 #include <mach/mach.h>
369 #include <mach/mach_error.h>
370 #include <servers/bootstrap.h>
371 #include <sys/types.h>
377 #include <sys/event.h>
380 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
382 #if TARGET_OS_EMBEDDED
383 #include <bootstrap_priv.h>
385 #define bootstrap_register(A,B,C) bootstrap_register2((A),(B),(C),0)
388 #include "DNSServiceDiscoveryRequestServer.h"
389 #include "DNSServiceDiscoveryReply.h"
392 #include "DNSCommon.h"
393 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
395 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
397 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
400 //*************************************************************************************************************
403 static mDNS_PlatformSupport PlatformStorage
;
405 // Start off with a default cache of 16K (99 records)
406 // Each time we grow the cache we add another 99 records
407 // 99 * 164 = 16236 bytes.
408 // This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
409 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
410 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
412 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
413 static mach_port_t m_port
= MACH_PORT_NULL
;
414 static mach_port_t client_death_port
= MACH_PORT_NULL
;
415 static mach_port_t signal_port
= MACH_PORT_NULL
;
416 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
418 static dnssd_sock_t launchd_fd
= dnssd_InvalidSocket
;
420 // mDNS Mach Message Timeout, in milliseconds.
421 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
422 // fails to service its mach message queue, but long enough to give a well-written
423 // client a chance to service its mach message queue without getting cut off.
424 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
425 // even extra-slow clients a fair chance before we cut them off.
426 #define MDNS_MM_TIMEOUT 250
428 static int restarting_via_mach_init
= 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
429 static int started_via_launchdaemon
= 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
433 static CFRunLoopRef CFRunLoop
;
435 //*************************************************************************************************************
436 // Active client list structures
438 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
439 struct DNSServiceDomainEnumeration_struct
441 DNSServiceDomainEnumeration
*next
;
442 mach_port_t ClientMachPort
;
443 DNSQuestion dom
; // Question asking for domains
444 DNSQuestion def
; // Question asking for default domain
447 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
448 struct DNSServiceBrowserResult_struct
450 DNSServiceBrowserResult
*next
;
455 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
457 typedef struct DNSServiceBrowserQuestion
459 struct DNSServiceBrowserQuestion
*next
;
462 } DNSServiceBrowserQuestion
;
464 struct DNSServiceBrowser_struct
466 DNSServiceBrowser
*next
;
467 mach_port_t ClientMachPort
;
468 DNSServiceBrowserQuestion
*qlist
;
469 DNSServiceBrowserResult
*results
;
471 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
472 domainname type
; // registration type
475 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
476 struct DNSServiceResolver_struct
478 DNSServiceResolver
*next
;
479 mach_port_t ClientMachPort
;
485 // A single registered service: ServiceRecordSet + bookkeeping
486 // Note that we duplicate some fields from parent DNSServiceRegistration object
487 // to facilitate cleanup, when instances and parent may be deallocated at different times.
488 typedef struct ServiceInstance
490 struct ServiceInstance
*next
;
491 mach_port_t ClientMachPort
;
492 mDNSBool autoname
; // Set if this name is tied to the Computer Name
493 mDNSBool renameonmemfree
; // Set if we just got a name conflict and now need to automatically pick a new name
496 ServiceRecordSet srs
;
497 // Don't add any fields after ServiceRecordSet.
498 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
501 // A client-created service. May reference several ServiceInstance objects if default
502 // settings cause registration in multiple domains.
503 typedef struct DNSServiceRegistration
505 struct DNSServiceRegistration
*next
;
506 mach_port_t ClientMachPort
;
507 mDNSBool DefaultDomain
;
511 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
512 domainlabel name
; // used only if autoname is false
515 unsigned char txtinfo
[1024];
518 ServiceInstance
*regs
;
519 } DNSServiceRegistration
;
521 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
522 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
523 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
524 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
526 // We keep a list of client-supplied event sources in KQSocketEventSource records
527 typedef struct KQSocketEventSource
529 struct KQSocketEventSource
*next
;
532 } KQSocketEventSource
;
534 static KQSocketEventSource
*gEventSources
;
536 //*************************************************************************************************************
537 // General Utility Functions
539 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
541 char _malloc_options
[] = "AXZ";
543 mDNSexport
void LogMemCorruption(const char *format
, ...)
547 va_start(ptr
,format
);
548 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
550 LogMsg("!!!! %s !!!!", buffer
);
551 NotifyOfElusiveBug("Memory Corruption", buffer
);
553 *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
557 mDNSlocal
void validatelists(mDNS
*const m
)
560 KQSocketEventSource
*k
;
561 for (k
= gEventSources
; k
; k
=k
->next
)
562 if (k
->next
== (KQSocketEventSource
*)~0 || k
->fd
< 0)
563 LogMemCorruption("gEventSources: %p is garbage (%d)", k
, k
->fd
);
565 // Check Mach client lists
566 DNSServiceDomainEnumeration
*e
;
567 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
568 if (e
->next
== (DNSServiceDomainEnumeration
*)~0 || e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
569 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
571 DNSServiceBrowser
*b
;
572 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
573 if (b
->next
== (DNSServiceBrowser
*)~0 || b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
574 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
576 DNSServiceResolver
*l
;
577 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
578 if (l
->next
== (DNSServiceResolver
*)~0 || l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
579 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
581 DNSServiceRegistration
*r
;
582 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
583 if (r
->next
== (DNSServiceRegistration
*)~0 || r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
584 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
586 // Check Unix Domain Socket client lists (uds_daemon.c)
589 // Check core mDNS lists
591 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
593 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
594 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
595 if (rr
->resrec
.name
!= &rr
->namestorage
)
596 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
597 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
600 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
601 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
602 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
604 rr
= m
->NewLocalRecords
;
606 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
607 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
609 rr
= m
->CurrentRecord
;
611 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
612 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
615 for (q
= m
->Questions
; q
; q
=q
->next
)
616 if (q
->next
== (DNSQuestion
*)~0 || q
->ThisQInterval
== (mDNSs32
)~0)
617 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q
, q
->ThisQInterval
, q
->next
);
622 FORALL_CACHERECORDS(slot
, cg
, cr
)
624 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
625 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, cr
, cr
->resrec
.RecordType
);
626 if (cr
->CRActiveQuestion
)
628 for (q
= m
->Questions
; q
; q
=q
->next
) if (q
== cr
->CRActiveQuestion
) break;
629 if (!q
) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot
, cr
->CRActiveQuestion
, CRDisplayString(m
, cr
));
633 // Check core uDNS lists
634 udns_validatelists(m
);
636 // Check platform-layer lists
637 NetworkInterfaceInfoOSX
*i
;
638 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
639 if (i
->next
== (NetworkInterfaceInfoOSX
*)~0 || !i
->ifa_name
|| i
->ifa_name
== (char *)~0)
640 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i
, i
->ifa_name
);
643 for (t
= m
->TunnelClients
; t
; t
=t
->next
)
644 if (t
->next
== (ClientTunnel
*)~0 || t
->dstname
.c
[0] > 63)
645 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t
, t
->dstname
.c
[0]);
648 void *mallocL(char *msg
, unsigned int size
)
650 unsigned long *mem
= malloc(size
+8);
653 LogMsg("malloc( %s : %d ) failed", msg
, size
);
658 if (size
> 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg
, size
, &mem
[2]);
659 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
662 //mDNSPlatformMemZero(&mem[2], size);
663 memset(&mem
[2], 0xFF, size
);
664 validatelists(&mDNSStorage
);
669 void freeL(char *msg
, void *x
)
672 LogMsg("free( %s @ NULL )!", msg
);
675 unsigned long *mem
= ((unsigned long *)x
) - 2;
676 if (mem
[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
677 if (mem
[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg
, mem
[1], &mem
[2]);
678 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
679 //mDNSPlatformMemZero(mem, mem[1]+8);
680 memset(mem
, 0xFF, mem
[1]+8);
681 validatelists(&mDNSStorage
);
688 //*************************************************************************************************************
689 // Client Death Detection
691 // This gets called after ALL constituent records of the Service Record Set have been deregistered
692 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
694 ServiceRecordSet
*s
= &x
->srs
;
695 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
699 e
->r
.RecordContext
= e
;
702 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
705 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
706 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
708 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
709 freeL("ServiceInstance", x
);
712 // AbortClient finds whatever client is identified by the given Mach port,
713 // stops whatever operation that client was doing, and frees its memory.
714 // In the case of a service registration, the actual freeing may be deferred
715 // until we get the mStatus_MemFree message, if necessary
716 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
718 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
719 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
720 DNSServiceResolver
**l
= &DNSServiceResolverList
;
721 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
723 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
726 DNSServiceDomainEnumeration
*x
= *e
;
729 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
730 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
731 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
732 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
733 freeL("DNSServiceDomainEnumeration", x
);
737 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
740 DNSServiceBrowser
*x
= *b
;
741 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
746 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
747 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
748 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
751 freeL("DNSServiceBrowserQuestion", freePtr
);
755 DNSServiceBrowserResult
*t
= x
->results
;
756 x
->results
= x
->results
->next
;
757 freeL("DNSServiceBrowserResult", t
);
759 freeL("DNSServiceBrowser", x
);
763 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
766 DNSServiceResolver
*x
= *l
;
769 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
770 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
771 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
772 freeL("DNSServiceResolver", x
);
776 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
779 ServiceInstance
*si
= NULL
;
780 DNSServiceRegistration
*x
= *r
;
786 ServiceInstance
*instance
= si
;
788 instance
->renameonmemfree
= mDNSfalse
;
789 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
);
790 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
792 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
793 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
794 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
795 // the list, so we should go ahead and free the memory right now
796 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
799 freeL("DNSServiceRegistration", x
);
803 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
806 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
808 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
810 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
811 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
812 DNSServiceResolver
*l
= DNSServiceResolverList
;
813 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
814 DNSServiceBrowserQuestion
*qptr
;
816 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
817 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
818 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
819 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
821 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
824 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
825 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
827 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
831 for (si
= r
->regs
; si
; si
= si
->next
)
832 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
834 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
839 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
841 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
842 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
843 DNSServiceResolver
*l
= DNSServiceResolverList
;
844 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
845 DNSServiceBrowserQuestion
*qptr
;
847 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
848 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
849 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
850 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
851 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
854 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
855 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
857 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
858 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
859 return(e
|| b
|| l
|| r
);
862 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
864 KQueueLock(&mDNSStorage
);
865 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
866 (void)unusedport
; // Unused
867 (void)size
; // Unused
868 (void)info
; // Unused
869 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
871 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
872 AbortClient(deathMessage
->not_port
, NULL
);
874 /* Deallocate the send right that came in the dead name notification */
875 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
877 KQueueUnlock(&mDNSStorage
, "Mach AbortClient");
880 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
883 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
884 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
885 // If the port already died while we were thinking about it, then abort the operation right away
886 if (r
!= KERN_SUCCESS
)
887 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
890 //*************************************************************************************************************
891 // Domain Enumeration
893 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
895 kern_return_t status
;
896 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
897 DNSServiceDomainEnumerationReplyResultType rt
;
898 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
901 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
902 if (answer
->rrtype
!= kDNSType_PTR
) return;
903 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
907 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
908 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
912 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
916 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
917 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
918 !AddRecord
? "RemoveDomain" :
919 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
921 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
922 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
923 if (status
== MACH_SEND_TIMED_OUT
)
924 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
927 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
930 // Check client parameter
931 (void)unusedserver
; // Unused
932 mStatus err
= mStatus_NoError
;
933 const char *errormsg
= "Unknown";
934 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
935 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
937 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
938 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
940 // Allocate memory, and handle failure
941 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
942 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
944 // Set up object, and link into list
945 x
->ClientMachPort
= client
;
946 x
->next
= DNSServiceDomainEnumerationList
;
947 DNSServiceDomainEnumerationList
= x
;
949 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
952 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
953 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
954 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
956 // Succeeded: Wrap up and return
957 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
958 EnableDeathNotificationForClient(client
, x
);
959 return(mStatus_NoError
);
962 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
966 //*************************************************************************************************************
967 // Browse for services
969 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
973 if (answer
->rrtype
!= kDNSType_PTR
)
974 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
977 domainname type
, domain
;
978 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
980 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
981 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
985 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
986 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
988 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
989 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
991 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
992 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
995 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
996 DNSServiceBrowserResult
**p
= &browser
->results
;
997 while (*p
) p
= &(*p
)->next
;
1000 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1001 browser
->ClientMachPort
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
1004 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1006 mStatus err
= mStatus_NoError
;
1007 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1009 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1011 if (SameDomainName(&ptr
->q
.qname
, d
))
1012 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1015 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1016 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1017 AssignDomainName(&question
->domain
, d
);
1018 question
->next
= browser
->qlist
;
1019 browser
->qlist
= question
;
1020 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1021 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1022 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1026 mDNSexport
void machserver_automatic_browse_domain_changed(const domainname
*d
, mDNSBool add
)
1028 DNSServiceBrowser
*ptr
;
1029 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1031 if (ptr
->DefaultDomain
)
1035 mStatus err
= AddDomainToBrowser(ptr
, d
);
1036 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1040 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1043 if (SameDomainName(&(*q
)->domain
, d
))
1045 DNSServiceBrowserQuestion
*rem
= *q
;
1047 mDNS_StopQueryWithRemoves(&mDNSStorage
, &rem
->q
);
1048 freeL("DNSServiceBrowserQuestion", rem
);
1053 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1059 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1060 DNSCString regtype
, DNSCString domain
)
1062 // Check client parameter
1063 (void)unusedserver
; // Unused
1064 mStatus err
= mStatus_NoError
;
1065 const char *errormsg
= "Unknown";
1067 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1068 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1070 // Check other parameters
1073 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1074 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1075 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1076 { errormsg
= "Bad Service SubType"; goto badparam
; }
1077 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1079 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1080 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1082 // Allocate memory, and handle failure
1083 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1084 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1086 // Set up object, and link into list
1087 AssignDomainName(&x
->type
, &t
);
1088 x
->ClientMachPort
= client
;
1092 x
->next
= DNSServiceBrowserList
;
1093 DNSServiceBrowserList
= x
;
1097 // Start browser for an explicit domain
1098 x
->DefaultDomain
= mDNSfalse
;
1099 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1100 err
= AddDomainToBrowser(x
, &d
);
1101 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1105 DNameListElem
*sdPtr
;
1106 // Start browser on all domains
1107 x
->DefaultDomain
= mDNStrue
;
1108 if (!AutoBrowseDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1109 for (sdPtr
= AutoBrowseDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1111 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1114 // only terminally bail if .local fails
1115 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1116 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1117 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1122 // Succeeded: Wrap up and return
1123 EnableDeathNotificationForClient(client
, x
);
1124 return(mStatus_NoError
);
1127 err
= mStatus_BadParamErr
;
1129 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1133 //*************************************************************************************************************
1134 // Resolve Service Info
1136 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1138 kern_return_t status
;
1139 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1140 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1141 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1142 struct sockaddr_storage interface
;
1143 struct sockaddr_storage address
;
1145 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1148 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1150 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1152 mDNSPlatformMemZero(&interface
, sizeof(interface
));
1153 mDNSPlatformMemZero(&address
, sizeof(address
));
1155 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1157 struct sockaddr_in
*s
= (struct sockaddr_in
*)&interface
;
1158 s
->sin_len
= sizeof(*s
);
1159 s
->sin_family
= AF_INET
;
1161 s
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1163 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1165 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1166 sin6
->sin6_len
= sizeof(*sin6
);
1167 sin6
->sin6_family
= AF_INET6
;
1168 sin6
->sin6_flowinfo
= 0;
1169 sin6
->sin6_port
= 0;
1170 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1171 sin6
->sin6_scope_id
= ifx
->scope_id
;
1174 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1176 struct sockaddr_in
*s
= (struct sockaddr_in
*)&address
;
1177 s
->sin_len
= sizeof(*s
);
1178 s
->sin_family
= AF_INET
;
1179 s
->sin_port
= query
->info
->port
.NotAnInteger
;
1180 s
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1184 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1185 sin6
->sin6_len
= sizeof(*sin6
);
1186 sin6
->sin6_family
= AF_INET6
;
1187 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1188 sin6
->sin6_flowinfo
= 0;
1189 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1190 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1193 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1194 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1195 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1196 // ASCII-1 characters are used in the C-string as boundary markers,
1197 // to indicate the boundaries between the original constituent P-strings.
1198 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1201 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1205 pstrlen
= query
->info
->TXTinfo
[i
];
1208 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1210 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1211 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1212 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1213 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1214 if (status
== MACH_SEND_TIMED_OUT
)
1215 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1218 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1219 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1221 // Check client parameter
1222 (void)unusedserver
; // Unused
1223 mStatus err
= mStatus_NoError
;
1224 const char *errormsg
= "Unknown";
1225 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1226 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1228 // Check other parameters
1230 domainname t
, d
, srv
;
1231 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1232 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1233 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1234 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1236 // Allocate memory, and handle failure
1237 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1238 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1240 // Set up object, and link into list
1241 x
->ClientMachPort
= client
;
1242 x
->i
.InterfaceID
= mDNSInterface_Any
;
1244 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1245 x
->next
= DNSServiceResolverList
;
1246 DNSServiceResolverList
= x
;
1249 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1250 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1251 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1253 // Succeeded: Wrap up and return
1254 EnableDeathNotificationForClient(client
, x
);
1255 return(mStatus_NoError
);
1258 err
= mStatus_BadParamErr
;
1260 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1264 //*************************************************************************************************************
1267 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1269 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1272 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1274 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1276 if (result
== mStatus_NoError
)
1278 kern_return_t status
;
1279 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1280 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1281 if (status
== MACH_SEND_TIMED_OUT
)
1282 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1283 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1284 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1287 else if (result
== mStatus_NameConflict
)
1289 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1290 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1291 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1292 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1294 // On conflict for an autoname service, rename and reregister *all* autoname services
1295 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1296 m
->MainCallback(m
, mStatus_ConfigChanged
);
1298 else if (si
->autoname
)
1300 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1305 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1306 // of their registration in the usual way (which we will catch via client death notification).
1307 // If the Mach queue is full, we forcibly abort the client immediately.
1308 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1309 if (status
== MACH_SEND_TIMED_OUT
)
1310 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1314 else if (result
== mStatus_MemFree
)
1316 if (si
->renameonmemfree
) // We intentionally terminated registration so we could re-register with new name
1318 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1319 si
->renameonmemfree
= mDNSfalse
;
1320 si
->name
= m
->nicelabel
;
1321 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1325 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1326 DNSServiceRegistration
*r
;
1327 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1329 ServiceInstance
**sp
= &r
->regs
;
1332 if (*sp
== si
) { LogMsg("RegCallback: %##s Still in list; removing", srs
->RR_SRV
.resrec
.name
->c
); *sp
= (*sp
)->next
; break; }
1337 FreeServiceInstance(si
);
1341 else if (result
!= mStatus_NATTraversal
)
1342 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1345 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1348 ServiceInstance
*si
= NULL
;
1349 AuthRecord
*SubTypes
= NULL
;
1351 for (si
= x
->regs
; si
; si
= si
->next
)
1353 if (SameDomainName(&si
->domain
, domain
))
1354 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1357 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1358 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1360 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1361 if (!si
) return mStatus_NoMemoryErr
;
1363 si
->ClientMachPort
= x
->ClientMachPort
;
1364 si
->renameonmemfree
= mDNSfalse
;
1365 si
->autoname
= x
->autoname
;
1366 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1367 si
->domain
= *domain
;
1369 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
,
1370 x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1378 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1379 freeL("ServiceInstance", si
);
1384 mDNSexport
void machserver_automatic_registration_domain_changed(const domainname
*d
, mDNSBool add
)
1386 DNSServiceRegistration
*reg
;
1388 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1390 if (reg
->DefaultDomain
)
1393 AddServiceInstance(reg
, d
);
1396 ServiceInstance
**si
= ®
->regs
;
1399 if (SameDomainName(&(*si
)->domain
, d
))
1401 ServiceInstance
*s
= *si
;
1403 if (mDNS_DeregisterService(&mDNSStorage
, &s
->srs
)) FreeServiceInstance(s
); // only free memory synchronously on error
1408 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1414 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1415 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1417 (void)unusedserver
; // Unused
1418 mStatus err
= mStatus_NoError
;
1419 const char *errormsg
= "Unknown";
1421 // older versions of this code passed the port via mach IPC as an int.
1422 // we continue to pass it as 4 bytes to maintain binary compatibility,
1423 // but now ensure that the network byte order is preserved by using a struct
1425 port
.b
[0] = IpPort
.bytes
[2];
1426 port
.b
[1] = IpPort
.bytes
[3];
1428 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1429 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1431 // Check for sub-types after the service type
1432 size_t reglen
= strlen(regtype
) + 1;
1433 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1434 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1435 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1437 // Check other parameters
1441 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1442 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1443 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1444 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1445 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1447 unsigned char txtinfo
[1024] = "";
1448 unsigned int data_len
= 0;
1449 unsigned int size
= sizeof(RDataBody
);
1450 unsigned char *pstring
= &txtinfo
[data_len
];
1451 char *ptr
= txtRecord
;
1453 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1454 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1455 // Hence we have to convert the C-string to a P-string.
1456 // ASCII-1 characters are allowed in the C-string as boundary markers,
1457 // so that a single C-string can be used to represent one or more P-strings.
1460 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1461 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1463 pstring
= &txtinfo
[data_len
];
1469 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1470 pstring
[++pstring
[0]] = *ptr
++;
1475 if (size
< data_len
)
1478 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1479 // a port number of zero. When two instances of the protected client are allowed to run on one
1480 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1481 if (!mDNSIPPortIsZero(port
))
1483 int count
= CountExistingRegistrations(&srv
, port
);
1485 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1486 client
, count
+1, srv
.c
, mDNSVal16(port
));
1489 // Allocate memory, and handle failure
1490 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1491 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1492 mDNSPlatformMemZero(x
, sizeof(*x
));
1494 // Set up object, and link into list
1495 x
->ClientMachPort
= client
;
1496 x
->DefaultDomain
= !domain
[0];
1497 x
->autoname
= (!name
[0]);
1499 x
->NumSubTypes
= NumSubTypes
;
1500 memcpy(x
->regtype
, regtype
, reglen
);
1504 memcpy(x
->txtinfo
, txtinfo
, 1024);
1505 x
->txt_len
= data_len
;
1509 x
->next
= DNSServiceRegistrationList
;
1510 DNSServiceRegistrationList
= x
;
1512 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1513 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1515 err
= AddServiceInstance(x
, &d
);
1516 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1518 if (x
->DefaultDomain
)
1521 for (p
= AutoRegistrationDomains
; p
; p
= p
->next
)
1522 AddServiceInstance(x
, &p
->name
);
1525 // Succeeded: Wrap up and return
1526 EnableDeathNotificationForClient(client
, x
);
1527 return(mStatus_NoError
);
1530 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1532 err
= mStatus_BadParamErr
;
1534 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1535 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1539 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1542 if (result
== mStatus_NoError
)
1544 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
1545 LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1546 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1547 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1549 else if (result
== mStatus_NameConflict
)
1551 LogOperation("Local Hostname conflict for \"%#s.local\"", m
->hostlabel
.c
);
1552 if (!m
->p
->HostNameConflict
) m
->p
->HostNameConflict
= NonZeroTime(m
->timenow
);
1553 else if (m
->timenow
- m
->p
->HostNameConflict
> 60 * mDNSPlatformOneSecond
)
1555 // Tell the helper we've given up
1556 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, NULL
);
1559 else if (result
== mStatus_GrowCache
)
1561 // Allocate another chunk of cache storage
1562 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1563 //LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
1564 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1566 else if (result
== mStatus_ConfigChanged
)
1568 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
1569 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
1570 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
1572 // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
1573 DNSServiceRegistration
*r
;
1574 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1577 ServiceInstance
*si
;
1578 for (si
= r
->regs
; si
; si
= si
->next
)
1580 if (!SameDomainLabelCS(si
->name
.c
, m
->nicelabel
.c
))
1582 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1583 si
->renameonmemfree
= mDNStrue
;
1584 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1585 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1590 // Then we call into the UDS daemon code, to let it do the same
1591 udsserver_handle_configchange(m
);
1595 //*************************************************************************************************************
1596 // Add / Update / Remove records from existing Registration
1598 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1599 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1601 // Check client parameter
1603 mStatus err
= mStatus_NoError
;
1604 const char *errormsg
= "Unknown";
1605 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1606 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1607 ServiceInstance
*si
;
1609 (void)unusedserver
; // Unused
1610 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1611 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1613 // Check other parameters
1614 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1615 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1616 else size
= sizeof(RDataBody
);
1619 *reference
= (natural_t
)id
;
1620 for (si
= x
->regs
; si
; si
= si
->next
)
1622 // Allocate memory, and handle failure
1623 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1624 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1626 // Fill in type, length, and data of new record
1627 extra
->r
.resrec
.rrtype
= type
;
1628 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1629 extra
->r
.resrec
.rdlength
= data_len
;
1630 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1633 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1634 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1635 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1639 freeL("Extra Resource Record", extra
);
1640 errormsg
= "mDNS_AddRecordToService";
1644 extra
->ClientID
= id
;
1647 return mStatus_NoError
;
1650 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
? x
->name
.c
: (mDNSu8
*)"\x8""«NULL»", type
, data_len
, errormsg
, err
);
1651 return mStatus_UnknownErr
;
1654 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1657 if (OldRData
!= &rr
->rdatastorage
)
1658 freeL("Old RData", OldRData
);
1661 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1663 // Check client parameter
1664 mStatus err
= mStatus_NoError
;
1665 const char *errormsg
= "Unknown";
1666 const domainname
*name
= (const domainname
*)"";
1668 name
= srs
->RR_SRV
.resrec
.name
;
1670 unsigned int size
= sizeof(RDataBody
);
1671 if (size
< data_len
)
1674 // Allocate memory, and handle failure
1675 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1676 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1678 // Fill in new length, and data
1679 newrdata
->MaxRDLength
= size
;
1680 memcpy(&newrdata
->u
, data
, data_len
);
1682 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1683 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1684 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1685 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1688 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1689 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1691 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1694 errormsg
= "mDNS_Update";
1695 freeL("RData", newrdata
);
1698 return(mStatus_NoError
);
1701 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1705 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1706 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1708 // Check client parameter
1709 mStatus err
= mStatus_NoError
;
1710 const char *errormsg
= "Unknown";
1711 const domainname
*name
= (const domainname
*)"";
1712 ServiceInstance
*si
;
1714 (void)unusedserver
; // unused
1715 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1716 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1717 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1718 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1720 // Check other parameters
1721 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1723 for (si
= x
->regs
; si
; si
= si
->next
)
1725 AuthRecord
*r
= NULL
;
1727 // Find the record we're updating. NULL reference means update the primary TXT record
1728 if (!reference
) r
= &si
->srs
.RR_TXT
;
1731 ExtraResourceRecord
*ptr
;
1732 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1734 if ((natural_t
)ptr
->ClientID
== reference
)
1735 { r
= &ptr
->r
; break; }
1737 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1739 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1740 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1743 return mStatus_NoError
;
1746 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1750 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
1752 const domainname
*const name
= srs
->RR_SRV
.resrec
.name
;
1753 mStatus err
= mStatus_NoError
;
1756 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
1758 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
1759 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
1764 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1765 natural_t reference
)
1767 // Check client parameter
1768 (void)unusedserver
; // Unused
1769 mStatus err
= mStatus_NoError
;
1770 const char *errormsg
= "Unknown";
1771 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1772 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1773 ServiceInstance
*si
;
1775 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1776 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1778 for (si
= x
->regs
; si
; si
= si
->next
)
1780 ExtraResourceRecord
*e
;
1781 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
1783 if ((natural_t
)e
->ClientID
== reference
)
1785 err
= RemoveRecord(&si
->srs
, e
, client
);
1789 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
1792 return mStatus_NoError
;
1795 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
1799 //*************************************************************************************************************
1802 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1804 mig_reply_error_t
*request
= msg
;
1805 mig_reply_error_t
*reply
;
1806 mach_msg_return_t mr
;
1808 (void)port
; // Unused
1809 (void)size
; // Unused
1810 (void)info
; // Unused
1812 KQueueLock(&mDNSStorage
);
1814 /* allocate a reply buffer */
1815 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1817 /* call the MiG server routine */
1818 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1820 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1822 if (reply
->RetCode
== MIG_NO_REPLY
)
1825 * This return code is a little tricky -- it appears that the
1826 * demux routine found an error of some sort, but since that
1827 * error would not normally get returned either to the local
1828 * user or the remote one, we pretend it's ok.
1830 CFAllocatorDeallocate(NULL
, reply
);
1835 * destroy any out-of-line data in the request buffer but don't destroy
1836 * the reply port right (since we need that to send an error message).
1838 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
1839 mach_msg_destroy(&request
->Head
);
1842 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
1844 /* no reply port, so destroy the reply */
1845 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1846 mach_msg_destroy(&reply
->Head
);
1847 CFAllocatorDeallocate(NULL
, reply
);
1854 * We don't want to block indefinitely because the client
1855 * isn't receiving messages from the reply port.
1856 * If we have a send-once right for the reply port, then
1857 * this isn't a concern because the send won't block.
1858 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1859 * To avoid falling off the kernel's fast RPC path unnecessarily,
1860 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1863 options
= MACH_SEND_MSG
;
1864 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
1865 options
|= MACH_SEND_TIMEOUT
;
1867 mr
= mach_msg(&reply
->Head
, /* msg */
1868 options
, /* option */
1869 reply
->Head
.msgh_size
, /* send_size */
1871 MACH_PORT_NULL
, /* rcv_name */
1872 MACH_MSG_TIMEOUT_NONE
, /* timeout */
1873 MACH_PORT_NULL
); /* notify */
1875 /* Has a message error occurred? */
1878 case MACH_SEND_INVALID_DEST
:
1879 case MACH_SEND_TIMED_OUT
:
1880 /* the reply can't be delivered, so destroy it */
1881 mach_msg_destroy(&reply
->Head
);
1885 /* Includes success case. */
1889 CFAllocatorDeallocate(NULL
, reply
);
1892 KQueueUnlock(&mDNSStorage
, "Mach client event");
1895 mDNSlocal kern_return_t
registerBootstrapService()
1897 kern_return_t status
;
1898 mach_port_t service_send_port
, service_rcv_port
;
1900 debugf("Registering Bootstrap Service");
1903 * See if our service name is already registered and if we have privilege to check in.
1905 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1906 if (status
== KERN_SUCCESS
)
1909 * If so, we must be a followup instance of an already defined server. In that case,
1910 * the bootstrap port we inherited from our parent is the server's privilege port, so set
1911 * that in case we have to unregister later (which requires the privilege port).
1913 server_priv_port
= bootstrap_port
;
1914 restarting_via_mach_init
= TRUE
;
1916 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
1918 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
1919 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
1920 if (status
!= KERN_SUCCESS
) return status
;
1922 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
1923 if (status
!= KERN_SUCCESS
)
1925 mach_port_deallocate(mach_task_self(), server_priv_port
);
1929 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1930 if (status
!= KERN_SUCCESS
)
1932 mach_port_deallocate(mach_task_self(), server_priv_port
);
1933 mach_port_deallocate(mach_task_self(), service_send_port
);
1936 assert(service_send_port
== service_rcv_port
);
1940 * We have no intention of responding to requests on the service port. We are not otherwise
1941 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
1942 * So, we can dispose of all the rights we have for the service port. We don't destroy the
1943 * send right for the server's privileged bootstrap port - in case we have to unregister later.
1945 mach_port_destroy(mach_task_self(), service_rcv_port
);
1949 mDNSlocal kern_return_t
destroyBootstrapService()
1951 debugf("Destroying Bootstrap Service");
1952 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
1955 mDNSlocal
void ExitCallback(int sig
)
1957 (void)sig
; // Unused
1958 LogMsgIdent(mDNSResponderVersionString
, "stopping");
1960 debugf("ExitCallback");
1961 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
1962 destroyBootstrapService();
1964 debugf("ExitCallback: Aborting MIG clients");
1965 while (DNSServiceDomainEnumerationList
)
1966 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
1967 while (DNSServiceBrowserList
)
1968 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
1969 while (DNSServiceResolverList
)
1970 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
1971 while (DNSServiceRegistrationList
)
1972 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
1974 if (udsserver_exit(launchd_fd
) < 0) LogMsg("ExitCallback: udsserver_exit failed");
1976 debugf("ExitCallback: mDNS_StartExit");
1977 mDNS_StartExit(&mDNSStorage
);
1980 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
1981 mDNSlocal
void HandleSIG(int sig
)
1984 debugf("HandleSIG %d", sig
);
1985 mach_msg_header_t header
;
1986 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1987 header
.msgh_remote_port
= signal_port
;
1988 header
.msgh_local_port
= MACH_PORT_NULL
;
1989 header
.msgh_size
= sizeof(header
);
1990 header
.msgh_id
= sig
;
1991 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1993 LogMsg("HandleSIG %d: mach_msg_send failed", sig
);
1994 if (sig
== SIGTERM
|| sig
== SIGINT
) exit(-1);
1998 mDNSlocal
void CatchABRT(int sig
)
2000 LogMsg("Received SIGABRT %d", sig
);
2001 sleep(1); // Pause to make sure syslog gets the message
2002 while(1) *(long*)0 = 0; // Generate a CrashReporter stack trace so we can find out what library called abort();
2005 mDNSlocal
void INFOCallback(void)
2007 mDNSs32 utc
= mDNSPlatformUTC();
2008 DNSServiceDomainEnumeration
*e
;
2009 DNSServiceBrowser
*b
;
2010 DNSServiceResolver
*l
;
2011 DNSServiceRegistration
*r
;
2012 NetworkInterfaceInfoOSX
*i
;
2015 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2017 udsserver_info(&mDNSStorage
);
2019 LogMsgNoIdent("--------- Mach Clients ---------");
2020 if (!DNSServiceDomainEnumerationList
&& !DNSServiceBrowserList
&& !DNSServiceResolverList
&& !DNSServiceRegistrationList
)
2021 LogMsgNoIdent("<None>");
2024 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2025 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2027 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2029 DNSServiceBrowserQuestion
*qptr
;
2030 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2031 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2033 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2034 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2036 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2038 ServiceInstance
*si
;
2039 for (si
= r
->regs
; si
; si
= si
->next
)
2040 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
));
2044 LogMsgNoIdent("----- KQSocketEventSources -----");
2045 if (!gEventSources
) LogMsgNoIdent("<None>");
2048 KQSocketEventSource
*k
;
2049 for (k
= gEventSources
; k
; k
=k
->next
)
2050 LogMsgNoIdent("%3d %s", k
->fd
, k
->kqs
.KQtask
);
2053 LogMsgNoIdent("------ Network Interfaces ------");
2054 if (!mDNSStorage
.p
->InterfaceList
) LogMsgNoIdent("<None>");
2057 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2060 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds",
2061 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2062 &i
->ifinfo
.ip
, utc
- i
->LastSeen
);
2064 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a",
2065 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2066 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2067 i
->ifinfo
.IPv4Available
? "v4" : " ",
2068 i
->ifinfo
.IPv4Available
? (mDNSv4Addr
*)&i
->ifa_v4addr
: &zerov4Addr
,
2069 i
->ifinfo
.IPv6Available
? "v6" : " ",
2070 i
->ifinfo
.InterfaceID
,
2071 i
->ifinfo
.Advertise
? "Adv" : " ",
2072 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2077 LogMsgNoIdent("--------- DNS Servers ----------");
2078 if (!mDNSStorage
.DNSServers
) LogMsgNoIdent("<None>");
2081 for (s
= mDNSStorage
.DNSServers
; s
; s
= s
->next
)
2083 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)s
->interface
;
2084 LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
2085 s
->domain
.c
, ifx
? ifx
->ifa_name
: "", ifx
? " " : "", &s
->addr
, mDNSVal16(s
->port
),
2086 s
->teststate
== DNSServer_Untested
? "(Untested)" :
2087 s
->teststate
== DNSServer_Passed
? "" :
2088 s
->teststate
== DNSServer_Failed
? "(Failed)" :
2089 s
->teststate
== DNSServer_Disabled
? "(Disabled)" : "(Unknown state)");
2093 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
2094 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32
)now
, now
);
2096 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2099 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2101 (void)port
; // Unused
2102 (void)size
; // Unused
2103 (void)info
; // Unused
2104 mach_msg_header_t
*msg_header
= (mach_msg_header_t
*)msg
;
2105 mDNS
*const m
= &mDNSStorage
;
2107 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
2109 switch(msg_header
->msgh_id
)
2115 LogMsg("SIGHUP: Purge cache");
2116 FORALL_CACHERECORDS(slot
, cg
, rr
) mDNS_PurgeCacheResourceRecord(m
, rr
);
2119 case SIGTERM
: ExitCallback(msg_header
->msgh_id
); break;
2120 case SIGINFO
: INFOCallback(); break;
2121 case SIGUSR1
: // mDNSCoreMachineSleep(m, !m->SleepState); break;
2122 LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2123 mDNSMacOSXNetworkChanged(m
);
2125 // Simulate KeychainChanged
2127 SetDomainSecrets(m
);
2131 case SIGUSR2
: SigLogLevel(); break;
2132 default: LogMsg("SignalCallback: Unknown signal %d", msg_header
->msgh_id
); break;
2134 KQueueUnlock(m
, "Unix Signal");
2137 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2138 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2140 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2143 CFMachPortRef s_port
;
2145 // If launchd already created our Mach port for us, then use that, else we create a new one of our own
2146 if (m_port
!= MACH_PORT_NULL
)
2147 s_port
= CFMachPortCreateWithPort(NULL
, m_port
, DNSserverCallback
, NULL
, NULL
);
2150 s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2151 m_port
= CFMachPortGetPort(s_port
);
2152 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2153 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2158 LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
2160 LogMsg("bootstrap_register() failed: %s %d", mach_error_string(status
), status
);
2165 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2166 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2167 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2168 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2169 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2171 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2172 rrcachestorage
, RR_CACHE_SIZE
,
2173 mDNS_Init_AdvertiseLocalAddresses
,
2174 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2176 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2178 client_death_port
= CFMachPortGetPort(d_port
);
2179 signal_port
= CFMachPortGetPort(i_port
);
2181 CFRunLoop
= CFRunLoopGetCurrent();
2182 CFRunLoopAddSource(CFRunLoop
, d_rls
, kCFRunLoopDefaultMode
);
2183 CFRunLoopAddSource(CFRunLoop
, s_rls
, kCFRunLoopDefaultMode
);
2184 CFRunLoopAddSource(CFRunLoop
, i_rls
, kCFRunLoopDefaultMode
);
2188 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2192 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2194 mDNSs32 now
= mDNS_TimeNow(m
);
2196 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2198 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2199 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2200 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2201 // we then systematically lose our own looped-back packets.
2202 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2204 // KeyChain frequently fails to notify clients of change events. To work around this
2205 // we set a timer and periodically poll to detect if any changes have occurred.
2206 // Without this Back To My Mac just does't work for a large number of users.
2207 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
2208 if (m
->p
->KeyChainBugTimer
&& now
- m
->p
->KeyChainBugTimer
>= 0)
2210 m
->p
->KeyChainBugInterval
*= 2;
2211 m
->p
->KeyChainBugTimer
= NonZeroTime(now
+ m
->p
->KeyChainBugInterval
);
2212 if (m
->p
->KeyChainBugInterval
> 2 * mDNSPlatformOneSecond
) m
->p
->KeyChainBugTimer
= 0;
2214 SetDomainSecrets(m
);
2218 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2219 mDNSs32 nextevent
= mDNS_Execute(m
);
2221 if (m
->p
->NetworkChanged
)
2222 if (nextevent
- m
->p
->NetworkChanged
> 0)
2223 nextevent
= m
->p
->NetworkChanged
;
2225 if (m
->p
->KeyChainBugTimer
)
2226 if (nextevent
- m
->p
->KeyChainBugTimer
> 0)
2227 nextevent
= m
->p
->KeyChainBugTimer
;
2229 // 3. Deliver any waiting browse messages to clients
2230 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2234 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2235 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2236 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2237 DNSServiceBrowser
*x
= b
;
2239 if (x
->results
) // Try to deliver the list of results
2243 DNSServiceBrowserResult
*const r
= x
->results
;
2245 domainname type
, domain
;
2246 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2247 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2248 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2249 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2250 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2251 ConvertDomainNameToCString(&type
, ctype
);
2252 ConvertDomainNameToCString(&domain
, cdom
);
2253 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2254 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2255 // If we failed to send the mach message, try again in one second
2256 if (status
== MACH_SEND_TIMED_OUT
)
2258 if (nextevent
- now
> mDNSPlatformOneSecond
)
2259 nextevent
= now
+ mDNSPlatformOneSecond
;
2264 x
->lastsuccess
= now
;
2265 x
->results
= x
->results
->next
;
2266 freeL("DNSServiceBrowserResult", r
);
2269 // If this client hasn't read a single message in the last 60 seconds, abort it
2270 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2271 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2275 DNSServiceResolver
*l
;
2276 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2277 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2280 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2281 "This places considerable burden on the network.", l
->i
.name
.c
);
2284 if (m
->p
->NotifyUser
)
2286 if (m
->p
->NotifyUser
- now
< 0)
2288 if (!SameDomainLabelCS(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2290 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2291 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
2292 m
->p
->usernicelabel
= m
->nicelabel
;
2294 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2296 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2297 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
2298 m
->p
->HostNameConflict
= 0; // Clear our indicator, now name change has been successful
2299 m
->p
->userhostlabel
= m
->hostlabel
;
2301 m
->p
->NotifyUser
= 0;
2304 if (nextevent
- m
->p
->NotifyUser
> 0)
2305 nextevent
= m
->p
->NotifyUser
;
2311 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2315 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2317 // NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent
2319 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2320 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2321 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2322 if (m
->NewLocalOnlyQuestions
)
2323 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2324 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2325 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2326 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2327 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2328 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2329 #ifndef UNICAST_DISABLED
2330 if (m
->timenow
- m
->NextuDNSEvent
>= 0)
2331 LogMsg("Task Scheduling Error: NextuDNSEvent %d", m
->timenow
- m
->NextuDNSEvent
);
2333 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2334 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2335 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2336 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2337 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2338 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2339 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2340 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2341 if (m
->timenow
- m
->NextScheduledNATOp
>= 0)
2342 LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m
->timenow
- m
->NextScheduledNATOp
);
2344 mDNS_Unlock(&mDNSStorage
);
2347 mDNSlocal mDNSBool
ReadyForSleep(mDNS
*m
)
2351 // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server
2353 for (q
= m
->Questions
; q
; q
= q
->next
)
2354 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->ReqLease
== 0 && q
->tcp
) return(mDNSfalse
);
2356 // 2. Scan list of registered records
2358 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
2359 if (rr
->state
== regState_Refresh
&& rr
->tcp
) return(mDNSfalse
);
2361 // 2. Scan list of registered services
2362 ServiceRecordSet
*srs
;
2363 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
2364 if (srs
->state
== regState_NoTarget
&& srs
->tcp
) return(mDNSfalse
);
2369 mDNSlocal
void KQWokenFlushBytes(int fd
, __unused
short filter
, __unused
void *context
)
2371 // Read all of the bytes so we won't wake again.
2373 while (recv(fd
, buffer
, sizeof(buffer
), MSG_DONTWAIT
) > 0) continue;
2376 mDNSlocal
void * KQueueLoop(void *m_param
)
2381 #if USE_SELECT_WITH_KQUEUEFD
2384 const int multiplier
= 1000000 / mDNSPlatformOneSecond
;
2386 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
2389 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2390 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2392 // This is the main work loop:
2393 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2394 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2395 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2396 // (4) On wakeup we first process *all* events
2397 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2400 #define kEventsToReadAtOnce 1
2401 struct kevent new_events
[kEventsToReadAtOnce
];
2403 // Run mDNS_Execute to find out the time we next need to wake up
2404 mDNSs32 start
= mDNSPlatformRawTime();
2405 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
2406 mDNSs32 end
= mDNSPlatformRawTime();
2407 if (end
- start
>= WatchDogReportingThreshold
)
2408 LogOperation("WARNING: Idle task took %dms to complete", end
- start
);
2410 mDNSs32 now
= mDNS_TimeNow(m
);
2412 if (m
->ShutdownTime
)
2414 if (mDNS_ExitNow(m
, now
))
2416 LogOperation("mDNS_FinalExit");
2417 mDNS_FinalExit(&mDNSStorage
);
2418 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
2421 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
2422 nextTimerEvent
= m
->ShutdownTime
;
2425 if (m
->p
->SleepLimit
)
2427 mDNSBool ready
= ReadyForSleep(m
);
2428 if (ready
|| now
- m
->p
->SleepLimit
>= 0)
2430 LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m
->p
->SleepCookie
,
2431 ready
? "ready for sleep" : "giving up", now
, m
->p
->SleepLimit
- now
);
2432 m
->p
->SleepLimit
= 0;
2433 IOAllowPowerChange(m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2436 if (nextTimerEvent
- m
->p
->SleepLimit
>= 0)
2437 nextTimerEvent
= m
->p
->SleepLimit
;
2440 // Convert absolute wakeup time to a relative time from now
2441 mDNSs32 ticks
= nextTimerEvent
- now
;
2442 if (ticks
< 1) ticks
= 1;
2444 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2450 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2453 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2456 // Release the lock, and sleep until:
2457 // 1. Something interesting happens like a packet arriving, or
2458 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
2459 // 3. The timeout expires
2460 pthread_mutex_unlock(&PlatformStorage
.BigMutex
);
2462 #if USE_SELECT_WITH_KQUEUEFD
2463 struct timeval timeout
;
2464 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2465 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2466 FD_SET(KQueueFD
, &readfds
);
2467 if (select(KQueueFD
+1, &readfds
, NULL
, NULL
, &timeout
) < 0)
2468 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2470 struct timespec timeout
;
2471 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2472 timeout
.tv_nsec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2473 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
2474 // and have it work similarly to the way it does with nevents non-zero --
2475 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
2476 // In fact, what happens if you do this is that it just returns immediately. So, we have
2477 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
2478 if (kevent(KQueueFD
, NULL
, 0, new_events
, 1, &timeout
) < 0)
2479 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2482 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2483 // We have to ignore the event we may have been told about above, because that
2484 // was done without holding the lock, and between the time we woke up and the
2485 // time we reclaimed the lock the other thread could have done something that
2486 // makes the event no longer valid. Now we have the lock, we call kevent again
2487 // and this time we can safely process the events it tells us about.
2489 static const struct timespec zero_timeout
= { 0, 0 };
2491 while ((events_found
= kevent(KQueueFD
, NULL
, 0, new_events
, kEventsToReadAtOnce
, &zero_timeout
)) != 0)
2493 if (events_found
> kEventsToReadAtOnce
|| (events_found
< 0 && errno
!= EINTR
))
2495 // Not sure what to do here, our kqueue has failed us - this isn't ideal
2496 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno
, strerror(errno
));
2500 numevents
+= events_found
;
2503 for (i
= 0; i
< events_found
; i
++)
2505 const KQueueEntry
*const kqentry
= new_events
[i
].udata
;
2506 mDNSs32 stime
= mDNSPlatformRawTime();
2507 #if LogAllOperations || MDNS_DEBUGMSGS
2508 const char *const KQtask
= kqentry
->KQtask
; // Grab a copy in case KQcallback deletes the task
2510 kqentry
->KQcallback(new_events
[i
].ident
, new_events
[i
].filter
, kqentry
->KQcontext
);
2511 mDNSs32 etime
= mDNSPlatformRawTime();
2512 if (etime
- stime
>= WatchDogReportingThreshold
)
2513 LogOperation("WARNING: %s took %dms to complete", KQtask
, etime
- stime
);
2521 mDNSlocal
void LaunchdCheckin(void)
2523 launch_data_t msg
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
2524 launch_data_t resp
= launch_msg(msg
);
2525 launch_data_free(msg
);
2526 if (!resp
) { LogMsg("launch_msg returned NULL"); return; }
2528 if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
)
2530 int err
= launch_data_get_errno(resp
);
2531 // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
2532 if (err
!= EACCES
) LogMsg("launch_msg returned %d", err
);
2533 else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err
);
2537 launch_data_t skts
= launch_data_dict_lookup(resp
, LAUNCH_JOBKEY_SOCKETS
);
2538 if (!skts
) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
2541 launch_data_t skt
= launch_data_dict_lookup(skts
, "Listeners");
2542 if (!skt
) LogMsg("launch_data_dict_lookup Listeners returned NULL");
2545 launch_data_t s
= launch_data_array_get_index(skt
, 0);
2546 if (!s
) LogMsg("launch_data_array_get_index(skt, 0) returned NULL");
2549 launchd_fd
= launch_data_get_fd(s
);
2550 LogOperation("Launchd Unix Domain Socket: %d", launchd_fd
);
2551 // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
2552 chmod(MDNS_UDS_SERVERPATH
, S_IRUSR
|S_IWUSR
| S_IRGRP
|S_IWGRP
| S_IROTH
|S_IWOTH
);
2557 launch_data_t ports
= launch_data_dict_lookup(resp
, "MachServices");
2558 if (!ports
) LogMsg("launch_data_dict_lookup MachServices returned NULL");
2561 launch_data_t p
= launch_data_dict_lookup(ports
, "com.apple.mDNSResponder");
2562 if (!p
) LogOperation("launch_data_array_get_index(ports, 0) returned NULL");
2565 m_port
= launch_data_get_fd(p
);
2566 LogOperation("Launchd Mach Port: %d", m_port
);
2567 if (m_port
== ~0U) m_port
= MACH_PORT_NULL
;
2571 launch_data_free(resp
);
2574 mDNSlocal
void DropPrivileges(void)
2576 static const char login
[] = "_mdnsresponder";
2577 struct passwd
*pwd
= getpwnam(login
);
2579 LogMsg("Could not find account name \"%s\". Running as root.", login
);
2582 uid_t uid
= pwd
->pw_uid
;
2583 gid_t gid
= pwd
->pw_gid
;
2585 LogMsg("Started as root. Switching to userid \"%s\".", login
);
2587 if (unlink(MDNS_UDS_SERVERPATH
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, errno
, strerror(errno
));
2590 static char path
[] = "/var/run/mdns/mDNSResponder";
2591 char *p
= strrchr(path
, '/');
2593 if (mkdir(path
, 0755) < 0 && errno
!= EEXIST
) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2594 else if (chown(path
, uid
, gid
) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2598 if (unlink(path
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path
, errno
, strerror(errno
));
2599 else if (symlink(path
, MDNS_UDS_SERVERPATH
) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, path
, errno
, strerror(errno
));
2600 else LogOperation("DropPrivileges: Created subdirectory and symlink");
2604 if (0 != initgroups(login
, gid
)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login
, (unsigned long)gid
);
2605 if (0 != setgid(gid
)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
2606 if (0 != setuid(uid
)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid
);
2610 extern int sandbox_init(const char *profile
, uint64_t flags
, char **errorbuf
) __attribute__((weak_import
));
2612 mDNSexport
int main(int argc
, char **argv
)
2615 kern_return_t status
;
2616 pthread_t KQueueThread
;
2618 LogMsgIdent(mDNSResponderVersionString
, "starting");
2620 if (0 == geteuid()) DropPrivileges();
2622 for (i
=1; i
<argc
; i
++)
2624 if (!strcasecmp(argv
[i
], "-d" )) mDNS_DebugMode
= mDNStrue
;
2625 if (!strcasecmp(argv
[i
], "-launchd" )) started_via_launchdaemon
= mDNStrue
;
2626 if (!strcasecmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2629 signal(SIGHUP
, HandleSIG
); // (Debugging) Purge the cache to check for cache handling bugs
2630 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2631 signal(SIGABRT
, CatchABRT
); // For debugging -- SIGABRT should never happen
2632 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2633 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2634 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2635 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2636 signal(SIGUSR2
, HandleSIG
); // (Debugging) Change log level
2638 mDNSStorage
.p
= &PlatformStorage
; // Make sure mDNSStorage.p is set up, because validatelists uses it
2641 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2642 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2644 registerBootstrapService();
2645 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2646 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2647 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2650 // Avoid unnecessarily duplicating a file descriptor to itself
2651 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2652 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2653 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2654 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2658 // Create the kqueue, mutex and thread to support KQSockets
2659 KQueueFD
= kqueue();
2660 if (KQueueFD
== -1) { LogMsg("kqueue() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2662 i
= pthread_mutex_init(&PlatformStorage
.BigMutex
, NULL
);
2663 if (i
== -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2665 int fdpair
[2] = {0, 0};
2666 i
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
);
2667 if (i
== -1) { LogMsg("socketpair() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2669 // Socket pair returned us two identical sockets connected to each other
2670 // We will use the first socket to send the second socket. The second socket
2671 // will be added to the kqueue so it will wake when data is sent.
2672 static const KQueueEntry wakeKQEntry
= { KQWokenFlushBytes
, NULL
, "kqueue wakeup after CFRunLoop event" };
2673 PlatformStorage
.WakeKQueueLoopFD
= fdpair
[0];
2674 KQueueSet(fdpair
[1], EV_ADD
, EVFILT_READ
, &wakeKQEntry
);
2676 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
2678 LogMsg("Note: Compiled without Apple Sandbox support");
2681 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
2685 int sandbox_err
= sandbox_init("mDNSResponder", SANDBOX_NAMED
, &sandbox_msg
);
2686 if (sandbox_err
) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg
); sandbox_free_error(sandbox_msg
); }
2687 else LogOperation("Now running under Apple Sandbox restrictions");
2691 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2692 status
= mDNSDaemonInitialize();
2693 if (status
) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit
; }
2694 status
= udsserver_init(launchd_fd
);
2695 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2697 // Start the kqueue thread
2698 i
= pthread_create(&KQueueThread
, NULL
, KQueueLoop
, &mDNSStorage
);
2699 if (i
== -1) { LogMsg("pthread_create() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
2704 LogMsg("ERROR: CFRunLoopRun Exiting.");
2705 mDNS_Close(&mDNSStorage
);
2708 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2711 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2715 // uds_daemon.c support routines /////////////////////////////////////////////
2717 // Arrange things so that callback is called with context when data appears on fd
2718 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2720 KQSocketEventSource
*newSource
= (KQSocketEventSource
*) mallocL("KQSocketEventSource", sizeof *newSource
);
2721 if (!newSource
) return mStatus_NoMemoryErr
;
2723 mDNSPlatformMemZero(newSource
, sizeof(*newSource
));
2725 newSource
->kqs
.KQcallback
= callback
;
2726 newSource
->kqs
.KQcontext
= context
;
2727 newSource
->kqs
.KQtask
= "UDS client";
2729 if (KQueueSet(fd
, EV_ADD
, EVFILT_READ
, &newSource
->kqs
) == 0)
2731 KQSocketEventSource
**p
= &gEventSources
;
2732 while (*p
) p
= &(*p
)->next
;
2734 return mStatus_NoError
;
2740 return mStatus_NoMemoryErr
;
2744 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2746 KQSocketEventSource
**p
= &gEventSources
;
2747 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
2750 KQSocketEventSource
*s
= *p
;
2752 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
2753 // causes the kernel to automatically remove any associated kevents
2755 freeL("KQSocketEventSource", s
);
2756 return mStatus_NoError
;
2758 return mStatus_NoSuchNameErr
;
2761 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2762 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2763 asm(".desc ___crashreporter_info__, 0x10");
2765 // For convenience when using the "strings" command, this is the last thing in the file
2766 // The "@(#) " pattern is a special prefix the "what" command looks for
2767 mDNSexport
const char mDNSResponderVersionString_SCCS
[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";