]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/daemon.c
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / daemon.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * Formatting notes:
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.)
35
36 Change History (most recent first):
37
38 $Log: daemon.c,v $
39 Revision 1.227 2004/12/10 13:52:57 cheshire
40 <rdar://problem/3909995> Turn off SIGPIPE signals
41
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
44
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
47
48 Revision 1.224 2004/12/10 00:41:05 cheshire
49 Adjust alignment of log messages
50
51 Revision 1.223 2004/12/07 20:42:34 cheshire
52 Add explicit context parameter to mDNS_RemoveRecordFromService()
53
54 Revision 1.222 2004/12/06 21:15:23 ksekar
55 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
56
57 Revision 1.221 2004/11/30 03:24:04 cheshire
58 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
59
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.
64
65 Revision 1.219 2004/11/25 01:00:56 cheshire
66 Checkin 1.217 not necessary
67
68 Revision 1.218 2004/11/24 20:27:19 cheshire
69 Add missing "err" parameter in LogMsg() call
70
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
73
74 Revision 1.216 2004/11/24 00:10:44 cheshire
75 <rdar://problem/3869241> For unicast operations, verify that service types are legal
76
77 Revision 1.215 2004/11/23 22:33:01 cheshire
78 <rdar://problem/3654910> Remove temporary workaround code for iChat
79
80 Revision 1.214 2004/11/23 22:13:59 cheshire
81 <rdar://problem/3886293> Subtype advertising broken for Mach API
82
83 Revision 1.213 2004/11/23 06:12:55 cheshire
84 <rdar://problem/3871405> Update wording for name conflict dialogs
85
86 Revision 1.212 2004/11/23 05:15:37 cheshire
87 <rdar://problem/3875830> Computer Name in use message garbled
88
89 Revision 1.211 2004/11/23 05:00:41 cheshire
90 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
91
92 Revision 1.210 2004/11/03 03:45:17 cheshire
93 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
94
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
97
98 Revision 1.208 2004/11/03 01:54:14 cheshire
99 Update debugging messages
100
101 Revision 1.207 2004/11/02 23:58:19 cheshire
102 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
103
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)
106
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
111
112 Revision 1.204 2004/10/27 01:57:21 cheshire
113 Add check of m->p->InterfaceList
114
115 Revision 1.203 2004/10/26 04:31:44 cheshire
116 Rename CountSubTypes() as ChopSubTypes()
117
118 Revision 1.202 2004/10/26 01:29:18 cheshire
119 Use "#if 0" instead of commenting out code
120
121 Revision 1.201 2004/10/25 21:41:39 ksekar
122 <rdar://problem/3852958> wide-area name conflicts can cause crash
123
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
127
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
132
133 Revision 1.198 2004/10/15 23:00:18 ksekar
134 <rdar://problem/3799242> Need to update LLQs on location changes
135
136 Revision 1.197 2004/10/12 23:38:59 ksekar
137 <rdar://problem/3837065> remove unnecessary log message
138
139 Revision 1.196 2004/10/04 05:56:04 cheshire
140 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
141
142 Revision 1.195 2004/09/30 00:24:59 ksekar
143 <rdar://problem/3695802> Dynamically update default registration domains on config change
144
145 Revision 1.194 2004/09/26 23:20:35 ksekar
146 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
147
148 Revision 1.193 2004/09/23 23:35:27 cheshire
149 Update error message
150
151 Revision 1.192 2004/09/21 23:40:12 ksekar
152 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
153
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
157
158 Revision 1.190 2004/09/21 19:51:15 cheshire
159 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
160
161 Revision 1.189 2004/09/21 18:17:23 cheshire
162 <rdar://problem/3785400> Add version info to mDNSResponder
163
164 Revision 1.188 2004/09/20 21:45:27 ksekar
165 Mach IPC cleanup
166
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.
172
173 Revision 1.186 2004/09/16 00:24:49 cheshire
174 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
175
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
178
179 Revision 1.184 2004/08/19 19:04:12 ksekar
180 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
181
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
187
188 Revision 1.182 2004/08/13 23:57:59 cheshire
189 Get rid of non-portable "_UNUSED"
190
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
194
195 Revision 1.180 2004/07/13 21:24:25 rpantos
196 Fix for <rdar://problem/3701120>.
197
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
200
201 Revision 1.178 2004/06/18 19:10:00 cheshire
202 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
203
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
206
207 Revision 1.176 2004/06/11 20:27:42 cheshire
208 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
209
210 Revision 1.175 2004/06/10 20:23:21 cheshire
211 Also list interfaces in SIGINFO output
212
213 Revision 1.174 2004/06/08 18:54:48 ksekar
214 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
215
216 Revision 1.173 2004/06/08 17:35:12 cheshire
217 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
218
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
221
222 Revision 1.171 2004/06/04 08:58:30 ksekar
223 <rdar://problem/3668624>: Keychain integration for secure dynamic update
224
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)
229
230 Revision 1.169 2004/05/30 01:30:16 ksekar
231 <rdar://problem/3668635>: wide-area default registrations should be in
232 .local too
233
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
236
237 Revision 1.167 2004/05/14 16:39:47 ksekar
238 Browse for iChat locally for now.
239
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.
243
244 Revision 1.165 2004/05/13 04:54:20 ksekar
245 Unified list copy/free code. Added symetric list for
246
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.
252
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.
256
257 Revision 1.162 2004/04/14 23:09:29 ksekar
258 Support for TSIG signed dynamic updates.
259
260 Revision 1.161 2004/04/07 01:20:04 cheshire
261 Hash slot value should be unsigned
262
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.
266
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"
270
271 Revision 1.158 2004/04/02 21:39:05 cheshire
272 Fix errors in comments
273
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
277
278 Revision 1.156 2004/03/19 18:19:19 ksekar
279 Fixed daemon.c to compile with malloc debugging turned on.
280
281 Revision 1.155 2004/03/13 01:57:34 ksekar
282 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
283
284 Revision 1.154 2004/03/12 08:42:47 cheshire
285 <rdar://problem/3548256>: Should not allow empty string for resolve domain
286
287 Revision 1.153 2004/03/12 08:08:51 cheshire
288 Update comments
289
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
293
294 Revision 1.151 2004/02/03 22:35:34 cheshire
295 <rdar://problem/3548256>: Should not allow empty string for resolve domain
296
297 Revision 1.150 2004/01/28 21:14:23 cheshire
298 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
299
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.
304
305 Revision 1.148 2004/01/25 00:03:20 cheshire
306 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
307
308 Revision 1.147 2004/01/19 19:51:46 cheshire
309 Fix compiler error (mixed declarations and code) on some versions of Linux
310
311 Revision 1.146 2003/12/08 21:00:46 rpantos
312 Changes to support mDNSResponder on Linux.
313
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)
316
317 Revision 1.144 2003/11/19 23:21:08 ksekar
318 <rdar://problem/3486646>: config change handler not called for dns-sd services
319
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.
323
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
326
327 Revision 1.141 2003/11/07 02:30:57 cheshire
328 Also check per-slot cache use counts in SIGINFO state log
329
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)
332
333 Revision 1.139 2003/10/21 00:10:18 rpantos
334 <rdar://problem/3409401>: mDNSResponder should not run as root
335
336 Revision 1.138 2003/10/07 20:16:58 cheshire
337 Shorten syslog message a bit
338
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
341
342 Revision 1.136 2003/09/23 02:07:25 cheshire
343 Include port number in DNSServiceRegistration START/STOP messages
344
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
347
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
350
351 Revision 1.133 2003/08/20 23:39:31 cheshire
352 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
353
354 Revision 1.132 2003/08/20 01:44:56 cheshire
355 Fix errors in LogOperation() calls (only used for debugging)
356
357 Revision 1.131 2003/08/19 05:39:43 cheshire
358 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
359
360 Revision 1.130 2003/08/16 03:39:01 cheshire
361 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
362
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.
370
371 Revision 1.128 2003/08/14 19:30:36 cheshire
372 <rdar://problem/3378473> Include list of cache records in SIGINFO output
373
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
376
377 Revision 1.126 2003/08/12 19:56:25 cheshire
378 Update to APSL 2.0
379
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
382
383 Revision 1.124 2003/07/25 18:28:23 cheshire
384 Minor fix to error messages in syslog: Display string parameters with quotes
385
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
389
390 Revision 1.122 2003/07/23 00:00:04 cheshire
391 Add comments
392
393 Revision 1.121 2003/07/20 03:38:51 ksekar
394 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
395
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
398
399 Revision 1.119 2003/07/17 19:08:58 cheshire
400 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
401
402 Revision 1.118 2003/07/15 21:12:28 cheshire
403 Added extra debugging checks in validatelists() (not used in final shipping version)
404
405 Revision 1.117 2003/07/15 01:55:15 cheshire
406 <rdar://problem/3315777> Need to implement service registration with subtypes
407
408 Revision 1.116 2003/07/02 21:19:51 cheshire
409 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
410
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
413
414 Revision 1.114 2003/07/01 21:10:20 cheshire
415 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
416
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
420 well behaved daemon
421
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.
427
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.
431
432 Revision 1.110 2003/06/10 01:14:11 cheshire
433 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
434
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.)
438
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()
441
442 Revision 1.107 2003/05/29 05:44:55 cheshire
443 Minor fixes to log messages
444
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
448
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
454
455 Revision 1.104 2003/05/26 00:42:06 cheshire
456 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
457
458 Revision 1.103 2003/05/23 23:07:44 cheshire
459 <rdar://problem/3268199> Must not write to stderr when running as daemon
460
461 Revision 1.102 2003/05/22 01:32:31 cheshire
462 Fix typo in Log message format string
463
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.
467
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.
472
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.)
475
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
479
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
482
483 Revision 1.96 2003/05/07 22:10:46 cheshire
484 <rdar://problem/3250330> Add a few more error logging messages
485
486 Revision 1.95 2003/05/07 19:20:17 cheshire
487 <rdar://problem/3251391> Add version number to mDNSResponder builds
488
489 Revision 1.94 2003/05/07 00:28:18 cheshire
490 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
491
492 Revision 1.93 2003/05/06 00:00:49 cheshire
493 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
494
495 Revision 1.92 2003/04/04 20:38:57 cheshire
496 Add $Log header
497
498 */
499
500 #include <mach/mach.h>
501 #include <mach/mach_error.h>
502 #include <servers/bootstrap.h>
503 #include <sys/types.h>
504 #include <unistd.h>
505 #include <paths.h>
506 #include <fcntl.h>
507 #include <pwd.h>
508 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
509
510 #include "DNSServiceDiscoveryRequestServer.h"
511 #include "DNSServiceDiscoveryReply.h"
512
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
515
516 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
517
518 #include "GenLinkedList.h"
519
520 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
521
522 //*************************************************************************************************************
523 // Macros
524
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)
530
531 //*************************************************************************************************************
532 // Globals
533
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];
539
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;
544
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
552
553 static int restarting_via_mach_init = 0;
554
555 //*************************************************************************************************************
556 // Active client list structures
557
558 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
559 struct DNSServiceDomainEnumeration_struct
560 {
561 DNSServiceDomainEnumeration *next;
562 mach_port_t ClientMachPort;
563 DNSQuestion dom; // Question asking for domains
564 DNSQuestion def; // Question asking for default domain
565 };
566
567 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
568 struct DNSServiceBrowserResult_struct
569 {
570 DNSServiceBrowserResult *next;
571 int resultType;
572 domainname result;
573 };
574
575 typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
576
577 typedef struct DNSServiceBrowserQuestion
578 {
579 struct DNSServiceBrowserQuestion *next;
580 DNSQuestion q;
581 domainname domain;
582 } DNSServiceBrowserQuestion;
583
584 struct DNSServiceBrowser_struct
585 {
586 DNSServiceBrowser *next;
587 mach_port_t ClientMachPort;
588 DNSServiceBrowserQuestion *qlist;
589 DNSServiceBrowserResult *results;
590 mDNSs32 lastsuccess;
591 mDNSBool DefaultDomain; // was the browse started on an explicit domain?
592 domainname type; // registration type
593 };
594
595 typedef struct DNSServiceResolver_struct DNSServiceResolver;
596 struct DNSServiceResolver_struct
597 {
598 DNSServiceResolver *next;
599 mach_port_t ClientMachPort;
600 ServiceInfoQuery q;
601 ServiceInfo i;
602 mDNSs32 ReportTime;
603 };
604
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
609 {
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
614 domainlabel name;
615 domainname domain;
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
619 } ServiceInstance;
620
621 // A client-created service. May reference several ServiceInstance objects if default
622 // settings cause registration in multiple domains.
623 typedef struct DNSServiceRegistration
624 {
625 struct DNSServiceRegistration *next;
626 mach_port_t ClientMachPort;
627 mDNSBool DefaultDomain;
628 mDNSBool autoname;
629 size_t rdsize;
630 int NumSubTypes;
631 char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
632 domainlabel name; // used only if autoname is false
633 domainname type;
634 mDNSIPPort port;
635 unsigned char txtinfo[1024];
636 size_t txt_len;
637 uint32_t NextRef;
638 ServiceInstance *regs;
639 } DNSServiceRegistration;
640
641 static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
642 static DNSServiceBrowser *DNSServiceBrowserList = NULL;
643 static DNSServiceResolver *DNSServiceResolverList = NULL;
644 static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
645
646 //*************************************************************************************************************
647 // General Utility Functions
648
649 #if MACOSX_MDNS_MALLOC_DEBUGGING
650
651 char _malloc_options[] = "AXZ";
652
653 static void validatelists(mDNS *const m)
654 {
655 DNSServiceDomainEnumeration *e;
656 DNSServiceBrowser *b;
657 DNSServiceResolver *l;
658 DNSServiceRegistration *r;
659 AuthRecord *rr;
660 CacheRecord *cr;
661 DNSQuestion *q;
662 mDNSu32 slot;
663 NetworkInterfaceInfoOSX *i;
664
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);
668
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);
672
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);
676
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);
680
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);
684
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);
688
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);
692
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);
697
698 for (i = m->p->InterfaceList; i; i = i->next)
699 if (!i->ifa_name)
700 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i);
701 }
702
703 void *mallocL(char *msg, unsigned int size)
704 {
705 unsigned long *mem = malloc(size+8);
706 if (!mem)
707 {
708 LogMsg("malloc( %s : %d ) failed", msg, size);
709 return(NULL);
710 }
711 else
712 {
713 LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
714 mem[0] = 0xDEAD1234;
715 mem[1] = size;
716 //bzero(&mem[2], size);
717 memset(&mem[2], 0xFF, size);
718 validatelists(&mDNSStorage);
719 return(&mem[2]);
720 }
721 }
722
723 void freeL(char *msg, void *x)
724 {
725 if (!x)
726 LogMsg("free( %s @ NULL )!", msg);
727 else
728 {
729 unsigned long *mem = ((unsigned long *)x) - 2;
730 if (mem[0] != 0xDEAD1234)
731 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
732 if (mem[1] > 24000)
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);
738 free(mem);
739 }
740 }
741
742 #endif
743
744 //*************************************************************************************************************
745 // Client Death Detection
746
747 mDNSlocal void FreeServiceInstance(ServiceInstance *x)
748 {
749 ServiceRecordSet *s = &x->srs;
750 ExtraResourceRecord *e = x->srs.Extras, *tmp;
751
752 while(e)
753 {
754 e->r.RecordContext = e;
755 tmp = e;
756 e = e->next;
757 FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
758 }
759
760 if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
761 freeL("TXT RData", s->RR_TXT.resrec.rdata);
762
763 if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
764 freeL("ServiceInstance", x);
765 }
766
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)
772 {
773 DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList;
774 DNSServiceBrowser **b = &DNSServiceBrowserList;
775 DNSServiceResolver **l = &DNSServiceResolverList;
776 DNSServiceRegistration **r = &DNSServiceRegistrationList;
777
778 while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next;
779 if (*e)
780 {
781 DNSServiceDomainEnumeration *x = *e;
782 *e = (*e)->next;
783 if (m && m != x)
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);
789 return;
790 }
791
792 while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
793 if (*b)
794 {
795 DNSServiceBrowser *x = *b;
796 DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist;
797 *b = (*b)->next;
798 while (qptr)
799 {
800 if (m && m != x)
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);
804 freePtr = qptr;
805 qptr = qptr->next;
806 freeL("DNSServiceBrowserQuestion", freePtr);
807 }
808 while (x->results)
809 {
810 DNSServiceBrowserResult *r = x->results;
811 x->results = x->results->next;
812 freeL("DNSServiceBrowserResult", r);
813 }
814 freeL("DNSServiceBrowser", x);
815 return;
816 }
817
818 while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next;
819 if (*l)
820 {
821 DNSServiceResolver *x = *l;
822 *l = (*l)->next;
823 if (m && m != x)
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);
828 return;
829 }
830
831 while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
832 if (*r)
833 {
834 ServiceInstance *si = NULL;
835 DNSServiceRegistration *x = *r;
836 *r = (*r)->next;
837
838 si = x->regs;
839 while (si)
840 {
841 ServiceInstance *instance = si;
842 si = si->next;
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));
846
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
852 }
853 x->regs = NULL;
854 freeL("DNSServiceRegistration", x);
855 return;
856 }
857
858 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort);
859 }
860
861 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
862
863 mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m)
864 {
865 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
866 DNSServiceBrowser *b = DNSServiceBrowserList;
867 DNSServiceResolver *l = DNSServiceResolverList;
868 DNSServiceRegistration *r = DNSServiceRegistrationList;
869 DNSServiceBrowserQuestion *qptr;
870
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);
876 else if (b)
877 {
878 for (qptr = b->qlist; qptr; qptr = qptr->next)
879 LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
880 }
881 else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
882 else if (r)
883 {
884 ServiceInstance *si;
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);
886 }
887 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
888
889 AbortClient(c, m);
890 }
891
892 mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
893 {
894 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
895 DNSServiceBrowser *b = DNSServiceBrowserList;
896 DNSServiceResolver *l = DNSServiceResolverList;
897 DNSServiceRegistration *r = DNSServiceRegistrationList;
898 DNSServiceBrowserQuestion *qptr;
899
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);
905 if (b)
906 {
907 for (qptr = b->qlist; qptr; qptr = qptr->next)
908 LogMsg("%5d: Browser(%##s) already exists!", c, qptr->q.qname.c);
909 }
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);
913 }
914
915 mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
916 {
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)
922 {
923 const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg;
924 AbortClient(deathMessage->not_port, NULL);
925
926 /* Deallocate the send right that came in the dead name notification */
927 mach_port_destroy(mach_task_self(), deathMessage->not_port);
928 }
929 }
930
931 mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
932 {
933 mach_port_t prev;
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);
939 }
940
941 //*************************************************************************************************************
942 // Domain Enumeration
943
944 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
945 {
946 kern_return_t status;
947 #pragma unused(m)
948 char buffer[MAX_ESCAPED_DOMAIN_NAME];
949 DNSServiceDomainEnumerationReplyResultType rt;
950 DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
951
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; }
955
956 if (AddRecord)
957 {
958 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain;
959 else rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
960 }
961 else
962 {
963 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain;
964 else return;
965 }
966
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");
971
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);
976 }
977
978 mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
979 int regDom)
980 {
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; }
987
988 mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
989 mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
990 const DNSServiceDomainEnumerationReplyResultType rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
991
992 // Allocate memory, and handle failure
993 DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
994 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
995
996 // Set up object, and link into list
997 x->ClientMachPort = client;
998 x->next = DNSServiceDomainEnumerationList;
999 DNSServiceDomainEnumerationList = x;
1000
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); }
1007
1008 // Do the operation
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; }
1012
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);
1017
1018 fail:
1019 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err);
1020 return(err);
1021 }
1022
1023 //*************************************************************************************************************
1024 // Browse for services
1025
1026 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1027 {
1028 (void)m; // Unused
1029
1030 if (answer->rrtype != kDNSType_PTR)
1031 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
1032
1033 domainlabel name;
1034 domainname type, domain;
1035 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
1036 {
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);
1039 return;
1040 }
1041
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; }
1044
1045 verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
1046 AssignDomainName(x->result, answer->rdata->u.name);
1047 if (AddRecord)
1048 x->resultType = DNSServiceBrowserReplyAddInstance;
1049 else x->resultType = DNSServiceBrowserReplyRemoveInstance;
1050 x->next = NULL;
1051
1052 DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext;
1053 DNSServiceBrowserResult **p = &browser->results;
1054 while (*p) p = &(*p)->next;
1055 *p = x;
1056 }
1057
1058 mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
1059 {
1060 mStatus err = mStatus_NoError;
1061 DNSServiceBrowserQuestion *ptr, *question = NULL;
1062
1063 for (ptr = browser->qlist; ptr; ptr = ptr->next)
1064 {
1065 if (SameDomainName(&ptr->q.qname, d))
1066 { debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; }
1067 }
1068
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);
1077 return err;
1078 }
1079
1080 mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
1081 {
1082 DNSServiceBrowser *ptr;
1083
1084 debugf("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
1085 for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
1086 {
1087 if (ptr->DefaultDomain)
1088 {
1089 if (add)
1090 {
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);
1093 }
1094 else
1095 {
1096 #if 0
1097 /*
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.
1101 */
1102 // find the question for this domain
1103 DNSServiceBrowserQuestion *q = ptr->qlist, *prev = NULL;
1104 while (q)
1105 {
1106 if (SameDomainName(&q->domain, d))
1107 {
1108 if (prev) prev->next = q->next;
1109 else ptr->qlist = q->next;
1110 mDNS_StopBrowse(&mDNSStorage, &q->q);
1111 freeL("DNSServiceBrowserQuestion", q);
1112 break;
1113 }
1114 prev = q;
1115 q = q->next;
1116 }
1117 if (!q) LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
1118 #endif
1119 }
1120 }
1121 }
1122 }
1123
1124 mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1125 DNSCString regtype, DNSCString domain)
1126 {
1127 // Check client parameter
1128 (void)unusedserver; // Unused
1129 mStatus err = mStatus_NoError;
1130 const char *errormsg = "Unknown";
1131 DNameListElem *SearchDomains = NULL, *sdPtr;
1132
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; }
1135
1136 // Check other parameters
1137 domainname t, d;
1138 t.c[0] = 0;
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; }
1144 domainname temp;
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"
1147
1148 // Allocate memory, and handle failure
1149 DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
1150 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1151
1152 // Set up object, and link into list
1153 AssignDomainName(x->type, t);
1154 x->ClientMachPort = client;
1155 x->results = NULL;
1156 x->lastsuccess = 0;
1157 x->qlist = NULL;
1158 x->next = DNSServiceBrowserList;
1159 DNSServiceBrowserList = x;
1160
1161 if (domain[0])
1162 {
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; }
1168 }
1169 else
1170 {
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)
1176 {
1177 err = AddDomainToBrowser(x, &sdPtr->name);
1178 if (err)
1179 {
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; }
1184 }
1185 }
1186 }
1187
1188 // Succeeded: Wrap up and return
1189 EnableDeathNotificationForClient(client, x);
1190 mDNS_FreeDNameList(SearchDomains);
1191 return(mStatus_NoError);
1192
1193 badparam:
1194 err = mStatus_BadParamErr;
1195 fail:
1196 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
1197 if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
1198 return(err);
1199 }
1200
1201 //*************************************************************************************************************
1202 // Resolve Service Info
1203
1204 mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
1205 {
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;
1212 char cstring[1024];
1213 int i, pstrlen = query->info->TXTinfo[0];
1214 (void)m; // Unused
1215
1216 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1217
1218 if (query->info->TXTlen > sizeof(cstring)) return;
1219
1220 bzero(&interface, sizeof(interface));
1221 bzero(&address, sizeof(address));
1222
1223 if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
1224 {
1225 struct sockaddr_in *sin = (struct sockaddr_in*)&interface;
1226 sin->sin_len = sizeof(*sin);
1227 sin->sin_family = AF_INET;
1228 sin->sin_port = 0;
1229 sin->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
1230 }
1231 else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
1232 {
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;
1240 }
1241
1242 if (query->info->ip.type == mDNSAddrType_IPv4)
1243 {
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;
1249 }
1250 else
1251 {
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;
1259 }
1260
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++)
1267 {
1268 if (--pstrlen >= 0)
1269 cstring[i-1] = query->info->TXTinfo[i];
1270 else
1271 {
1272 cstring[i-1] = 1;
1273 pstrlen = query->info->TXTinfo[i];
1274 }
1275 }
1276 cstring[i-1] = 0; // Put the terminating NULL on the end
1277
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);
1284 }
1285
1286 mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client,
1287 DNSCString name, DNSCString regtype, DNSCString domain)
1288 {
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; }
1295
1296 // Check other parameters
1297 domainlabel n;
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; }
1303
1304 // Allocate memory, and handle failure
1305 DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x));
1306 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1307
1308 // Set up object, and link into list
1309 x->ClientMachPort = client;
1310 x->i.InterfaceID = mDNSInterface_Any;
1311 x->i.name = srv;
1312 x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
1313 x->next = DNSServiceResolverList;
1314 DNSServiceResolverList = x;
1315
1316 // Do the operation
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; }
1320
1321 // Succeeded: Wrap up and return
1322 EnableDeathNotificationForClient(client, x);
1323 return(mStatus_NoError);
1324
1325 badparam:
1326 err = mStatus_BadParamErr;
1327 fail:
1328 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
1329 return(err);
1330 }
1331
1332 //*************************************************************************************************************
1333 // Registration
1334
1335 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
1336 {
1337 m->p->NotifyUser = NonZeroTime(m->timenow + delay);
1338 }
1339
1340 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
1341 {
1342 ServiceInstance *si = (ServiceInstance*)srs->ServiceContext;
1343
1344 if (result == mStatus_NoError)
1345 {
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
1353 }
1354
1355 else if (result == mStatus_NameConflict)
1356 {
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)
1361 {
1362 // On conflict for an autoname service, rename and reregister *all* autoname services
1363 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
1364 m->MainCallback(m, mStatus_ConfigChanged);
1365 }
1366 else if (si->autoname)
1367 {
1368 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
1369 return;
1370 }
1371 else
1372 {
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);
1379 }
1380 }
1381
1382 else if (result == mStatus_MemFree)
1383 {
1384 if (si->autorename)
1385 {
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);
1390 }
1391 else
1392 {
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)
1396 {
1397 ServiceInstance *sp = r->regs, *prev = NULL;
1398 while (sp)
1399 {
1400 if (sp == si)
1401 {
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;
1405 break;
1406 }
1407 prev = sp;
1408 sp = sp->next;
1409 }
1410 }
1411 // END SANITY CHECK
1412 FreeServiceInstance(si);
1413 }
1414 }
1415
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);
1418 }
1419
1420 mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
1421 {
1422 mStatus err = 0;
1423 ServiceInstance *si = NULL;
1424 AuthRecord *SubTypes = NULL;
1425
1426 for (si = x->regs; si; si = si->next)
1427 {
1428 if (SameDomainName(&si->domain, domain))
1429 { LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; }
1430 }
1431
1432 SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype);
1433 if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr;
1434
1435 si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
1436 if (!si) return mStatus_NoMemoryErr;
1437
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;
1443
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);
1445 if (!err)
1446 {
1447 si->next = x->regs;
1448 x->regs = si;
1449 }
1450 else
1451 {
1452 LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
1453 freeL("ServiceInstance", si);
1454 }
1455 return err;
1456 }
1457
1458 mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
1459 {
1460 DNSServiceRegistration *reg;
1461
1462 LogMsg("%s default registration domain %##s", add ? "Adding" : "Removing", d->c);
1463 for (reg = DNSServiceRegistrationList; reg; reg = reg->next)
1464 {
1465 if (reg->DefaultDomain)
1466 {
1467 if (add)
1468 {
1469 AddServiceInstance(reg, d);
1470 }
1471 else
1472 {
1473 ServiceInstance *si = reg->regs, *prev = NULL;
1474 while (si)
1475 {
1476 if (SameDomainName(&si->domain, d))
1477 {
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
1482 break;
1483 }
1484 prev = si;
1485 si = si->next;
1486 }
1487 if (!si) LogMsg("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort);
1488 }
1489 }
1490 }
1491 }
1492
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)
1495 {
1496 (void)unusedserver; // Unused
1497 mStatus err = mStatus_NoError;
1498 const char *errormsg = "Unknown";
1499
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
1503 mDNSIPPort port;
1504 port.b[0] = IpPort.bytes[2];
1505 port.b[1] = IpPort.bytes[3];
1506
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; }
1509
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; }
1515
1516 // Check other parameters
1517 domainlabel n;
1518 domainname t, d;
1519 domainname srv;
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; }
1525
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;
1531
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.
1537 while (*ptr)
1538 {
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
1541 {
1542 pstring = &txtinfo[data_len];
1543 pstring[0] = 0;
1544 ptr++;
1545 }
1546 else
1547 {
1548 if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; }
1549 pstring[++pstring[0]] = *ptr++;
1550 }
1551 }
1552
1553 data_len++;
1554 if (size < data_len)
1555 size = data_len;
1556
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)
1561 {
1562 int count = CountExistingRegistrations(&srv, port);
1563 if (count)
1564 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1565 client, count+1, srv.c, mDNSVal16(port));
1566 }
1567
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));
1572
1573 // Set up object, and link into list
1574 x->ClientMachPort = client;
1575 x->DefaultDomain = !domain[0];
1576 x->autoname = (!name[0]);
1577 x->rdsize = size;
1578 x->NumSubTypes = NumSubTypes;
1579 memcpy(x->regtype, regtype, reglen);
1580 x->name = n;
1581 x->type = t;
1582 x->port = port;
1583 memcpy(x->txtinfo, txtinfo, 1024);
1584 x->txt_len = data_len;
1585 x->NextRef = 0;
1586 x->regs = NULL;
1587
1588 x->next = DNSServiceRegistrationList;
1589 DNSServiceRegistrationList = x;
1590
1591 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1592 x->ClientMachPort, name, regtype, domain, mDNSVal16(port));
1593
1594 err = AddServiceInstance(x, &d);
1595 if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; } // bail if .local (or explicit domain) fails
1596
1597 if (x->DefaultDomain)
1598 {
1599 DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList();
1600 for (ptr = regdomains; ptr; ptr = ptr->next)
1601 AddServiceInstance(x, &ptr->name);
1602 mDNS_FreeDNameList(regdomains);
1603 }
1604
1605 // Succeeded: Wrap up and return
1606 EnableDeathNotificationForClient(client, x);
1607 return(mStatus_NoError);
1608
1609 badtxt:
1610 LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
1611 badparam:
1612 err = mStatus_BadParamErr;
1613 fail:
1614 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1615 client, name, regtype, domain, mDNSVal16(port), errormsg, err);
1616 return(err);
1617 }
1618
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)
1623 {
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);
1633 *n1 = *n2;
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");
1636 else
1637 {
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);
1643 Boolean result;
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)
1649 {
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
1660 }
1661 if (s0) CFRelease(s0);
1662 if (s1) CFRelease(s1);
1663 if (s2) CFRelease(s2);
1664 if (alertMessage) CFRelease(alertMessage);
1665 SCPreferencesUnlock(session);
1666 }
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);
1672 }
1673
1674 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
1675 {
1676 (void)m; // Unused
1677 if (result == mStatus_NoError)
1678 {
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);
1681 }
1682 else if (result == mStatus_ConfigChanged)
1683 {
1684 DNSServiceRegistration *r;
1685 for (r = DNSServiceRegistrationList; r; r=r->next)
1686 if (r->autoname)
1687 {
1688 ServiceInstance *si;
1689 for (si = r->regs; si; si = si->next)
1690 {
1691 if (!SameDomainLabel(si->name.c, m->nicelabel.c))
1692 {
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);
1697 }
1698 }
1699 }
1700 udsserver_handle_configchange();
1701 }
1702 else if (result == mStatus_GrowCache)
1703 {
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);
1708 }
1709 }
1710
1711 //*************************************************************************************************************
1712 // Add / Update / Remove records from existing Registration
1713
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)
1716 {
1717 // Check client parameter
1718 uint32_t id;
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;
1724 size_t size;
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; }
1728
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);
1733
1734 id = x->NextRef++;
1735 *reference = (natural_t)id;
1736 for (si = x->regs; si; si = si->next)
1737 {
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; }
1741
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);
1747
1748 // Do the operation
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);
1752
1753 if (err)
1754 {
1755 freeL("Extra Resource Record", extra);
1756 errormsg = "mDNS_AddRecordToService";
1757 goto fail;
1758 }
1759
1760 extra->ClientID = id;
1761 }
1762
1763 return mStatus_NoError;
1764
1765 fail:
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;
1768 }
1769
1770 mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
1771 {
1772 (void)m; // Unused
1773 if (OldRData != &rr->rdatastorage)
1774 freeL("Old RData", OldRData);
1775 }
1776
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)
1778 {
1779 // Check client parameter
1780 mStatus err = mStatus_NoError;
1781 const char *errormsg = "Unknown";
1782 domainname *name = (domainname *)"";
1783
1784 name = &srs->RR_SRV.resrec.name;
1785
1786 unsigned int size = sizeof(RDataBody);
1787 if (size < data_len)
1788 size = data_len;
1789
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; }
1793
1794 // Fill in new length, and data
1795 newrdata->MaxRDLength = size;
1796 memcpy(&newrdata->u, data, data_len);
1797
1798 // Do the operation
1799 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1800 client, srs->RR_SRV.resrec.name.c, data_len);
1801
1802 err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
1803 if (err)
1804 {
1805 errormsg = "mDNS_Update";
1806 freeL("RData", newrdata);
1807 return err;
1808 }
1809 return(mStatus_NoError);
1810
1811 fail:
1812 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err);
1813 return(err);
1814 }
1815
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)
1818 {
1819 // Check client parameter
1820 mStatus err = mStatus_NoError;
1821 const char *errormsg = "Unknown";
1822 domainname *name = (domainname *)"";
1823 ServiceInstance *si;
1824
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; }
1830
1831 // Check other parameters
1832 if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
1833
1834 for (si = x->regs; si; si = si->next)
1835 {
1836 AuthRecord *r = NULL;
1837
1838 // Find the record we're updating. NULL reference means update the primary TXT record
1839 if (!reference) r = &si->srs.RR_TXT;
1840 else
1841 {
1842 ExtraResourceRecord *ptr;
1843 for (ptr = si->srs.Extras; ptr; ptr = ptr->next)
1844 {
1845 if ((natural_t)ptr->ClientID == reference)
1846 { r = &ptr->r; break; }
1847 }
1848 if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
1849 }
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!
1852 }
1853
1854 return mStatus_NoError;
1855
1856 fail:
1857 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
1858 return(err);
1859 }
1860
1861 mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
1862 {
1863 domainname *name = &srs->RR_SRV.resrec.name;
1864 mStatus err = mStatus_NoError;
1865
1866 // Do the operation
1867 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name.c);
1868
1869 err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
1870 if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
1871
1872 return err;
1873 }
1874
1875 mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1876 natural_t reference)
1877 {
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;
1885
1886 while (x && x->ClientMachPort != client) x = x->next;
1887 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
1888
1889 for (si = x->regs; si; si = si->next)
1890 {
1891 ExtraResourceRecord *e;
1892 for (e = si->srs.Extras; e; e = e->next)
1893 {
1894 if ((natural_t)e->ClientID == reference)
1895 {
1896 err = RemoveRecord(&si->srs, e, client);
1897 break;
1898 }
1899 }
1900 if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
1901 }
1902
1903 return mStatus_NoError;
1904
1905 fail:
1906 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
1907 return(err);
1908 }
1909
1910 //*************************************************************************************************************
1911 // Support Code
1912
1913 mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
1914 {
1915 mig_reply_error_t *request = msg;
1916 mig_reply_error_t *reply;
1917 mach_msg_return_t mr;
1918 int options;
1919 (void)port; // Unused
1920 (void)size; // Unused
1921 (void)info; // Unused
1922
1923 /* allocate a reply buffer */
1924 reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
1925
1926 /* call the MiG server routine */
1927 (void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head);
1928
1929 if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS))
1930 {
1931 if (reply->RetCode == MIG_NO_REPLY)
1932 {
1933 /*
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.
1938 */
1939 CFAllocatorDeallocate(NULL, reply);
1940 return;
1941 }
1942
1943 /*
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).
1946 */
1947 request->Head.msgh_remote_port = MACH_PORT_NULL;
1948 mach_msg_destroy(&request->Head);
1949 }
1950
1951 if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
1952 {
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);
1957 return;
1958 }
1959
1960 /*
1961 * send reply.
1962 *
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.
1970 */
1971
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;
1975
1976 mr = mach_msg(&reply->Head, /* msg */
1977 options, /* option */
1978 reply->Head.msgh_size, /* send_size */
1979 0, /* rcv_size */
1980 MACH_PORT_NULL, /* rcv_name */
1981 MACH_MSG_TIMEOUT_NONE, /* timeout */
1982 MACH_PORT_NULL); /* notify */
1983
1984 /* Has a message error occurred? */
1985 switch (mr)
1986 {
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);
1991 break;
1992
1993 default :
1994 /* Includes success case. */
1995 break;
1996 }
1997
1998 CFAllocatorDeallocate(NULL, reply);
1999 }
2000
2001 mDNSlocal kern_return_t registerBootstrapService()
2002 {
2003 kern_return_t status;
2004 mach_port_t service_send_port, service_rcv_port;
2005
2006 debugf("Registering Bootstrap Service");
2007
2008 /*
2009 * See if our service name is already registered and if we have privilege to check in.
2010 */
2011 status = bootstrap_check_in(bootstrap_port, (char*)kmDNSBootstrapName, &service_rcv_port);
2012 if (status == KERN_SUCCESS)
2013 {
2014 /*
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).
2018 */
2019 server_priv_port = bootstrap_port;
2020 restarting_via_mach_init = TRUE;
2021 }
2022 else if (status == BOOTSTRAP_UNKNOWN_SERVICE)
2023 {
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;
2027
2028 status = bootstrap_create_service(server_priv_port, (char*)kmDNSBootstrapName, &service_send_port);
2029 if (status != KERN_SUCCESS)
2030 {
2031 mach_port_deallocate(mach_task_self(), server_priv_port);
2032 return status;
2033 }
2034
2035 status = bootstrap_check_in(server_priv_port, (char*)kmDNSBootstrapName, &service_rcv_port);
2036 if (status != KERN_SUCCESS)
2037 {
2038 mach_port_deallocate(mach_task_self(), server_priv_port);
2039 mach_port_deallocate(mach_task_self(), service_send_port);
2040 return status;
2041 }
2042 assert(service_send_port == service_rcv_port);
2043 }
2044
2045 /*
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.
2050 */
2051 mach_port_destroy(mach_task_self(), service_rcv_port);
2052 return status;
2053 }
2054
2055 mDNSlocal kern_return_t destroyBootstrapService()
2056 {
2057 debugf("Destroying Bootstrap Service");
2058 return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
2059 }
2060
2061 mDNSlocal void ExitCallback(int signal)
2062 {
2063 #if 0
2064 CacheRecord *rr;
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);
2068 #endif
2069
2070 LogMsgIdent(mDNSResponderVersionString, "stopping");
2071
2072 debugf("ExitCallback: destroyBootstrapService");
2073 if (!mDNS_DebugMode && signal != SIGHUP)
2074 destroyBootstrapService();
2075
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);
2085
2086 debugf("ExitCallback: mDNS_Close");
2087 mDNS_Close(&mDNSStorage);
2088 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2089 exit(0);
2090 }
2091
2092 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2093 mDNSlocal void HandleSIG(int signal)
2094 {
2095 debugf(" ");
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)
2104 {
2105 LogMsg("HandleSIG %d: mach_msg_send failed", signal);
2106 if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1);
2107 }
2108 }
2109
2110 mDNSlocal void INFOCallback(void)
2111 {
2112 DNSServiceDomainEnumeration *e;
2113 DNSServiceBrowser *b;
2114 DNSServiceResolver *l;
2115 DNSServiceRegistration *r;
2116 NetworkInterfaceInfoOSX *i;
2117
2118 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
2119
2120 udsserver_info(&mDNSStorage);
2121
2122 for (e = DNSServiceDomainEnumerationList; e; e=e->next)
2123 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
2124
2125 for (b = DNSServiceBrowserList; b; b=b->next)
2126 {
2127 DNSServiceBrowserQuestion *qptr;
2128 for (qptr = b->qlist; qptr; qptr = qptr->next)
2129 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c);
2130 }
2131 for (l = DNSServiceResolverList; l; l=l->next)
2132 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
2133
2134 for (r = DNSServiceRegistrationList; r; r=r->next)
2135 {
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));
2139 }
2140
2141 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
2142 {
2143 if (!i->Exists)
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);
2146 else
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" : " ",
2155 &i->ifinfo.ip);
2156 }
2157
2158 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
2159 }
2160
2161 mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
2162 {
2163 (void)port; // Unused
2164 (void)size; // Unused
2165 (void)info; // Unused
2166 mach_msg_header_t *m = (mach_msg_header_t *)msg;
2167 switch(m->msgh_id)
2168 {
2169 case SIGHUP:
2170 case SIGINT:
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;
2176 }
2177 }
2178
2179 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
2180 {
2181 mStatus err;
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);
2191
2192 if (status)
2193 {
2194 if (status == 1103)
2195 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2196 else
2197 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
2198 return(status);
2199 }
2200
2201 err = mDNS_Init(&mDNSStorage, &PlatformStorage,
2202 rrcachestorage, RR_CACHE_SIZE,
2203 mDNS_Init_AdvertiseLocalAddresses,
2204 mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
2205
2206 if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
2207
2208 client_death_port = CFMachPortGetPort(d_port);
2209 signal_port = CFMachPortGetPort(i_port);
2210
2211 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
2212 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
2213 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
2214 CFRelease(d_rls);
2215 CFRelease(s_rls);
2216 CFRelease(i_rls);
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; }
2220 return(err);
2221 }
2222
2223 mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
2224 {
2225 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
2226 mDNSs32 nextevent = mDNS_Execute(m);
2227
2228 mDNSs32 now = mDNS_TimeNow(m);
2229
2230 // 2. Deliver any waiting browse messages to clients
2231 DNSServiceBrowser *b = DNSServiceBrowserList;
2232
2233 while (b)
2234 {
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;
2239 b = b->next;
2240 if (x->results) // Try to deliver the list of results
2241 {
2242 while (x->results)
2243 {
2244 DNSServiceBrowserResult *const r = x->results;
2245 domainlabel name;
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)
2258 {
2259 if (nextevent - now > mDNSPlatformOneSecond)
2260 nextevent = now + mDNSPlatformOneSecond;
2261 break;
2262 }
2263 else
2264 {
2265 x->lastsuccess = now;
2266 x->results = x->results->next;
2267 freeL("DNSServiceBrowserResult", r);
2268 }
2269 }
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);
2273 }
2274 }
2275
2276 DNSServiceResolver *l;
2277 for (l = DNSServiceResolverList; l; l=l->next)
2278 if (l->ReportTime && now - l->ReportTime >= 0)
2279 {
2280 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);
2283 }
2284
2285 if (m->p->NotifyUser)
2286 {
2287 if (m->p->NotifyUser - now < 0)
2288 {
2289 if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c))
2290 {
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
2295 }
2296 if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c))
2297 {
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."));
2301 }
2302 m->p->NotifyUser = 0;
2303 }
2304 else
2305 if (nextevent - m->p->NotifyUser > 0)
2306 nextevent = m->p->NotifyUser;
2307 }
2308
2309 if (m->p->NetworkChanged)
2310 {
2311 if (m->p->NetworkChanged - now < 0)
2312 {
2313 m->p->NetworkChanged = 0;
2314 mDNSMacOSXNetworkChanged(m);
2315 }
2316 else
2317 if (nextevent - m->p->NetworkChanged > 0)
2318 nextevent = m->p->NetworkChanged;
2319 }
2320
2321 return(nextevent);
2322 }
2323
2324 mDNSexport int main(int argc, char **argv)
2325 {
2326 int i;
2327 kern_return_t status;
2328
2329 for (i=1; i<argc; i++)
2330 {
2331 if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
2332 }
2333
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
2340
2341 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2342 if (!mDNS_DebugMode) registerBootstrapService();
2343
2344 if (!mDNS_DebugMode && !restarting_via_mach_init)
2345 exit(0); /* mach_init will restart us immediately as a daemon */
2346
2347 if (!mDNS_DebugMode)
2348 {
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));
2351 else
2352 {
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);
2358 }
2359 }
2360
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();
2364
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");
2368 if (pw != NULL)
2369 setuid(pw->pw_uid);
2370 else
2371 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2372 #endif
2373
2374 if (status == 0)
2375 {
2376 LogMsg("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
2377 int numevents = 0;
2378 int RunLoopStatus = kCFRunLoopRunTimedOut;
2379
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)
2387 {
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);
2392
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
2396 if (ticks > 1)
2397 RepeatedBusy = 0;
2398 else
2399 {
2400 ticks = 1;
2401 if (++RepeatedBusy >= mDNSPlatformOneSecond * 10)
2402 { LogMsg("Task Scheduling Error: Continuously busy for the last ten seconds"); RepeatedBusy = 0; }
2403 }
2404 CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
2405
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);
2411 numevents = 0;
2412 RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
2413
2414 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2415 while (RunLoopStatus == kCFRunLoopRunHandledSource)
2416 {
2417 numevents++;
2418 RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
2419 }
2420 }
2421
2422 LogMsg("ERROR: CFRunLoopRun Exiting.");
2423 mDNS_Close(&mDNSStorage);
2424 }
2425
2426 if (!mDNS_DebugMode) destroyBootstrapService();
2427
2428 return(status);
2429 }
2430
2431 // uds_daemon.c support routines /////////////////////////////////////////////
2432
2433 // We keep a list of client-supplied event sources in PosixEventSource records
2434 struct CFSocketEventSource
2435 {
2436 udsEventCallback Callback;
2437 void *Context;
2438 int fd;
2439 struct CFSocketEventSource *Next;
2440 CFSocketRef cfs;
2441 CFRunLoopSourceRef RLS;
2442 };
2443 typedef struct CFSocketEventSource CFSocketEventSource;
2444
2445 static GenLinkedList gEventSources; // linked list of CFSocketEventSource's
2446
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
2449 {
2450 (void)s; // Unused
2451 (void)t; // Unused
2452 (void)dr; // Unused
2453 (void)c; // Unused
2454 CFSocketEventSource *source = (CFSocketEventSource*) i;
2455 source->Callback(source->Context);
2456 }
2457
2458 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
2459 // Arrange things so that callback is called with context when data appears on fd
2460 {
2461 CFSocketEventSource *newSource;
2462 CFSocketContext cfContext = { 0, NULL, NULL, NULL, NULL };
2463
2464 if (gEventSources.LinkOffset == 0)
2465 InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
2466
2467 if (fd >= FD_SETSIZE || fd < 0)
2468 return mStatus_UnsupportedErr;
2469 if (callback == NULL)
2470 return mStatus_BadParamErr;
2471
2472 newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource);
2473 if (NULL == newSource)
2474 return mStatus_NoMemoryErr;
2475
2476 newSource->Callback = callback;
2477 newSource->Context = context;
2478 newSource->fd = fd;
2479
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)))
2484 {
2485 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
2486 AddToTail(&gEventSources, newSource);
2487 }
2488 else
2489 {
2490 if (newSource->cfs)
2491 {
2492 CFSocketInvalidate(newSource->cfs); // automatically closes socket
2493 CFRelease(newSource->cfs);
2494 }
2495 return mStatus_NoMemoryErr;
2496 }
2497
2498 return mStatus_NoError;
2499 }
2500
2501 mStatus udsSupportRemoveFDFromEventLoop(int fd)
2502 // Reverse what was done in udsSupportAddFDToEventLoop().
2503 {
2504 CFSocketEventSource *iSource;
2505
2506 for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
2507 {
2508 if (fd == iSource->fd)
2509 {
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);
2516 free(iSource);
2517 return mStatus_NoError;
2518 }
2519 }
2520 return mStatus_NoSuchNameErr;
2521 }
2522
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");
2526
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__ ")";