2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
25 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
26 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
27 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
28 * therefore common sense dictates that if they are part of a compound statement then they
29 * should be indented to the same level as everything else in that compound statement.
30 * Indenting curly braces at the same level as the "if" implies that curly braces are
31 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
32 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
33 * understand why variable y is not of type "char*" just proves the point that poor code
34 * layout leads people to unfortunate misunderstandings about how the C language really works.)
36 Change History (most recent first):
39 Revision 1.227 2004/12/10 13:52:57 cheshire
40 <rdar://problem/3909995> Turn off SIGPIPE signals
42 Revision 1.226 2004/12/10 05:27:26 cheshire
43 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
45 Revision 1.225 2004/12/10 04:28:29 cheshire
46 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
48 Revision 1.224 2004/12/10 00:41:05 cheshire
49 Adjust alignment of log messages
51 Revision 1.223 2004/12/07 20:42:34 cheshire
52 Add explicit context parameter to mDNS_RemoveRecordFromService()
54 Revision 1.222 2004/12/06 21:15:23 ksekar
55 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
57 Revision 1.221 2004/11/30 03:24:04 cheshire
58 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
60 Revision 1.220 2004/11/29 23:34:31 cheshire
61 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
62 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
63 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
65 Revision 1.219 2004/11/25 01:00:56 cheshire
66 Checkin 1.217 not necessary
68 Revision 1.218 2004/11/24 20:27:19 cheshire
69 Add missing "err" parameter in LogMsg() call
71 Revision 1.217 2004/11/24 17:55:01 ksekar
72 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
74 Revision 1.216 2004/11/24 00:10:44 cheshire
75 <rdar://problem/3869241> For unicast operations, verify that service types are legal
77 Revision 1.215 2004/11/23 22:33:01 cheshire
78 <rdar://problem/3654910> Remove temporary workaround code for iChat
80 Revision 1.214 2004/11/23 22:13:59 cheshire
81 <rdar://problem/3886293> Subtype advertising broken for Mach API
83 Revision 1.213 2004/11/23 06:12:55 cheshire
84 <rdar://problem/3871405> Update wording for name conflict dialogs
86 Revision 1.212 2004/11/23 05:15:37 cheshire
87 <rdar://problem/3875830> Computer Name in use message garbled
89 Revision 1.211 2004/11/23 05:00:41 cheshire
90 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
92 Revision 1.210 2004/11/03 03:45:17 cheshire
93 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
95 Revision 1.209 2004/11/03 02:25:50 cheshire
96 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
98 Revision 1.208 2004/11/03 01:54:14 cheshire
99 Update debugging messages
101 Revision 1.207 2004/11/02 23:58:19 cheshire
102 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
104 Revision 1.206 2004/10/28 02:40:47 cheshire
105 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
107 Revision 1.205 2004/10/28 02:21:01 cheshire
108 <rdar://problem/3856500> Improve mDNSResponder signal handling
109 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
110 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
112 Revision 1.204 2004/10/27 01:57:21 cheshire
113 Add check of m->p->InterfaceList
115 Revision 1.203 2004/10/26 04:31:44 cheshire
116 Rename CountSubTypes() as ChopSubTypes()
118 Revision 1.202 2004/10/26 01:29:18 cheshire
119 Use "#if 0" instead of commenting out code
121 Revision 1.201 2004/10/25 21:41:39 ksekar
122 <rdar://problem/3852958> wide-area name conflicts can cause crash
124 Revision 1.200 2004/10/22 01:03:55 cheshire
125 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
126 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
128 Revision 1.199 2004/10/19 21:33:19 cheshire
129 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
130 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
131 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
133 Revision 1.198 2004/10/15 23:00:18 ksekar
134 <rdar://problem/3799242> Need to update LLQs on location changes
136 Revision 1.197 2004/10/12 23:38:59 ksekar
137 <rdar://problem/3837065> remove unnecessary log message
139 Revision 1.196 2004/10/04 05:56:04 cheshire
140 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
142 Revision 1.195 2004/09/30 00:24:59 ksekar
143 <rdar://problem/3695802> Dynamically update default registration domains on config change
145 Revision 1.194 2004/09/26 23:20:35 ksekar
146 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
148 Revision 1.193 2004/09/23 23:35:27 cheshire
151 Revision 1.192 2004/09/21 23:40:12 ksekar
152 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
154 Revision 1.191 2004/09/21 21:05:12 cheshire
155 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
156 into mDNSShared/uds_daemon.c
158 Revision 1.190 2004/09/21 19:51:15 cheshire
159 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
161 Revision 1.189 2004/09/21 18:17:23 cheshire
162 <rdar://problem/3785400> Add version info to mDNSResponder
164 Revision 1.188 2004/09/20 21:45:27 ksekar
167 Revision 1.187 2004/09/17 01:08:52 cheshire
168 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
169 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
170 declared in that file are ONLY appropriate to single-address-space embedded applications.
171 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
173 Revision 1.186 2004/09/16 00:24:49 cheshire
174 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
176 Revision 1.185 2004/08/25 02:01:45 cheshire
177 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
179 Revision 1.184 2004/08/19 19:04:12 ksekar
180 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
182 Revision 1.183 2004/08/14 03:22:42 cheshire
183 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
184 Add GetUserSpecifiedDDNSName() routine
185 Convert ServiceRegDomain to domainname instead of C string
186 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
188 Revision 1.182 2004/08/13 23:57:59 cheshire
189 Get rid of non-portable "_UNUSED"
191 Revision 1.181 2004/08/11 02:02:26 cheshire
192 Remove "mDNS *globalInstance" parameter from udsserver_init();
193 Move CheckForDuplicateRegistrations to uds_daemon.c
195 Revision 1.180 2004/07/13 21:24:25 rpantos
196 Fix for <rdar://problem/3701120>.
198 Revision 1.179 2004/06/19 00:02:54 cheshire
199 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
201 Revision 1.178 2004/06/18 19:10:00 cheshire
202 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
204 Revision 1.177 2004/06/16 23:14:46 ksekar
205 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
207 Revision 1.176 2004/06/11 20:27:42 cheshire
208 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
210 Revision 1.175 2004/06/10 20:23:21 cheshire
211 Also list interfaces in SIGINFO output
213 Revision 1.174 2004/06/08 18:54:48 ksekar
214 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
216 Revision 1.173 2004/06/08 17:35:12 cheshire
217 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
219 Revision 1.172 2004/06/05 00:04:26 cheshire
220 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
222 Revision 1.171 2004/06/04 08:58:30 ksekar
223 <rdar://problem/3668624>: Keychain integration for secure dynamic update
225 Revision 1.170 2004/05/30 20:01:50 ksekar
226 <rdar://problem/3668635>: wide-area default registrations should be in
227 .local too - fixed service registration when clients pass an explicit
228 domain (broken by previous checkin)
230 Revision 1.169 2004/05/30 01:30:16 ksekar
231 <rdar://problem/3668635>: wide-area default registrations should be in
234 Revision 1.168 2004/05/18 23:51:26 cheshire
235 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
237 Revision 1.167 2004/05/14 16:39:47 ksekar
238 Browse for iChat locally for now.
240 Revision 1.166 2004/05/13 21:33:52 ksekar
241 Clean up non-local registration control via config file. Force iChat
242 registrations to be local for now.
244 Revision 1.165 2004/05/13 04:54:20 ksekar
245 Unified list copy/free code. Added symetric list for
247 Revision 1.164 2004/05/12 22:03:08 ksekar
248 Made GetSearchDomainList a true platform-layer call (declaration moved
249 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
250 only on non-OSX platforms. Changed call to return a copy of the list
251 to avoid shared memory issues. Added a routine to free the list.
253 Revision 1.163 2004/05/12 02:03:25 ksekar
254 Non-local domains will only be browsed by default, and show up in
255 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
257 Revision 1.162 2004/04/14 23:09:29 ksekar
258 Support for TSIG signed dynamic updates.
260 Revision 1.161 2004/04/07 01:20:04 cheshire
261 Hash slot value should be unsigned
263 Revision 1.160 2004/04/06 19:51:24 cheshire
264 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
265 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
267 Revision 1.159 2004/04/03 01:36:55 cheshire
268 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
269 If "nobody" user doesn't exist, log a message and continue as "root"
271 Revision 1.158 2004/04/02 21:39:05 cheshire
272 Fix errors in comments
274 Revision 1.157 2004/03/19 18:49:10 ksekar
275 Increased size check in freeL() to account for LargeCacheRecord
276 structs larger than 8k
278 Revision 1.156 2004/03/19 18:19:19 ksekar
279 Fixed daemon.c to compile with malloc debugging turned on.
281 Revision 1.155 2004/03/13 01:57:34 ksekar
282 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
284 Revision 1.154 2004/03/12 08:42:47 cheshire
285 <rdar://problem/3548256>: Should not allow empty string for resolve domain
287 Revision 1.153 2004/03/12 08:08:51 cheshire
290 Revision 1.152 2004/02/05 19:39:29 cheshire
291 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
292 so that all platforms get this functionality
294 Revision 1.151 2004/02/03 22:35:34 cheshire
295 <rdar://problem/3548256>: Should not allow empty string for resolve domain
297 Revision 1.150 2004/01/28 21:14:23 cheshire
298 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
300 Revision 1.149 2004/01/28 02:30:08 ksekar
301 Added default Search Domains to unicast browsing, controlled via
302 Networking sharing prefs pane. Stopped sending unicast messages on
303 every interface. Fixed unicast resolving via mach-port API.
305 Revision 1.148 2004/01/25 00:03:20 cheshire
306 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
308 Revision 1.147 2004/01/19 19:51:46 cheshire
309 Fix compiler error (mixed declarations and code) on some versions of Linux
311 Revision 1.146 2003/12/08 21:00:46 rpantos
312 Changes to support mDNSResponder on Linux.
314 Revision 1.145 2003/12/05 22:08:07 cheshire
315 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
317 Revision 1.144 2003/11/19 23:21:08 ksekar
318 <rdar://problem/3486646>: config change handler not called for dns-sd services
320 Revision 1.143 2003/11/14 21:18:32 cheshire
321 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
322 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
324 Revision 1.142 2003/11/08 22:18:29 cheshire
325 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
327 Revision 1.141 2003/11/07 02:30:57 cheshire
328 Also check per-slot cache use counts in SIGINFO state log
330 Revision 1.140 2003/10/21 19:58:26 cheshire
331 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
333 Revision 1.139 2003/10/21 00:10:18 rpantos
334 <rdar://problem/3409401>: mDNSResponder should not run as root
336 Revision 1.138 2003/10/07 20:16:58 cheshire
337 Shorten syslog message a bit
339 Revision 1.137 2003/09/23 02:12:43 cheshire
340 Also include port number in list of services registered via new UDS API
342 Revision 1.136 2003/09/23 02:07:25 cheshire
343 Include port number in DNSServiceRegistration START/STOP messages
345 Revision 1.135 2003/09/23 01:34:02 cheshire
346 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
348 Revision 1.134 2003/08/21 20:01:37 cheshire
349 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
351 Revision 1.133 2003/08/20 23:39:31 cheshire
352 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
354 Revision 1.132 2003/08/20 01:44:56 cheshire
355 Fix errors in LogOperation() calls (only used for debugging)
357 Revision 1.131 2003/08/19 05:39:43 cheshire
358 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
360 Revision 1.130 2003/08/16 03:39:01 cheshire
361 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
363 Revision 1.129 2003/08/15 20:16:03 cheshire
364 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
365 We want to avoid touching the rdata pages, so we don't page them in.
366 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
367 Moved this from the RData to the ResourceRecord object.
368 2. To avoid unnecessarily touching the rdata just to compare it,
369 compute a hash of the rdata and store the hash in the ResourceRecord object.
371 Revision 1.128 2003/08/14 19:30:36 cheshire
372 <rdar://problem/3378473> Include list of cache records in SIGINFO output
374 Revision 1.127 2003/08/14 02:18:21 cheshire
375 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
377 Revision 1.126 2003/08/12 19:56:25 cheshire
380 Revision 1.125 2003/08/08 18:36:04 cheshire
381 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
383 Revision 1.124 2003/07/25 18:28:23 cheshire
384 Minor fix to error messages in syslog: Display string parameters with quotes
386 Revision 1.123 2003/07/23 17:45:28 cheshire
387 <rdar://problem/3339388> mDNSResponder leaks a bit
388 Don't allocate memory for the reply until after we've verified that the reply is valid
390 Revision 1.122 2003/07/23 00:00:04 cheshire
393 Revision 1.121 2003/07/20 03:38:51 ksekar
394 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
396 Revision 1.120 2003/07/18 00:30:00 cheshire
397 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
399 Revision 1.119 2003/07/17 19:08:58 cheshire
400 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
402 Revision 1.118 2003/07/15 21:12:28 cheshire
403 Added extra debugging checks in validatelists() (not used in final shipping version)
405 Revision 1.117 2003/07/15 01:55:15 cheshire
406 <rdar://problem/3315777> Need to implement service registration with subtypes
408 Revision 1.116 2003/07/02 21:19:51 cheshire
409 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
411 Revision 1.115 2003/07/02 02:41:24 cheshire
412 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
414 Revision 1.114 2003/07/01 21:10:20 cheshire
415 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
417 Revision 1.113 2003/06/28 17:27:43 vlubet
418 <rdar://problem/3221246> Redirect standard input, standard output, and
419 standard error file descriptors to /dev/null just like any other
422 Revision 1.112 2003/06/25 23:42:19 ksekar
423 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
424 Reviewed by: Stuart Cheshire
425 Added files necessary to implement Unix domain sockets based enhanced
426 DNS-SD APIs, and integrated with existing Mach-port based daemon.
428 Revision 1.111 2003/06/11 01:02:43 cheshire
429 <rdar://problem/3287858> mDNSResponder binary compatibility
430 Make single binary that can run on both Jaguar and Panther.
432 Revision 1.110 2003/06/10 01:14:11 cheshire
433 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
435 Revision 1.109 2003/06/06 19:53:43 cheshire
436 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
437 (Global search-and-replace; no functional change to code execution.)
439 Revision 1.108 2003/06/06 14:08:06 cheshire
440 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
442 Revision 1.107 2003/05/29 05:44:55 cheshire
443 Minor fixes to log messages
445 Revision 1.106 2003/05/27 18:30:55 cheshire
446 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
447 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
449 Revision 1.105 2003/05/26 03:21:29 cheshire
450 Tidy up address structure naming:
451 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
452 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
453 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
455 Revision 1.104 2003/05/26 00:42:06 cheshire
456 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
458 Revision 1.103 2003/05/23 23:07:44 cheshire
459 <rdar://problem/3268199> Must not write to stderr when running as daemon
461 Revision 1.102 2003/05/22 01:32:31 cheshire
462 Fix typo in Log message format string
464 Revision 1.101 2003/05/22 00:26:55 cheshire
465 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
466 Modify error message to explain that this is technically legal, but may indicate a bug.
468 Revision 1.100 2003/05/21 21:02:24 ksekar
469 <rdar://problem/3247035>: Service should be prefixed
470 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
471 Mach message port to "com.apple.mDNSResponder.
473 Revision 1.99 2003/05/21 17:33:49 cheshire
474 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
476 Revision 1.98 2003/05/20 00:33:07 cheshire
477 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
478 SIGHUP now writes state summary to syslog
480 Revision 1.97 2003/05/08 00:19:08 cheshire
481 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
483 Revision 1.96 2003/05/07 22:10:46 cheshire
484 <rdar://problem/3250330> Add a few more error logging messages
486 Revision 1.95 2003/05/07 19:20:17 cheshire
487 <rdar://problem/3251391> Add version number to mDNSResponder builds
489 Revision 1.94 2003/05/07 00:28:18 cheshire
490 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
492 Revision 1.93 2003/05/06 00:00:49 cheshire
493 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
495 Revision 1.92 2003/04/04 20:38:57 cheshire
500 #include <mach/mach.h>
501 #include <mach/mach_error.h>
502 #include <servers/bootstrap.h>
503 #include <sys/types.h>
508 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
510 #include "DNSServiceDiscoveryRequestServer.h"
511 #include "DNSServiceDiscoveryReply.h"
513 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
514 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
516 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
518 #include "GenLinkedList.h"
520 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
522 //*************************************************************************************************************
525 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
526 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
527 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
528 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
529 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
531 //*************************************************************************************************************
534 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
535 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
536 static mDNS_PlatformSupport PlatformStorage
;
537 #define RR_CACHE_SIZE 64
538 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
540 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
541 static mach_port_t client_death_port
= MACH_PORT_NULL
;
542 static mach_port_t signal_port
= MACH_PORT_NULL
;
543 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
545 // mDNS Mach Message Timeout, in milliseconds.
546 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
547 // fails to service its mach message queue, but long enough to give a well-written
548 // client a chance to service its mach message queue without getting cut off.
549 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
550 // even extra-slow clients a fair chance before we cut them off.
551 #define MDNS_MM_TIMEOUT 250
553 static int restarting_via_mach_init
= 0;
555 //*************************************************************************************************************
556 // Active client list structures
558 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
559 struct DNSServiceDomainEnumeration_struct
561 DNSServiceDomainEnumeration
*next
;
562 mach_port_t ClientMachPort
;
563 DNSQuestion dom
; // Question asking for domains
564 DNSQuestion def
; // Question asking for default domain
567 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
568 struct DNSServiceBrowserResult_struct
570 DNSServiceBrowserResult
*next
;
575 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
577 typedef struct DNSServiceBrowserQuestion
579 struct DNSServiceBrowserQuestion
*next
;
582 } DNSServiceBrowserQuestion
;
584 struct DNSServiceBrowser_struct
586 DNSServiceBrowser
*next
;
587 mach_port_t ClientMachPort
;
588 DNSServiceBrowserQuestion
*qlist
;
589 DNSServiceBrowserResult
*results
;
591 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
592 domainname type
; // registration type
595 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
596 struct DNSServiceResolver_struct
598 DNSServiceResolver
*next
;
599 mach_port_t ClientMachPort
;
605 // A single registered service: ServiceRecordSet + bookkeeping
606 // Note that we duplicate some fields from parent DNSServiceRegistration object
607 // to facilitate cleanup, when instances and parent may be deallocated at different times.
608 typedef struct ServiceInstance
610 struct ServiceInstance
*next
;
611 mach_port_t ClientMachPort
;
612 mDNSBool autoname
; // Set if this name is tied to the Computer Name
613 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
616 ServiceRecordSet srs
;
617 // Don't add any fields after ServiceRecordSet.
618 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
621 // A client-created service. May reference several ServiceInstance objects if default
622 // settings cause registration in multiple domains.
623 typedef struct DNSServiceRegistration
625 struct DNSServiceRegistration
*next
;
626 mach_port_t ClientMachPort
;
627 mDNSBool DefaultDomain
;
631 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
632 domainlabel name
; // used only if autoname is false
635 unsigned char txtinfo
[1024];
638 ServiceInstance
*regs
;
639 } DNSServiceRegistration
;
641 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
642 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
643 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
644 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
646 //*************************************************************************************************************
647 // General Utility Functions
649 #if MACOSX_MDNS_MALLOC_DEBUGGING
651 char _malloc_options
[] = "AXZ";
653 static void validatelists(mDNS
*const m
)
655 DNSServiceDomainEnumeration
*e
;
656 DNSServiceBrowser
*b
;
657 DNSServiceResolver
*l
;
658 DNSServiceRegistration
*r
;
663 NetworkInterfaceInfoOSX
*i
;
665 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
666 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
667 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
669 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
670 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
671 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
673 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
674 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
675 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
677 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
678 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
679 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
681 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
682 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
683 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
685 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
686 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
687 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
689 for (q
= m
->Questions
; q
; q
=q
->next
)
690 if (q
->ThisQInterval
== (mDNSs32
)~0)
691 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
693 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
694 for (cr
= m
->rrcache_hash
[slot
]; cr
; cr
=cr
->next
)
695 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
696 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
);
698 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
700 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i
);
703 void *mallocL(char *msg
, unsigned int size
)
705 unsigned long *mem
= malloc(size
+8);
708 LogMsg("malloc( %s : %d ) failed", msg
, size
);
713 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
716 //bzero(&mem[2], size);
717 memset(&mem
[2], 0xFF, size
);
718 validatelists(&mDNSStorage
);
723 void freeL(char *msg
, void *x
)
726 LogMsg("free( %s @ NULL )!", msg
);
729 unsigned long *mem
= ((unsigned long *)x
) - 2;
730 if (mem
[0] != 0xDEAD1234)
731 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
733 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
734 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
735 //bzero(mem, mem[1]+8);
736 memset(mem
, 0xFF, mem
[1]+8);
737 validatelists(&mDNSStorage
);
744 //*************************************************************************************************************
745 // Client Death Detection
747 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
749 ServiceRecordSet
*s
= &x
->srs
;
750 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
754 e
->r
.RecordContext
= e
;
757 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
760 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
761 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
763 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
764 freeL("ServiceInstance", x
);
767 // AbortClient finds whatever client is identified by the given Mach port,
768 // stops whatever operation that client was doing, and frees its memory.
769 // In the case of a service registration, the actual freeing may be deferred
770 // until we get the mStatus_MemFree message, if necessary
771 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
773 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
774 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
775 DNSServiceResolver
**l
= &DNSServiceResolverList
;
776 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
778 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
781 DNSServiceDomainEnumeration
*x
= *e
;
784 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
785 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
786 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
787 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
788 freeL("DNSServiceDomainEnumeration", x
);
792 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
795 DNSServiceBrowser
*x
= *b
;
796 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
801 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
802 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
803 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
806 freeL("DNSServiceBrowserQuestion", freePtr
);
810 DNSServiceBrowserResult
*r
= x
->results
;
811 x
->results
= x
->results
->next
;
812 freeL("DNSServiceBrowserResult", r
);
814 freeL("DNSServiceBrowser", x
);
818 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
821 DNSServiceResolver
*x
= *l
;
824 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
825 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
826 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
827 freeL("DNSServiceResolver", x
);
831 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
834 ServiceInstance
*si
= NULL
;
835 DNSServiceRegistration
*x
= *r
;
841 ServiceInstance
*instance
= si
;
843 instance
->autorename
= mDNSfalse
;
844 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
);
845 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
.c
, SRS_PORT(&instance
->srs
));
847 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
848 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
849 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
850 // the list, so we should go ahead and free the memory right now
851 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
854 freeL("DNSServiceRegistration", x
);
858 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
861 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
863 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
865 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
866 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
867 DNSServiceResolver
*l
= DNSServiceResolverList
;
868 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
869 DNSServiceBrowserQuestion
*qptr
;
871 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
872 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
873 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
874 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
875 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
878 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
879 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
881 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
885 for (si
= r
->regs
; si
; si
= si
->next
) LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
.c
, reason
, msg
);
887 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
892 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
894 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
895 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
896 DNSServiceResolver
*l
= DNSServiceResolverList
;
897 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
898 DNSServiceBrowserQuestion
*qptr
;
900 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
901 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
902 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
903 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
904 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
907 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
908 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
910 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
911 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
.c
: NULL
);
912 return(e
|| b
|| l
|| r
);
915 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
917 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
918 (void)unusedport
; // Unused
919 (void)size
; // Unused
920 (void)info
; // Unused
921 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
923 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
924 AbortClient(deathMessage
->not_port
, NULL
);
926 /* Deallocate the send right that came in the dead name notification */
927 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
931 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
934 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
935 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
936 // If the port already died while we were thinking about it, then abort the operation right away
937 if (r
!= KERN_SUCCESS
)
938 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
941 //*************************************************************************************************************
942 // Domain Enumeration
944 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
946 kern_return_t status
;
948 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
949 DNSServiceDomainEnumerationReplyResultType rt
;
950 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
952 debugf("FoundDomain: %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
953 if (answer
->rrtype
!= kDNSType_PTR
) return;
954 if (!x
) { debugf("FoundDomain: DNSServiceDomainEnumeration is NULL"); return; }
958 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
959 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
963 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
967 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
968 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
969 !AddRecord
? "RemoveDomain" :
970 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
972 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
973 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
974 if (status
== MACH_SEND_TIMED_OUT
)
975 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
978 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
981 // Check client parameter
982 (void)unusedserver
; // Unused
983 mStatus err
= mStatus_NoError
;
984 const char *errormsg
= "Unknown";
985 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
986 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
988 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
989 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
990 const DNSServiceDomainEnumerationReplyResultType rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
992 // Allocate memory, and handle failure
993 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
994 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
996 // Set up object, and link into list
997 x
->ClientMachPort
= client
;
998 x
->next
= DNSServiceDomainEnumerationList
;
999 DNSServiceDomainEnumerationList
= x
;
1001 // Generate initial response
1002 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1003 // We always give local. as the initial default browse domain, and then look for more
1004 kern_return_t status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, "local.", 0, MDNS_MM_TIMEOUT
);
1005 if (status
== MACH_SEND_TIMED_OUT
)
1006 { AbortBlockedClient(x
->ClientMachPort
, "local enumeration", x
); return(mStatus_UnknownErr
); }
1009 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, FoundDomain
, x
);
1010 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, FoundDomain
, x
);
1011 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1013 // Succeeded: Wrap up and return
1014 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1015 EnableDeathNotificationForClient(client
, x
);
1016 return(mStatus_NoError
);
1019 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1023 //*************************************************************************************************************
1024 // Browse for services
1026 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1030 if (answer
->rrtype
!= kDNSType_PTR
)
1031 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1034 domainname type
, domain
;
1035 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1037 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1038 answer
->name
.c
, answer
->rdata
->u
.name
.c
);
1042 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1043 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1045 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1046 AssignDomainName(x
->result
, answer
->rdata
->u
.name
);
1048 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1049 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1052 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1053 DNSServiceBrowserResult
**p
= &browser
->results
;
1054 while (*p
) p
= &(*p
)->next
;
1058 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1060 mStatus err
= mStatus_NoError
;
1061 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1063 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1065 if (SameDomainName(&ptr
->q
.qname
, d
))
1066 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1069 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1070 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1071 AssignDomainName(question
->domain
, *d
);
1072 question
->next
= browser
->qlist
;
1073 browser
->qlist
= question
;
1074 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1075 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1076 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1080 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1082 DNSServiceBrowser
*ptr
;
1084 debugf("%s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1085 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1087 if (ptr
->DefaultDomain
)
1091 mStatus err
= AddDomainToBrowser(ptr
, d
);
1092 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1098 * By cancelling the browse immediately, we may lose remove events.
1099 * Instead, we allow the browse to run. If our previous results are no longer valid (e.g. because we
1100 * moved out from behind a firewall) we will get remove events for those names.
1102 // find the question for this domain
1103 DNSServiceBrowserQuestion
*q
= ptr
->qlist
, *prev
= NULL
;
1106 if (SameDomainName(&q
->domain
, d
))
1108 if (prev
) prev
->next
= q
->next
;
1109 else ptr
->qlist
= q
->next
;
1110 mDNS_StopBrowse(&mDNSStorage
, &q
->q
);
1111 freeL("DNSServiceBrowserQuestion", q
);
1117 if (!q
) LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1124 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1125 DNSCString regtype
, DNSCString domain
)
1127 // Check client parameter
1128 (void)unusedserver
; // Unused
1129 mStatus err
= mStatus_NoError
;
1130 const char *errormsg
= "Unknown";
1131 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1133 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1134 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1136 // Check other parameters
1139 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1140 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1141 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1142 { errormsg
= "Bad Service SubType"; goto badparam
; }
1143 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1145 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1146 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1148 // Allocate memory, and handle failure
1149 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1150 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1152 // Set up object, and link into list
1153 AssignDomainName(x
->type
, t
);
1154 x
->ClientMachPort
= client
;
1158 x
->next
= DNSServiceBrowserList
;
1159 DNSServiceBrowserList
= x
;
1163 // Start browser for an explicit domain
1164 x
->DefaultDomain
= mDNSfalse
;
1165 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1166 err
= AddDomainToBrowser(x
, &d
);
1167 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1171 // Start browser on all domains
1172 x
->DefaultDomain
= mDNStrue
;
1173 SearchDomains
= mDNSPlatformGetSearchDomainList();
1174 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1175 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1177 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1180 // only terminally bail if .local fails
1181 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1182 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1183 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1188 // Succeeded: Wrap up and return
1189 EnableDeathNotificationForClient(client
, x
);
1190 mDNS_FreeDNameList(SearchDomains
);
1191 return(mStatus_NoError
);
1194 err
= mStatus_BadParamErr
;
1196 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1197 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1201 //*************************************************************************************************************
1202 // Resolve Service Info
1204 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1206 kern_return_t status
;
1207 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1208 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1209 if (query
->info
->InterfaceID
== (mDNSInterfaceID
)~0) ifx
= mDNSNULL
;
1210 struct sockaddr_storage interface
;
1211 struct sockaddr_storage address
;
1213 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1216 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1218 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1220 bzero(&interface
, sizeof(interface
));
1221 bzero(&address
, sizeof(address
));
1223 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1225 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1226 sin
->sin_len
= sizeof(*sin
);
1227 sin
->sin_family
= AF_INET
;
1229 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1231 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1233 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1234 sin6
->sin6_len
= sizeof(*sin6
);
1235 sin6
->sin6_family
= AF_INET6
;
1236 sin6
->sin6_flowinfo
= 0;
1237 sin6
->sin6_port
= 0;
1238 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1239 sin6
->sin6_scope_id
= ifx
->scope_id
;
1242 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1244 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1245 sin
->sin_len
= sizeof(*sin
);
1246 sin
->sin_family
= AF_INET
;
1247 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1248 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1252 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1253 sin6
->sin6_len
= sizeof(*sin6
);
1254 sin6
->sin6_family
= AF_INET6
;
1255 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1256 sin6
->sin6_flowinfo
= 0;
1257 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1258 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1261 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1262 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1263 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1264 // ASCII-1 characters are used in the C-string as boundary markers,
1265 // to indicate the boundaries between the original constituent P-strings.
1266 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1269 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1273 pstrlen
= query
->info
->TXTinfo
[i
];
1276 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1278 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1279 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1280 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1281 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1282 if (status
== MACH_SEND_TIMED_OUT
)
1283 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1286 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1287 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1289 // Check client parameter
1290 (void)unusedserver
; // Unused
1291 mStatus err
= mStatus_NoError
;
1292 const char *errormsg
= "Unknown";
1293 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1294 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1296 // Check other parameters
1298 domainname t
, d
, srv
;
1299 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1300 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1301 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1302 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1304 // Allocate memory, and handle failure
1305 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1306 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1308 // Set up object, and link into list
1309 x
->ClientMachPort
= client
;
1310 x
->i
.InterfaceID
= mDNSInterface_Any
;
1312 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1313 x
->next
= DNSServiceResolverList
;
1314 DNSServiceResolverList
= x
;
1317 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
1318 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1319 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1321 // Succeeded: Wrap up and return
1322 EnableDeathNotificationForClient(client
, x
);
1323 return(mStatus_NoError
);
1326 err
= mStatus_BadParamErr
;
1328 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1332 //*************************************************************************************************************
1335 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1337 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1340 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1342 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1344 if (result
== mStatus_NoError
)
1346 kern_return_t status
;
1347 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(srs
));
1348 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1349 if (status
== MACH_SEND_TIMED_OUT
)
1350 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1351 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1352 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1355 else if (result
== mStatus_NameConflict
)
1357 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(srs
));
1358 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1359 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1360 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1362 // On conflict for an autoname service, rename and reregister *all* autoname services
1363 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1364 m
->MainCallback(m
, mStatus_ConfigChanged
);
1366 else if (si
->autoname
)
1368 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1373 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1374 // of their registration in the usual way (which we will catch via client death notification).
1375 // If the Mach queue is full, we forcibly abort the client immediately.
1376 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1377 if (status
== MACH_SEND_TIMED_OUT
)
1378 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1382 else if (result
== mStatus_MemFree
)
1386 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1387 si
->autorename
= mDNSfalse
;
1388 si
->name
= m
->nicelabel
;
1389 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1393 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1394 DNSServiceRegistration
*r
;
1395 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1397 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1402 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
.c
);
1403 if (prev
) prev
->next
= sp
->next
;
1404 else r
->regs
= sp
->next
;
1412 FreeServiceInstance(si
);
1416 else if (result
!= mStatus_NATTraversal
)
1417 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(srs
), result
);
1420 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1423 ServiceInstance
*si
= NULL
;
1424 AuthRecord
*SubTypes
= NULL
;
1426 for (si
= x
->regs
; si
; si
= si
->next
)
1428 if (SameDomainName(&si
->domain
, domain
))
1429 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1432 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1433 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1435 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1436 if (!si
) return mStatus_NoMemoryErr
;
1438 si
->ClientMachPort
= x
->ClientMachPort
;
1439 si
->autorename
= mDNSfalse
;
1440 si
->autoname
= x
->autoname
;
1441 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1442 si
->domain
= *domain
;
1444 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
, x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1452 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1453 freeL("ServiceInstance", si
);
1458 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1460 DNSServiceRegistration
*reg
;
1462 LogMsg("%s default registration domain %##s", add
? "Adding" : "Removing", d
->c
);
1463 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1465 if (reg
->DefaultDomain
)
1469 AddServiceInstance(reg
, d
);
1473 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1476 if (SameDomainName(&si
->domain
, d
))
1478 if (prev
) prev
->next
= si
->next
;
1479 else reg
->regs
= si
->next
;
1480 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1481 FreeServiceInstance(si
); // only free memory synchronously on error
1487 if (!si
) LogMsg("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
);
1493 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1494 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1496 (void)unusedserver
; // Unused
1497 mStatus err
= mStatus_NoError
;
1498 const char *errormsg
= "Unknown";
1500 // older versions of this code passed the port via mach IPC as an int.
1501 // we continue to pass it as 4 bytes to maintain binary compatibility,
1502 // but now ensure that the network byte order is preserved by using a struct
1504 port
.b
[0] = IpPort
.bytes
[2];
1505 port
.b
[1] = IpPort
.bytes
[3];
1507 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1508 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1510 // Check for sub-types after the service type
1511 size_t reglen
= strlen(regtype
) + 1;
1512 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1513 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1514 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1516 // Check other parameters
1520 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1521 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1522 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1523 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1524 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1526 unsigned char txtinfo
[1024] = "";
1527 unsigned int data_len
= 0;
1528 unsigned int size
= sizeof(RDataBody
);
1529 unsigned char *pstring
= &txtinfo
[data_len
];
1530 char *ptr
= txtRecord
;
1532 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1533 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1534 // Hence we have to convert the C-string to a P-string.
1535 // ASCII-1 characters are allowed in the C-string as boundary markers,
1536 // so that a single C-string can be used to represent one or more P-strings.
1539 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1540 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1542 pstring
= &txtinfo
[data_len
];
1548 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1549 pstring
[++pstring
[0]] = *ptr
++;
1554 if (size
< data_len
)
1557 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1558 // a port number of zero. When two instances of the protected client are allowed to run on one
1559 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1560 if (port
.NotAnInteger
)
1562 int count
= CountExistingRegistrations(&srv
, port
);
1564 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1565 client
, count
+1, srv
.c
, mDNSVal16(port
));
1568 // Allocate memory, and handle failure
1569 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1570 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1571 bzero(x
, sizeof(*x
));
1573 // Set up object, and link into list
1574 x
->ClientMachPort
= client
;
1575 x
->DefaultDomain
= !domain
[0];
1576 x
->autoname
= (!name
[0]);
1578 x
->NumSubTypes
= NumSubTypes
;
1579 memcpy(x
->regtype
, regtype
, reglen
);
1583 memcpy(x
->txtinfo
, txtinfo
, 1024);
1584 x
->txt_len
= data_len
;
1588 x
->next
= DNSServiceRegistrationList
;
1589 DNSServiceRegistrationList
= x
;
1591 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1592 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1594 err
= AddServiceInstance(x
, &d
);
1595 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1597 if (x
->DefaultDomain
)
1599 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1600 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1601 AddServiceInstance(x
, &ptr
->name
);
1602 mDNS_FreeDNameList(regdomains
);
1605 // Succeeded: Wrap up and return
1606 EnableDeathNotificationForClient(client
, x
);
1607 return(mStatus_NoError
);
1610 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1612 err
= mStatus_BadParamErr
;
1614 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1615 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1619 // This updates either the text of the field currently labelled "Local Hostname",
1620 // or the text of the field currently labelled "Computer Name"
1621 // in the Sharing Prefs Control Panel
1622 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, domainlabel
*n1
, domainlabel
*n2
, char *msg
, char *suffix
, CFStringRef subtext
)
1624 char oldname
[MAX_DOMAIN_LABEL
+1];
1625 char newname
[MAX_DOMAIN_LABEL
+1];
1626 ConvertDomainLabelToCString_unescaped(n1
, oldname
);
1627 ConvertDomainLabelToCString_unescaped(n2
, newname
);
1628 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1629 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1630 const CFStringRef f1
= CFStringCreateWithCString(NULL
, "“%@%s”", kCFStringEncodingUTF8
);
1631 const CFStringRef f2
= CFStringCreateWithCString(NULL
, "“%@%s”", kCFStringEncodingUTF8
);
1632 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1634 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1635 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1638 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1639 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1640 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1641 // const CFMutableArrayRef alertMessage = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1642 const CFMutableStringRef alertMessage
= CFStringCreateMutable(NULL
, 0);
1644 if (n2
== &m
->hostlabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1645 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1646 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertMessage
)
1647 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1648 else if (m
->p
->NotifyUser
)
1650 // CFArrayAppendValue(alertMessage, s0);
1651 CFStringAppend(alertMessage
, s0
);
1652 CFStringAppend(alertMessage
, s1
);
1653 CFStringAppend(alertMessage
, CFSTR(" is already in use on this network. The name has been changed to "));
1654 CFStringAppend(alertMessage
, s2
);
1655 CFStringAppend(alertMessage
, CFSTR(" automatically."));
1656 CFUserNotificationDisplayNotice(60.0, // Auto-dismiss after 60 seconds
1657 kCFUserNotificationCautionAlertLevel
,
1658 NULL
, NULL
, NULL
, // iconURL, soundURL, localizationURL
1659 (CFStringRef
)alertMessage
, subtext
, NULL
); // alertHeader, alertMessage, defaultButtonTitle
1661 if (s0
) CFRelease(s0
);
1662 if (s1
) CFRelease(s1
);
1663 if (s2
) CFRelease(s2
);
1664 if (alertMessage
) CFRelease(alertMessage
);
1665 SCPreferencesUnlock(session
);
1667 if (cfoldname
) CFRelease(cfoldname
);
1668 if (cfnewname
) CFRelease(cfnewname
);
1669 if (f1
) CFRelease(f1
);
1670 if (f2
) CFRelease(f2
);
1671 if (session
) CFRelease(session
);
1674 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1677 if (result
== mStatus_NoError
)
1679 // Allow three seconds in case we get a Computer Name update too -- don't want to alert the user twice
1680 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
*3);
1682 else if (result
== mStatus_ConfigChanged
)
1684 DNSServiceRegistration
*r
;
1685 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1688 ServiceInstance
*si
;
1689 for (si
= r
->regs
; si
; si
= si
->next
)
1691 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1693 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
.c
, m
->nicelabel
.c
);
1694 si
->autorename
= mDNStrue
;
1695 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1696 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1700 udsserver_handle_configchange();
1702 else if (result
== mStatus_GrowCache
)
1704 // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
1705 mDNSu32 numrecords
= m
->rrcache_size
;
1706 CacheRecord
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheRecord
) * numrecords
);
1707 if (storage
) mDNS_GrowCache(m
, storage
, numrecords
);
1711 //*************************************************************************************************************
1712 // Add / Update / Remove records from existing Registration
1714 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1715 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1717 // Check client parameter
1719 mStatus err
= mStatus_NoError
;
1720 const char *errormsg
= "Unknown";
1721 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1722 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1723 ServiceInstance
*si
;
1725 (void)unusedserver
; // Unused
1726 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1727 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1729 // Check other parameters
1730 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1731 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1732 else size
= sizeof(RDataBody
);
1735 *reference
= (natural_t
)id
;
1736 for (si
= x
->regs
; si
; si
= si
->next
)
1738 // Allocate memory, and handle failure
1739 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1740 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1742 // Fill in type, length, and data of new record
1743 extra
->r
.resrec
.rrtype
= type
;
1744 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1745 extra
->r
.resrec
.rdlength
= data_len
;
1746 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1749 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1750 client
, si
->srs
.RR_SRV
.resrec
.name
.c
, type
, data_len
, extra
);
1751 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1755 freeL("Extra Resource Record", extra
);
1756 errormsg
= "mDNS_AddRecordToService";
1760 extra
->ClientID
= id
;
1763 return mStatus_NoError
;
1766 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1767 return mStatus_UnknownErr
;
1770 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1773 if (OldRData
!= &rr
->rdatastorage
)
1774 freeL("Old RData", OldRData
);
1777 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1779 // Check client parameter
1780 mStatus err
= mStatus_NoError
;
1781 const char *errormsg
= "Unknown";
1782 domainname
*name
= (domainname
*)"";
1784 name
= &srs
->RR_SRV
.resrec
.name
;
1786 unsigned int size
= sizeof(RDataBody
);
1787 if (size
< data_len
)
1790 // Allocate memory, and handle failure
1791 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1792 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1794 // Fill in new length, and data
1795 newrdata
->MaxRDLength
= size
;
1796 memcpy(&newrdata
->u
, data
, data_len
);
1799 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1800 client
, srs
->RR_SRV
.resrec
.name
.c
, data_len
);
1802 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1805 errormsg
= "mDNS_Update";
1806 freeL("RData", newrdata
);
1809 return(mStatus_NoError
);
1812 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1816 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1817 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1819 // Check client parameter
1820 mStatus err
= mStatus_NoError
;
1821 const char *errormsg
= "Unknown";
1822 domainname
*name
= (domainname
*)"";
1823 ServiceInstance
*si
;
1825 (void)unusedserver
; // unused
1826 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1827 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1828 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1829 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1831 // Check other parameters
1832 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1834 for (si
= x
->regs
; si
; si
= si
->next
)
1836 AuthRecord
*r
= NULL
;
1838 // Find the record we're updating. NULL reference means update the primary TXT record
1839 if (!reference
) r
= &si
->srs
.RR_TXT
;
1842 ExtraResourceRecord
*ptr
;
1843 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1845 if ((natural_t
)ptr
->ClientID
== reference
)
1846 { r
= &ptr
->r
; break; }
1848 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1850 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1851 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1854 return mStatus_NoError
;
1857 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1861 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
1863 domainname
*name
= &srs
->RR_SRV
.resrec
.name
;
1864 mStatus err
= mStatus_NoError
;
1867 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
.c
);
1869 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
1870 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
1875 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1876 natural_t reference
)
1878 // Check client parameter
1879 (void)unusedserver
; // Unused
1880 mStatus err
= mStatus_NoError
;
1881 const char *errormsg
= "Unknown";
1882 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1883 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1884 ServiceInstance
*si
;
1886 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1887 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1889 for (si
= x
->regs
; si
; si
= si
->next
)
1891 ExtraResourceRecord
*e
;
1892 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
1894 if ((natural_t
)e
->ClientID
== reference
)
1896 err
= RemoveRecord(&si
->srs
, e
, client
);
1900 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
1903 return mStatus_NoError
;
1906 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
1910 //*************************************************************************************************************
1913 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1915 mig_reply_error_t
*request
= msg
;
1916 mig_reply_error_t
*reply
;
1917 mach_msg_return_t mr
;
1919 (void)port
; // Unused
1920 (void)size
; // Unused
1921 (void)info
; // Unused
1923 /* allocate a reply buffer */
1924 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1926 /* call the MiG server routine */
1927 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1929 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1931 if (reply
->RetCode
== MIG_NO_REPLY
)
1934 * This return code is a little tricky -- it appears that the
1935 * demux routine found an error of some sort, but since that
1936 * error would not normally get returned either to the local
1937 * user or the remote one, we pretend it's ok.
1939 CFAllocatorDeallocate(NULL
, reply
);
1944 * destroy any out-of-line data in the request buffer but don't destroy
1945 * the reply port right (since we need that to send an error message).
1947 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
1948 mach_msg_destroy(&request
->Head
);
1951 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
1953 /* no reply port, so destroy the reply */
1954 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1955 mach_msg_destroy(&reply
->Head
);
1956 CFAllocatorDeallocate(NULL
, reply
);
1963 * We don't want to block indefinitely because the client
1964 * isn't receiving messages from the reply port.
1965 * If we have a send-once right for the reply port, then
1966 * this isn't a concern because the send won't block.
1967 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1968 * To avoid falling off the kernel's fast RPC path unnecessarily,
1969 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1972 options
= MACH_SEND_MSG
;
1973 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
1974 options
|= MACH_SEND_TIMEOUT
;
1976 mr
= mach_msg(&reply
->Head
, /* msg */
1977 options
, /* option */
1978 reply
->Head
.msgh_size
, /* send_size */
1980 MACH_PORT_NULL
, /* rcv_name */
1981 MACH_MSG_TIMEOUT_NONE
, /* timeout */
1982 MACH_PORT_NULL
); /* notify */
1984 /* Has a message error occurred? */
1987 case MACH_SEND_INVALID_DEST
:
1988 case MACH_SEND_TIMED_OUT
:
1989 /* the reply can't be delivered, so destroy it */
1990 mach_msg_destroy(&reply
->Head
);
1994 /* Includes success case. */
1998 CFAllocatorDeallocate(NULL
, reply
);
2001 mDNSlocal kern_return_t
registerBootstrapService()
2003 kern_return_t status
;
2004 mach_port_t service_send_port
, service_rcv_port
;
2006 debugf("Registering Bootstrap Service");
2009 * See if our service name is already registered and if we have privilege to check in.
2011 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2012 if (status
== KERN_SUCCESS
)
2015 * If so, we must be a followup instance of an already defined server. In that case,
2016 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2017 * that in case we have to unregister later (which requires the privilege port).
2019 server_priv_port
= bootstrap_port
;
2020 restarting_via_mach_init
= TRUE
;
2022 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2024 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2025 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2026 if (status
!= KERN_SUCCESS
) return status
;
2028 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2029 if (status
!= KERN_SUCCESS
)
2031 mach_port_deallocate(mach_task_self(), server_priv_port
);
2035 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2036 if (status
!= KERN_SUCCESS
)
2038 mach_port_deallocate(mach_task_self(), server_priv_port
);
2039 mach_port_deallocate(mach_task_self(), service_send_port
);
2042 assert(service_send_port
== service_rcv_port
);
2046 * We have no intention of responding to requests on the service port. We are not otherwise
2047 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2048 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2049 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2051 mach_port_destroy(mach_task_self(), service_rcv_port
);
2055 mDNSlocal kern_return_t
destroyBootstrapService()
2057 debugf("Destroying Bootstrap Service");
2058 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2061 mDNSlocal
void ExitCallback(int signal
)
2065 int rrcache_active
= 0;
2066 for (rr
= mDNSStorage
.rrcache
; rr
; rr
=rr
->next
) if (CacheRRActive(&mDNSStorage
, rr
)) rrcache_active
++;
2067 debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage
.rrcache_used
, rrcache_active
);
2070 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2072 debugf("ExitCallback: destroyBootstrapService");
2073 if (!mDNS_DebugMode
&& signal
!= SIGHUP
)
2074 destroyBootstrapService();
2076 debugf("ExitCallback: Aborting MIG clients");
2077 while (DNSServiceDomainEnumerationList
)
2078 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2079 while (DNSServiceBrowserList
)
2080 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2081 while (DNSServiceResolverList
)
2082 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2083 while (DNSServiceRegistrationList
)
2084 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2086 debugf("ExitCallback: mDNS_Close");
2087 mDNS_Close(&mDNSStorage
);
2088 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2092 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2093 mDNSlocal
void HandleSIG(int signal
)
2096 debugf("HandleSIG %d", signal
);
2097 mach_msg_header_t header
;
2098 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2099 header
.msgh_remote_port
= signal_port
;
2100 header
.msgh_local_port
= MACH_PORT_NULL
;
2101 header
.msgh_size
= sizeof(header
);
2102 header
.msgh_id
= signal
;
2103 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2105 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2106 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2110 mDNSlocal
void INFOCallback(void)
2112 DNSServiceDomainEnumeration
*e
;
2113 DNSServiceBrowser
*b
;
2114 DNSServiceResolver
*l
;
2115 DNSServiceRegistration
*r
;
2116 NetworkInterfaceInfoOSX
*i
;
2118 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2120 udsserver_info(&mDNSStorage
);
2122 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2123 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2125 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2127 DNSServiceBrowserQuestion
*qptr
;
2128 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2129 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2131 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2132 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2134 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2136 ServiceInstance
*si
;
2137 for (si
= r
->regs
; si
; si
= si
->next
)
2138 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
));
2141 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2144 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT",
2145 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
);
2147 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2148 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2149 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2150 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2151 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2152 i
->ifinfo
.InterfaceID
,
2153 i
->ifinfo
.Advertise
? "Adv" : " ",
2154 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2158 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2161 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2163 (void)port
; // Unused
2164 (void)size
; // Unused
2165 (void)info
; // Unused
2166 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2171 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2172 case SIGINFO
: INFOCallback(); break;
2173 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2174 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2175 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2179 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2182 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2183 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2184 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2185 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2186 char *MachServerName
= mDNSMacOSXSystemBuildNumber(NULL
) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2187 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2188 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2189 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2190 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2195 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2197 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2201 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2202 rrcachestorage
, RR_CACHE_SIZE
,
2203 mDNS_Init_AdvertiseLocalAddresses
,
2204 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2206 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2208 client_death_port
= CFMachPortGetPort(d_port
);
2209 signal_port
= CFMachPortGetPort(i_port
);
2211 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2212 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2213 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2217 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2218 err
= udsserver_init();
2219 if (err
) { LogMsg("Daemon start: udsserver_init failed"); return err
; }
2223 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2225 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2226 mDNSs32 nextevent
= mDNS_Execute(m
);
2228 mDNSs32 now
= mDNS_TimeNow(m
);
2230 // 2. Deliver any waiting browse messages to clients
2231 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2235 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2236 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2237 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2238 DNSServiceBrowser
*x
= b
;
2240 if (x
->results
) // Try to deliver the list of results
2244 DNSServiceBrowserResult
*const r
= x
->results
;
2246 domainname type
, domain
;
2247 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2248 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2249 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2250 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2251 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2252 ConvertDomainNameToCString(&type
, ctype
);
2253 ConvertDomainNameToCString(&domain
, cdom
);
2254 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2255 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2256 // If we failed to send the mach message, try again in one second
2257 if (status
== MACH_SEND_TIMED_OUT
)
2259 if (nextevent
- now
> mDNSPlatformOneSecond
)
2260 nextevent
= now
+ mDNSPlatformOneSecond
;
2265 x
->lastsuccess
= now
;
2266 x
->results
= x
->results
->next
;
2267 freeL("DNSServiceBrowserResult", r
);
2270 // If this client hasn't read a single message in the last 60 seconds, abort it
2271 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2272 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2276 DNSServiceResolver
*l
;
2277 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2278 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2281 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2282 "This places considerable burden on the network.", l
->i
.name
.c
);
2285 if (m
->p
->NotifyUser
)
2287 if (m
->p
->NotifyUser
- now
< 0)
2289 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2291 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2292 RecordUpdatedName(m
, &m
->p
->usernicelabel
, &m
->nicelabel
, "The name of your computer ", "",
2293 CFSTR("To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field."));
2294 m
->p
->NotifyUser
= 0; // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2296 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2298 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2299 RecordUpdatedName(m
, &m
->p
->userhostlabel
, &m
->hostlabel
, "This computer's local hostname ", ".local",
2300 CFSTR("To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field."));
2302 m
->p
->NotifyUser
= 0;
2305 if (nextevent
- m
->p
->NotifyUser
> 0)
2306 nextevent
= m
->p
->NotifyUser
;
2309 if (m
->p
->NetworkChanged
)
2311 if (m
->p
->NetworkChanged
- now
< 0)
2313 m
->p
->NetworkChanged
= 0;
2314 mDNSMacOSXNetworkChanged(m
);
2317 if (nextevent
- m
->p
->NetworkChanged
> 0)
2318 nextevent
= m
->p
->NetworkChanged
;
2324 mDNSexport
int main(int argc
, char **argv
)
2327 kern_return_t status
;
2329 for (i
=1; i
<argc
; i
++)
2331 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2334 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2335 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2336 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2337 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2338 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2339 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2341 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2342 if (!mDNS_DebugMode
) registerBootstrapService();
2344 if (!mDNS_DebugMode
&& !restarting_via_mach_init
)
2345 exit(0); /* mach_init will restart us immediately as a daemon */
2347 if (!mDNS_DebugMode
)
2349 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2350 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2353 // Avoid unnecessarily duplicating a file descriptor to itself
2354 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2355 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2356 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2357 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2361 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2362 LogMsgIdent(mDNSResponderVersionString
, "starting");
2363 status
= mDNSDaemonInitialize();
2365 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2366 // Now that we're finished with anything privileged, switch over to running as "nobody"
2367 const struct passwd
*pw
= getpwnam("nobody");
2371 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2376 LogMsg("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2378 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2380 // This is the main work loop:
2381 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2382 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2383 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2384 // (4) On wakeup we first process *all* events
2385 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2386 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2388 // 1. Before going into a blocking wait call and letting our process to go sleep,
2389 // call mDNSDaemonIdle to allow any deferred work to be completed.
2390 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2391 nextevent
= udsserver_idle(nextevent
);
2393 // 2. Work out how long we expect to sleep before the next scheduled task
2394 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2395 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2401 if (++RepeatedBusy
>= mDNSPlatformOneSecond
* 10)
2402 { LogMsg("Task Scheduling Error: Continuously busy for the last ten seconds"); RepeatedBusy
= 0; }
2404 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2406 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2407 // (a) our next wakeup time, or (b) an event occurs.
2408 // The 'true' parameter makes it return after handling any event that occurs
2409 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2410 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2412 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2414 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2415 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2418 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2422 LogMsg("ERROR: CFRunLoopRun Exiting.");
2423 mDNS_Close(&mDNSStorage
);
2426 if (!mDNS_DebugMode
) destroyBootstrapService();
2431 // uds_daemon.c support routines /////////////////////////////////////////////
2433 // We keep a list of client-supplied event sources in PosixEventSource records
2434 struct CFSocketEventSource
2436 udsEventCallback Callback
;
2439 struct CFSocketEventSource
*Next
;
2441 CFRunLoopSourceRef RLS
;
2443 typedef struct CFSocketEventSource CFSocketEventSource
;
2445 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2447 static void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2448 // Called by CFSocket when data appears on socket
2454 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2455 source
->Callback(source
->Context
);
2458 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2459 // Arrange things so that callback is called with context when data appears on fd
2461 CFSocketEventSource
*newSource
;
2462 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2464 if (gEventSources
.LinkOffset
== 0)
2465 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2467 if (fd
>= FD_SETSIZE
|| fd
< 0)
2468 return mStatus_UnsupportedErr
;
2469 if (callback
== NULL
)
2470 return mStatus_BadParamErr
;
2472 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2473 if (NULL
== newSource
)
2474 return mStatus_NoMemoryErr
;
2476 newSource
->Callback
= callback
;
2477 newSource
->Context
= context
;
2480 cfContext
.info
= newSource
;
2481 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2482 cf_callback
, &cfContext
)) &&
2483 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2485 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2486 AddToTail(&gEventSources
, newSource
);
2492 CFSocketInvalidate(newSource
->cfs
); // automatically closes socket
2493 CFRelease(newSource
->cfs
);
2495 return mStatus_NoMemoryErr
;
2498 return mStatus_NoError
;
2501 mStatus
udsSupportRemoveFDFromEventLoop(int fd
)
2502 // Reverse what was done in udsSupportAddFDToEventLoop().
2504 CFSocketEventSource
*iSource
;
2506 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2508 if (fd
== iSource
->fd
)
2510 RemoveFromList(&gEventSources
, iSource
);
2511 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2512 CFRunLoopSourceInvalidate(iSource
->RLS
);
2513 CFRelease(iSource
->RLS
);
2514 CFSocketInvalidate(iSource
->cfs
);
2515 CFRelease(iSource
->cfs
);
2517 return mStatus_NoError
;
2520 return mStatus_NoSuchNameErr
;
2523 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2524 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2525 asm(".desc ___crashreporter_info__, 0x10");
2527 // For convenience when using the "strings" command, this is the last thing in the file
2528 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";