]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/daemon.c
mDNSResponder-108.2.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.255.2.1 2005/07/22 21:45:04 ksekar
40 Fix GCC 4.0/Intel compiler warnings
41
42 Revision 1.255 2005/03/09 00:48:43 cheshire
43 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
44 Move "m->p->NetworkChanged = 0;" line from caller to callee
45
46 Revision 1.254 2005/03/03 04:34:19 cheshire
47 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
48
49 Revision 1.253 2005/03/03 03:55:09 cheshire
50 <rdar://problem/3862944> Name collision notifications should be localized
51
52 Revision 1.252 2005/02/23 02:29:17 cheshire
53 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
54 Minor refinements, better variable names, improved comments
55
56 Revision 1.251 2005/02/21 21:31:24 ksekar
57 <rdar://problem/4015162> changed LogMsg to debugf
58
59 Revision 1.250 2005/02/19 01:25:04 cheshire
60 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
61 Further refinements
62
63 Revision 1.249 2005/02/19 00:28:45 cheshire
64 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
65
66 Revision 1.248 2005/02/19 00:18:34 cheshire
67 Confusing variable name -- alertMessage should be called alertHeader
68
69 Revision 1.247 2005/02/15 02:13:49 cheshire
70 If we did registerBootstrapService() when starting, then we must do
71 destroyBootstrapService() before exiting, or Mach init will keep restarting us.
72
73 Revision 1.246 2005/02/03 00:44:37 cheshire
74 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
75
76 Revision 1.245 2005/02/01 19:56:47 ksekar
77 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
78
79 Revision 1.244 2005/01/28 00:34:49 cheshire
80 Turn off "Starting time value" log message
81
82 Revision 1.243 2005/01/27 17:46:58 cheshire
83 Added comment about CFSocketInvalidate closing the underlying socket
84
85 Revision 1.242 2005/01/27 00:10:58 cheshire
86 <rdar://problem/3967867> Name change log messages every time machine boots
87
88 Revision 1.241 2005/01/25 17:28:06 ksekar
89 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
90
91 Revision 1.240 2005/01/21 02:39:18 cheshire
92 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
93
94 Revision 1.239 2005/01/20 00:25:01 cheshire
95 Improve validatelists() log message generation
96
97 Revision 1.238 2005/01/19 19:15:35 ksekar
98 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
99
100 Revision 1.237 2005/01/19 03:33:09 cheshire
101 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
102
103 Revision 1.236 2005/01/19 03:16:38 cheshire
104 <rdar://problem/3961051> CPU Spin in mDNSResponder
105 Improve detail of "Task Scheduling Error" diagnostic messages
106
107 Revision 1.235 2005/01/15 00:56:41 ksekar
108 <rdar://problem/3954575> Unicast services don't disappear when logging
109 out of VPN
110
111 Revision 1.234 2005/01/10 03:42:30 ksekar
112 Clarify debugf
113
114 Revision 1.233 2004/12/18 00:53:46 cheshire
115 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
116
117 Revision 1.232 2004/12/17 23:37:48 cheshire
118 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
119 (and other repetitive configuration changes)
120
121 Revision 1.231 2004/12/17 04:13:38 cheshire
122 Removed debugging check
123
124 Revision 1.230 2004/12/17 04:09:30 cheshire
125 <rdar://problem/3191011> Switch mDNSResponder to launchd
126
127 Revision 1.229 2004/12/16 21:51:36 cheshire
128 Remove some startup messages
129
130 Revision 1.228 2004/12/16 20:13:01 cheshire
131 <rdar://problem/3324626> Cache memory management improvements
132
133 Revision 1.227 2004/12/10 13:52:57 cheshire
134 <rdar://problem/3909995> Turn off SIGPIPE signals
135
136 Revision 1.226 2004/12/10 05:27:26 cheshire
137 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
138
139 Revision 1.225 2004/12/10 04:28:29 cheshire
140 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
141
142 Revision 1.224 2004/12/10 00:41:05 cheshire
143 Adjust alignment of log messages
144
145 Revision 1.223 2004/12/07 20:42:34 cheshire
146 Add explicit context parameter to mDNS_RemoveRecordFromService()
147
148 Revision 1.222 2004/12/06 21:15:23 ksekar
149 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
150
151 Revision 1.221 2004/11/30 03:24:04 cheshire
152 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
153
154 Revision 1.220 2004/11/29 23:34:31 cheshire
155 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
156 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
157 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
158
159 Revision 1.219 2004/11/25 01:00:56 cheshire
160 Checkin 1.217 not necessary
161
162 Revision 1.218 2004/11/24 20:27:19 cheshire
163 Add missing "err" parameter in LogMsg() call
164
165 Revision 1.217 2004/11/24 17:55:01 ksekar
166 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
167
168 Revision 1.216 2004/11/24 00:10:44 cheshire
169 <rdar://problem/3869241> For unicast operations, verify that service types are legal
170
171 Revision 1.215 2004/11/23 22:33:01 cheshire
172 <rdar://problem/3654910> Remove temporary workaround code for iChat
173
174 Revision 1.214 2004/11/23 22:13:59 cheshire
175 <rdar://problem/3886293> Subtype advertising broken for Mach API
176
177 Revision 1.213 2004/11/23 06:12:55 cheshire
178 <rdar://problem/3871405> Update wording for name conflict dialogs
179
180 Revision 1.212 2004/11/23 05:15:37 cheshire
181 <rdar://problem/3875830> Computer Name in use message garbled
182
183 Revision 1.211 2004/11/23 05:00:41 cheshire
184 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
185
186 Revision 1.210 2004/11/03 03:45:17 cheshire
187 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
188
189 Revision 1.209 2004/11/03 02:25:50 cheshire
190 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
191
192 Revision 1.208 2004/11/03 01:54:14 cheshire
193 Update debugging messages
194
195 Revision 1.207 2004/11/02 23:58:19 cheshire
196 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
197
198 Revision 1.206 2004/10/28 02:40:47 cheshire
199 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
200
201 Revision 1.205 2004/10/28 02:21:01 cheshire
202 <rdar://problem/3856500> Improve mDNSResponder signal handling
203 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
204 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
205
206 Revision 1.204 2004/10/27 01:57:21 cheshire
207 Add check of m->p->InterfaceList
208
209 Revision 1.203 2004/10/26 04:31:44 cheshire
210 Rename CountSubTypes() as ChopSubTypes()
211
212 Revision 1.202 2004/10/26 01:29:18 cheshire
213 Use "#if 0" instead of commenting out code
214
215 Revision 1.201 2004/10/25 21:41:39 ksekar
216 <rdar://problem/3852958> wide-area name conflicts can cause crash
217
218 Revision 1.200 2004/10/22 01:03:55 cheshire
219 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
220 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
221
222 Revision 1.199 2004/10/19 21:33:19 cheshire
223 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
224 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
225 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
226
227 Revision 1.198 2004/10/15 23:00:18 ksekar
228 <rdar://problem/3799242> Need to update LLQs on location changes
229
230 Revision 1.197 2004/10/12 23:38:59 ksekar
231 <rdar://problem/3837065> remove unnecessary log message
232
233 Revision 1.196 2004/10/04 05:56:04 cheshire
234 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
235
236 Revision 1.195 2004/09/30 00:24:59 ksekar
237 <rdar://problem/3695802> Dynamically update default registration domains on config change
238
239 Revision 1.194 2004/09/26 23:20:35 ksekar
240 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
241
242 Revision 1.193 2004/09/23 23:35:27 cheshire
243 Update error message
244
245 Revision 1.192 2004/09/21 23:40:12 ksekar
246 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
247
248 Revision 1.191 2004/09/21 21:05:12 cheshire
249 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
250 into mDNSShared/uds_daemon.c
251
252 Revision 1.190 2004/09/21 19:51:15 cheshire
253 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
254
255 Revision 1.189 2004/09/21 18:17:23 cheshire
256 <rdar://problem/3785400> Add version info to mDNSResponder
257
258 Revision 1.188 2004/09/20 21:45:27 ksekar
259 Mach IPC cleanup
260
261 Revision 1.187 2004/09/17 01:08:52 cheshire
262 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
263 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
264 declared in that file are ONLY appropriate to single-address-space embedded applications.
265 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
266
267 Revision 1.186 2004/09/16 00:24:49 cheshire
268 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
269
270 Revision 1.185 2004/08/25 02:01:45 cheshire
271 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
272
273 Revision 1.184 2004/08/19 19:04:12 ksekar
274 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
275
276 Revision 1.183 2004/08/14 03:22:42 cheshire
277 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
278 Add GetUserSpecifiedDDNSName() routine
279 Convert ServiceRegDomain to domainname instead of C string
280 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
281
282 Revision 1.182 2004/08/13 23:57:59 cheshire
283 Get rid of non-portable "_UNUSED"
284
285 Revision 1.181 2004/08/11 02:02:26 cheshire
286 Remove "mDNS *globalInstance" parameter from udsserver_init();
287 Move CheckForDuplicateRegistrations to uds_daemon.c
288
289 Revision 1.180 2004/07/13 21:24:25 rpantos
290 Fix for <rdar://problem/3701120>.
291
292 Revision 1.179 2004/06/19 00:02:54 cheshire
293 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
294
295 Revision 1.178 2004/06/18 19:10:00 cheshire
296 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
297
298 Revision 1.177 2004/06/16 23:14:46 ksekar
299 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
300
301 Revision 1.176 2004/06/11 20:27:42 cheshire
302 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
303
304 Revision 1.175 2004/06/10 20:23:21 cheshire
305 Also list interfaces in SIGINFO output
306
307 Revision 1.174 2004/06/08 18:54:48 ksekar
308 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
309
310 Revision 1.173 2004/06/08 17:35:12 cheshire
311 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
312
313 Revision 1.172 2004/06/05 00:04:26 cheshire
314 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
315
316 Revision 1.171 2004/06/04 08:58:30 ksekar
317 <rdar://problem/3668624>: Keychain integration for secure dynamic update
318
319 Revision 1.170 2004/05/30 20:01:50 ksekar
320 <rdar://problem/3668635>: wide-area default registrations should be in
321 .local too - fixed service registration when clients pass an explicit
322 domain (broken by previous checkin)
323
324 Revision 1.169 2004/05/30 01:30:16 ksekar
325 <rdar://problem/3668635>: wide-area default registrations should be in
326 .local too
327
328 Revision 1.168 2004/05/18 23:51:26 cheshire
329 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
330
331 Revision 1.167 2004/05/14 16:39:47 ksekar
332 Browse for iChat locally for now.
333
334 Revision 1.166 2004/05/13 21:33:52 ksekar
335 Clean up non-local registration control via config file. Force iChat
336 registrations to be local for now.
337
338 Revision 1.165 2004/05/13 04:54:20 ksekar
339 Unified list copy/free code. Added symetric list for
340
341 Revision 1.164 2004/05/12 22:03:08 ksekar
342 Made GetSearchDomainList a true platform-layer call (declaration moved
343 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
344 only on non-OSX platforms. Changed call to return a copy of the list
345 to avoid shared memory issues. Added a routine to free the list.
346
347 Revision 1.163 2004/05/12 02:03:25 ksekar
348 Non-local domains will only be browsed by default, and show up in
349 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
350
351 Revision 1.162 2004/04/14 23:09:29 ksekar
352 Support for TSIG signed dynamic updates.
353
354 Revision 1.161 2004/04/07 01:20:04 cheshire
355 Hash slot value should be unsigned
356
357 Revision 1.160 2004/04/06 19:51:24 cheshire
358 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
359 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
360
361 Revision 1.159 2004/04/03 01:36:55 cheshire
362 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
363 If "nobody" user doesn't exist, log a message and continue as "root"
364
365 Revision 1.158 2004/04/02 21:39:05 cheshire
366 Fix errors in comments
367
368 Revision 1.157 2004/03/19 18:49:10 ksekar
369 Increased size check in freeL() to account for LargeCacheRecord
370 structs larger than 8k
371
372 Revision 1.156 2004/03/19 18:19:19 ksekar
373 Fixed daemon.c to compile with malloc debugging turned on.
374
375 Revision 1.155 2004/03/13 01:57:34 ksekar
376 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
377
378 Revision 1.154 2004/03/12 08:42:47 cheshire
379 <rdar://problem/3548256>: Should not allow empty string for resolve domain
380
381 Revision 1.153 2004/03/12 08:08:51 cheshire
382 Update comments
383
384 Revision 1.152 2004/02/05 19:39:29 cheshire
385 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
386 so that all platforms get this functionality
387
388 Revision 1.151 2004/02/03 22:35:34 cheshire
389 <rdar://problem/3548256>: Should not allow empty string for resolve domain
390
391 Revision 1.150 2004/01/28 21:14:23 cheshire
392 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
393
394 Revision 1.149 2004/01/28 02:30:08 ksekar
395 Added default Search Domains to unicast browsing, controlled via
396 Networking sharing prefs pane. Stopped sending unicast messages on
397 every interface. Fixed unicast resolving via mach-port API.
398
399 Revision 1.148 2004/01/25 00:03:20 cheshire
400 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
401
402 Revision 1.147 2004/01/19 19:51:46 cheshire
403 Fix compiler error (mixed declarations and code) on some versions of Linux
404
405 Revision 1.146 2003/12/08 21:00:46 rpantos
406 Changes to support mDNSResponder on Linux.
407
408 Revision 1.145 2003/12/05 22:08:07 cheshire
409 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
410
411 Revision 1.144 2003/11/19 23:21:08 ksekar
412 <rdar://problem/3486646>: config change handler not called for dns-sd services
413
414 Revision 1.143 2003/11/14 21:18:32 cheshire
415 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
416 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
417
418 Revision 1.142 2003/11/08 22:18:29 cheshire
419 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
420
421 Revision 1.141 2003/11/07 02:30:57 cheshire
422 Also check per-slot cache use counts in SIGINFO state log
423
424 Revision 1.140 2003/10/21 19:58:26 cheshire
425 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
426
427 Revision 1.139 2003/10/21 00:10:18 rpantos
428 <rdar://problem/3409401>: mDNSResponder should not run as root
429
430 Revision 1.138 2003/10/07 20:16:58 cheshire
431 Shorten syslog message a bit
432
433 Revision 1.137 2003/09/23 02:12:43 cheshire
434 Also include port number in list of services registered via new UDS API
435
436 Revision 1.136 2003/09/23 02:07:25 cheshire
437 Include port number in DNSServiceRegistration START/STOP messages
438
439 Revision 1.135 2003/09/23 01:34:02 cheshire
440 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
441
442 Revision 1.134 2003/08/21 20:01:37 cheshire
443 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
444
445 Revision 1.133 2003/08/20 23:39:31 cheshire
446 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
447
448 Revision 1.132 2003/08/20 01:44:56 cheshire
449 Fix errors in LogOperation() calls (only used for debugging)
450
451 Revision 1.131 2003/08/19 05:39:43 cheshire
452 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
453
454 Revision 1.130 2003/08/16 03:39:01 cheshire
455 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
456
457 Revision 1.129 2003/08/15 20:16:03 cheshire
458 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
459 We want to avoid touching the rdata pages, so we don't page them in.
460 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
461 Moved this from the RData to the ResourceRecord object.
462 2. To avoid unnecessarily touching the rdata just to compare it,
463 compute a hash of the rdata and store the hash in the ResourceRecord object.
464
465 Revision 1.128 2003/08/14 19:30:36 cheshire
466 <rdar://problem/3378473> Include list of cache records in SIGINFO output
467
468 Revision 1.127 2003/08/14 02:18:21 cheshire
469 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
470
471 Revision 1.126 2003/08/12 19:56:25 cheshire
472 Update to APSL 2.0
473
474 Revision 1.125 2003/08/08 18:36:04 cheshire
475 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
476
477 Revision 1.124 2003/07/25 18:28:23 cheshire
478 Minor fix to error messages in syslog: Display string parameters with quotes
479
480 Revision 1.123 2003/07/23 17:45:28 cheshire
481 <rdar://problem/3339388> mDNSResponder leaks a bit
482 Don't allocate memory for the reply until after we've verified that the reply is valid
483
484 Revision 1.122 2003/07/23 00:00:04 cheshire
485 Add comments
486
487 Revision 1.121 2003/07/20 03:38:51 ksekar
488 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
489
490 Revision 1.120 2003/07/18 00:30:00 cheshire
491 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
492
493 Revision 1.119 2003/07/17 19:08:58 cheshire
494 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
495
496 Revision 1.118 2003/07/15 21:12:28 cheshire
497 Added extra debugging checks in validatelists() (not used in final shipping version)
498
499 Revision 1.117 2003/07/15 01:55:15 cheshire
500 <rdar://problem/3315777> Need to implement service registration with subtypes
501
502 Revision 1.116 2003/07/02 21:19:51 cheshire
503 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
504
505 Revision 1.115 2003/07/02 02:41:24 cheshire
506 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
507
508 Revision 1.114 2003/07/01 21:10:20 cheshire
509 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
510
511 Revision 1.113 2003/06/28 17:27:43 vlubet
512 <rdar://problem/3221246> Redirect standard input, standard output, and
513 standard error file descriptors to /dev/null just like any other
514 well behaved daemon
515
516 Revision 1.112 2003/06/25 23:42:19 ksekar
517 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
518 Reviewed by: Stuart Cheshire
519 Added files necessary to implement Unix domain sockets based enhanced
520 DNS-SD APIs, and integrated with existing Mach-port based daemon.
521
522 Revision 1.111 2003/06/11 01:02:43 cheshire
523 <rdar://problem/3287858> mDNSResponder binary compatibility
524 Make single binary that can run on both Jaguar and Panther.
525
526 Revision 1.110 2003/06/10 01:14:11 cheshire
527 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
528
529 Revision 1.109 2003/06/06 19:53:43 cheshire
530 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
531 (Global search-and-replace; no functional change to code execution.)
532
533 Revision 1.108 2003/06/06 14:08:06 cheshire
534 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
535
536 Revision 1.107 2003/05/29 05:44:55 cheshire
537 Minor fixes to log messages
538
539 Revision 1.106 2003/05/27 18:30:55 cheshire
540 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
541 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
542
543 Revision 1.105 2003/05/26 03:21:29 cheshire
544 Tidy up address structure naming:
545 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
546 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
547 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
548
549 Revision 1.104 2003/05/26 00:42:06 cheshire
550 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
551
552 Revision 1.103 2003/05/23 23:07:44 cheshire
553 <rdar://problem/3268199> Must not write to stderr when running as daemon
554
555 Revision 1.102 2003/05/22 01:32:31 cheshire
556 Fix typo in Log message format string
557
558 Revision 1.101 2003/05/22 00:26:55 cheshire
559 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
560 Modify error message to explain that this is technically legal, but may indicate a bug.
561
562 Revision 1.100 2003/05/21 21:02:24 ksekar
563 <rdar://problem/3247035>: Service should be prefixed
564 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
565 Mach message port to "com.apple.mDNSResponder.
566
567 Revision 1.99 2003/05/21 17:33:49 cheshire
568 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
569
570 Revision 1.98 2003/05/20 00:33:07 cheshire
571 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
572 SIGHUP now writes state summary to syslog
573
574 Revision 1.97 2003/05/08 00:19:08 cheshire
575 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
576
577 Revision 1.96 2003/05/07 22:10:46 cheshire
578 <rdar://problem/3250330> Add a few more error logging messages
579
580 Revision 1.95 2003/05/07 19:20:17 cheshire
581 <rdar://problem/3251391> Add version number to mDNSResponder builds
582
583 Revision 1.94 2003/05/07 00:28:18 cheshire
584 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
585
586 Revision 1.93 2003/05/06 00:00:49 cheshire
587 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
588
589 Revision 1.92 2003/04/04 20:38:57 cheshire
590 Add $Log header
591
592 */
593
594 #include <mach/mach.h>
595 #include <mach/mach_error.h>
596 #include <servers/bootstrap.h>
597 #include <sys/types.h>
598 #include <unistd.h>
599 #include <paths.h>
600 #include <fcntl.h>
601 #include <pwd.h>
602 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
603
604 #include "DNSServiceDiscoveryRequestServer.h"
605 #include "DNSServiceDiscoveryReply.h"
606
607 #include "DNSCommon.h"
608 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
609
610 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
611
612 #include "GenLinkedList.h"
613
614 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
615
616 //*************************************************************************************************************
617 // Macros
618
619 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
620 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
621 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
622 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
623 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
624
625 //*************************************************************************************************************
626 // Globals
627
628 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
629 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
630 static mDNS_PlatformSupport PlatformStorage;
631
632 // Start off with a default cache of 16K (about 100 records)
633 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
634 static CacheEntity rrcachestorage[RR_CACHE_SIZE];
635
636 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
637 static mach_port_t client_death_port = MACH_PORT_NULL;
638 static mach_port_t signal_port = MACH_PORT_NULL;
639 static mach_port_t server_priv_port = MACH_PORT_NULL;
640
641 // mDNS Mach Message Timeout, in milliseconds.
642 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
643 // fails to service its mach message queue, but long enough to give a well-written
644 // client a chance to service its mach message queue without getting cut off.
645 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
646 // even extra-slow clients a fair chance before we cut them off.
647 #define MDNS_MM_TIMEOUT 250
648
649 static int restarting_via_mach_init = 0;
650 static int started_via_launchdaemon = 0;
651
652 static int OSXVers;
653
654 //*************************************************************************************************************
655 // Active client list structures
656
657 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
658 struct DNSServiceDomainEnumeration_struct
659 {
660 DNSServiceDomainEnumeration *next;
661 mach_port_t ClientMachPort;
662 DNSQuestion dom; // Question asking for domains
663 DNSQuestion def; // Question asking for default domain
664 };
665
666 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
667 struct DNSServiceBrowserResult_struct
668 {
669 DNSServiceBrowserResult *next;
670 int resultType;
671 domainname result;
672 };
673
674 typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
675
676 typedef struct DNSServiceBrowserQuestion
677 {
678 struct DNSServiceBrowserQuestion *next;
679 DNSQuestion q;
680 domainname domain;
681 } DNSServiceBrowserQuestion;
682
683 struct DNSServiceBrowser_struct
684 {
685 DNSServiceBrowser *next;
686 mach_port_t ClientMachPort;
687 DNSServiceBrowserQuestion *qlist;
688 DNSServiceBrowserResult *results;
689 mDNSs32 lastsuccess;
690 mDNSBool DefaultDomain; // was the browse started on an explicit domain?
691 domainname type; // registration type
692 };
693
694 typedef struct DNSServiceResolver_struct DNSServiceResolver;
695 struct DNSServiceResolver_struct
696 {
697 DNSServiceResolver *next;
698 mach_port_t ClientMachPort;
699 ServiceInfoQuery q;
700 ServiceInfo i;
701 mDNSs32 ReportTime;
702 };
703
704 // A single registered service: ServiceRecordSet + bookkeeping
705 // Note that we duplicate some fields from parent DNSServiceRegistration object
706 // to facilitate cleanup, when instances and parent may be deallocated at different times.
707 typedef struct ServiceInstance
708 {
709 struct ServiceInstance *next;
710 mach_port_t ClientMachPort;
711 mDNSBool autoname; // Set if this name is tied to the Computer Name
712 mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name
713 domainlabel name;
714 domainname domain;
715 ServiceRecordSet srs;
716 // Don't add any fields after ServiceRecordSet.
717 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
718 } ServiceInstance;
719
720 // A client-created service. May reference several ServiceInstance objects if default
721 // settings cause registration in multiple domains.
722 typedef struct DNSServiceRegistration
723 {
724 struct DNSServiceRegistration *next;
725 mach_port_t ClientMachPort;
726 mDNSBool DefaultDomain;
727 mDNSBool autoname;
728 size_t rdsize;
729 int NumSubTypes;
730 char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
731 domainlabel name; // used only if autoname is false
732 domainname type;
733 mDNSIPPort port;
734 unsigned char txtinfo[1024];
735 size_t txt_len;
736 uint32_t NextRef;
737 ServiceInstance *regs;
738 } DNSServiceRegistration;
739
740 static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
741 static DNSServiceBrowser *DNSServiceBrowserList = NULL;
742 static DNSServiceResolver *DNSServiceResolverList = NULL;
743 static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
744
745 //*************************************************************************************************************
746 // General Utility Functions
747
748 #if MACOSX_MDNS_MALLOC_DEBUGGING
749
750 char _malloc_options[] = "AXZ";
751
752 mDNSlocal void validatelists(mDNS *const m)
753 {
754 DNSServiceDomainEnumeration *e;
755 DNSServiceBrowser *b;
756 DNSServiceResolver *l;
757 DNSServiceRegistration *r;
758 AuthRecord *rr;
759 CacheGroup *cg;
760 CacheRecord *cr;
761 DNSQuestion *q;
762 mDNSu32 slot;
763 NetworkInterfaceInfoOSX *i;
764
765 for (e = DNSServiceDomainEnumerationList; e; e=e->next)
766 if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
767 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort);
768
769 for (b = DNSServiceBrowserList; b; b=b->next)
770 if (b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
771 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b, b->ClientMachPort);
772
773 for (l = DNSServiceResolverList; l; l=l->next)
774 if (l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
775 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l, l->ClientMachPort);
776
777 for (r = DNSServiceRegistrationList; r; r=r->next)
778 if (r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
779 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
780
781 for (rr = m->ResourceRecords; rr; rr=rr->next)
782 {
783 if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
784 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
785 if (rr->resrec.name != &rr->namestorage)
786 LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
787 rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
788 }
789
790 for (rr = m->DuplicateRecords; rr; rr=rr->next)
791 if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
792 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
793
794 for (q = m->Questions; q; q=q->next)
795 if (q->ThisQInterval == (mDNSs32)~0)
796 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
797
798 FORALL_CACHERECORDS(slot, cg, cr)
799 if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
800 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
801
802 for (i = m->p->InterfaceList; i; i = i->next)
803 if (!i->ifa_name)
804 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i);
805 }
806
807 void *mallocL(char *msg, unsigned int size)
808 {
809 unsigned long *mem = malloc(size+8);
810 if (!mem)
811 {
812 LogMsg("malloc( %s : %d ) failed", msg, size);
813 return(NULL);
814 }
815 else
816 {
817 LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
818 mem[0] = 0xDEAD1234;
819 mem[1] = size;
820 //bzero(&mem[2], size);
821 memset(&mem[2], 0xFF, size);
822 validatelists(&mDNSStorage);
823 return(&mem[2]);
824 }
825 }
826
827 void freeL(char *msg, void *x)
828 {
829 if (!x)
830 LogMsg("free( %s @ NULL )!", msg);
831 else
832 {
833 unsigned long *mem = ((unsigned long *)x) - 2;
834 if (mem[0] != 0xDEAD1234)
835 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
836 if (mem[1] > 24000)
837 { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
838 LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
839 //bzero(mem, mem[1]+8);
840 memset(mem, 0xFF, mem[1]+8);
841 validatelists(&mDNSStorage);
842 free(mem);
843 }
844 }
845
846 #endif
847
848 //*************************************************************************************************************
849 // Client Death Detection
850
851 mDNSlocal void FreeServiceInstance(ServiceInstance *x)
852 {
853 ServiceRecordSet *s = &x->srs;
854 ExtraResourceRecord *e = x->srs.Extras, *tmp;
855
856 while(e)
857 {
858 e->r.RecordContext = e;
859 tmp = e;
860 e = e->next;
861 FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
862 }
863
864 if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
865 freeL("TXT RData", s->RR_TXT.resrec.rdata);
866
867 if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
868 freeL("ServiceInstance", x);
869 }
870
871 // AbortClient finds whatever client is identified by the given Mach port,
872 // stops whatever operation that client was doing, and frees its memory.
873 // In the case of a service registration, the actual freeing may be deferred
874 // until we get the mStatus_MemFree message, if necessary
875 mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
876 {
877 DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList;
878 DNSServiceBrowser **b = &DNSServiceBrowserList;
879 DNSServiceResolver **l = &DNSServiceResolverList;
880 DNSServiceRegistration **r = &DNSServiceRegistrationList;
881
882 while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next;
883 if (*e)
884 {
885 DNSServiceDomainEnumeration *x = *e;
886 *e = (*e)->next;
887 if (m && m != x)
888 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->dom.qname.c, m, x);
889 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort, x->dom.qname.c);
890 mDNS_StopGetDomains(&mDNSStorage, &x->dom);
891 mDNS_StopGetDomains(&mDNSStorage, &x->def);
892 freeL("DNSServiceDomainEnumeration", x);
893 return;
894 }
895
896 while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
897 if (*b)
898 {
899 DNSServiceBrowser *x = *b;
900 DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist;
901 *b = (*b)->next;
902 while (qptr)
903 {
904 if (m && m != x)
905 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
906 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c);
907 mDNS_StopBrowse(&mDNSStorage, &qptr->q);
908 freePtr = qptr;
909 qptr = qptr->next;
910 freeL("DNSServiceBrowserQuestion", freePtr);
911 }
912 while (x->results)
913 {
914 DNSServiceBrowserResult *r = x->results;
915 x->results = x->results->next;
916 freeL("DNSServiceBrowserResult", r);
917 }
918 freeL("DNSServiceBrowser", x);
919 return;
920 }
921
922 while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next;
923 if (*l)
924 {
925 DNSServiceResolver *x = *l;
926 *l = (*l)->next;
927 if (m && m != x)
928 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
929 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort, x->i.name.c);
930 mDNS_StopResolveService(&mDNSStorage, &x->q);
931 freeL("DNSServiceResolver", x);
932 return;
933 }
934
935 while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
936 if (*r)
937 {
938 ServiceInstance *si = NULL;
939 DNSServiceRegistration *x = *r;
940 *r = (*r)->next;
941
942 si = x->regs;
943 while (si)
944 {
945 ServiceInstance *instance = si;
946 si = si->next;
947 instance->autorename = mDNSfalse;
948 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);
949 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
950
951 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
952 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
953 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
954 // the list, so we should go ahead and free the memory right now
955 if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
956 }
957 x->regs = NULL;
958 freeL("DNSServiceRegistration", x);
959 return;
960 }
961
962 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort);
963 }
964
965 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
966
967 mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m)
968 {
969 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
970 DNSServiceBrowser *b = DNSServiceBrowserList;
971 DNSServiceResolver *l = DNSServiceResolverList;
972 DNSServiceRegistration *r = DNSServiceRegistrationList;
973 DNSServiceBrowserQuestion *qptr;
974
975 while (e && e->ClientMachPort != c) e = e->next;
976 while (b && b->ClientMachPort != c) b = b->next;
977 while (l && l->ClientMachPort != c) l = l->next;
978 while (r && r->ClientMachPort != c) r = r->next;
979 if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
980 else if (b)
981 {
982 for (qptr = b->qlist; qptr; qptr = qptr->next)
983 LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
984 }
985 else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
986 else if (r)
987 {
988 ServiceInstance *si;
989 for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
990 }
991 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
992
993 AbortClient(c, m);
994 }
995
996 mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
997 {
998 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
999 DNSServiceBrowser *b = DNSServiceBrowserList;
1000 DNSServiceResolver *l = DNSServiceResolverList;
1001 DNSServiceRegistration *r = DNSServiceRegistrationList;
1002 DNSServiceBrowserQuestion *qptr;
1003
1004 while (e && e->ClientMachPort != c) e = e->next;
1005 while (b && b->ClientMachPort != c) b = b->next;
1006 while (l && l->ClientMachPort != c) l = l->next;
1007 while (r && r->ClientMachPort != c) r = r->next;
1008 if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c);
1009 if (b)
1010 {
1011 for (qptr = b->qlist; qptr; qptr = qptr->next)
1012 LogMsg("%5d: Browser(%##s) already exists!", c, qptr->q.qname.c);
1013 }
1014 if (l) LogMsg("%5d: Resolver(%##s) already exists!", c, l->i.name.c);
1015 if (r) LogMsg("%5d: Registration(%##s) already exists!", c, r->regs ? r->regs->srs.RR_SRV.resrec.name->c : NULL);
1016 return(e || b || l || r);
1017 }
1018
1019 mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
1020 {
1021 mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
1022 (void)unusedport; // Unused
1023 (void)size; // Unused
1024 (void)info; // Unused
1025 if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME)
1026 {
1027 const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg;
1028 AbortClient(deathMessage->not_port, NULL);
1029
1030 /* Deallocate the send right that came in the dead name notification */
1031 mach_port_destroy(mach_task_self(), deathMessage->not_port);
1032 }
1033 }
1034
1035 mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
1036 {
1037 mach_port_t prev;
1038 kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0,
1039 client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
1040 // If the port already died while we were thinking about it, then abort the operation right away
1041 if (r != KERN_SUCCESS)
1042 AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
1043 }
1044
1045 //*************************************************************************************************************
1046 // Domain Enumeration
1047
1048 mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1049 {
1050 kern_return_t status;
1051 #pragma unused(m)
1052 char buffer[MAX_ESCAPED_DOMAIN_NAME];
1053 DNSServiceDomainEnumerationReplyResultType rt;
1054 DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
1055
1056 debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
1057 if (answer->rrtype != kDNSType_PTR) return;
1058 if (!x) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1059
1060 if (AddRecord)
1061 {
1062 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain;
1063 else rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
1064 }
1065 else
1066 {
1067 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain;
1068 else return;
1069 }
1070
1071 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1072 x->ClientMachPort, x->dom.qname.c, answer->rdata->u.name.c,
1073 !AddRecord ? "RemoveDomain" :
1074 question == &x->dom ? "AddDomain" : "AddDomainDefault");
1075
1076 ConvertDomainNameToCString(&answer->rdata->u.name, buffer);
1077 status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, buffer, 0, MDNS_MM_TIMEOUT);
1078 if (status == MACH_SEND_TIMED_OUT)
1079 AbortBlockedClient(x->ClientMachPort, "enumeration", x);
1080 }
1081
1082 mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1083 int regDom)
1084 {
1085 // Check client parameter
1086 (void)unusedserver; // Unused
1087 mStatus err = mStatus_NoError;
1088 const char *errormsg = "Unknown";
1089 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1090 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1091
1092 mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
1093 mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
1094
1095 // Allocate memory, and handle failure
1096 DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
1097 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1098
1099 // Set up object, and link into list
1100 x->ClientMachPort = client;
1101 x->next = DNSServiceDomainEnumerationList;
1102 DNSServiceDomainEnumerationList = x;
1103
1104 verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
1105
1106 // Do the operation
1107 err = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
1108 if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
1109 if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
1110
1111 // Succeeded: Wrap up and return
1112 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c);
1113 EnableDeathNotificationForClient(client, x);
1114 return(mStatus_NoError);
1115
1116 fail:
1117 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err);
1118 return(err);
1119 }
1120
1121 //*************************************************************************************************************
1122 // Browse for services
1123
1124 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1125 {
1126 (void)m; // Unused
1127
1128 if (answer->rrtype != kDNSType_PTR)
1129 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
1130
1131 domainlabel name;
1132 domainname type, domain;
1133 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
1134 {
1135 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1136 answer->name->c, answer->rdata->u.name.c);
1137 return;
1138 }
1139
1140 DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
1141 if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
1142
1143 verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
1144 AssignDomainName(&x->result, &answer->rdata->u.name);
1145 if (AddRecord)
1146 x->resultType = DNSServiceBrowserReplyAddInstance;
1147 else x->resultType = DNSServiceBrowserReplyRemoveInstance;
1148 x->next = NULL;
1149
1150 DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext;
1151 DNSServiceBrowserResult **p = &browser->results;
1152 while (*p) p = &(*p)->next;
1153 *p = x;
1154 }
1155
1156 mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
1157 {
1158 mStatus err = mStatus_NoError;
1159 DNSServiceBrowserQuestion *ptr, *question = NULL;
1160
1161 for (ptr = browser->qlist; ptr; ptr = ptr->next)
1162 {
1163 if (SameDomainName(&ptr->q.qname, d))
1164 { debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; }
1165 }
1166
1167 question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
1168 if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
1169 AssignDomainName(&question->domain, d);
1170 question->next = browser->qlist;
1171 browser->qlist = question;
1172 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
1173 err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSInterface_Any, mDNSfalse, FoundInstance, browser);
1174 if (err) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
1175 return err;
1176 }
1177
1178 mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
1179 {
1180 DNSServiceBrowser *ptr;
1181
1182 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
1183 for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
1184 {
1185 if (ptr->DefaultDomain)
1186 {
1187 if (add)
1188 {
1189 mStatus err = AddDomainToBrowser(ptr, d);
1190 if (err && err != mStatus_AlreadyRegistered) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d, ptr->ClientMachPort);
1191 }
1192 else
1193 {
1194 DNSServiceBrowserQuestion **q = &ptr->qlist;
1195 while (*q)
1196 {
1197 if (SameDomainName(&(*q)->domain, d))
1198 {
1199 DNSServiceBrowserQuestion *remove = *q;
1200 *q = (*q)->next;
1201 if (remove->q.LongLived)
1202 {
1203 // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
1204 // we don't need to worry about the question being cancelled mid-loop
1205 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
1206 while (ka) { remove->q.QuestionCallback(&mDNSStorage, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
1207 }
1208 mDNS_StopBrowse(&mDNSStorage, &remove->q);
1209 freeL("DNSServiceBrowserQuestion", remove );
1210 return;
1211 }
1212 q = &(*q)->next;
1213 }
1214 LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
1215 }
1216 }
1217 }
1218 }
1219
1220 mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1221 DNSCString regtype, DNSCString domain)
1222 {
1223 // Check client parameter
1224 (void)unusedserver; // Unused
1225 mStatus err = mStatus_NoError;
1226 const char *errormsg = "Unknown";
1227 DNameListElem *SearchDomains = NULL, *sdPtr;
1228
1229 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1230 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1231
1232 // Check other parameters
1233 domainname t, d;
1234 t.c[0] = 0;
1235 mDNSs32 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
1236 if (NumSubTypes < 0 || NumSubTypes > 1) { errormsg = "Bad Service SubType"; goto badparam; }
1237 if (NumSubTypes == 1 && !AppendDNSNameString(&t, regtype + strlen(regtype) + 1))
1238 { errormsg = "Bad Service SubType"; goto badparam; }
1239 if (!regtype[0] || !AppendDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
1240 domainname temp;
1241 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
1242 if (temp.c[0] > 15 && (!domain || domain[0] == 0)) domain = "local."; // For over-long service types, we only allow domain "local"
1243
1244 // Allocate memory, and handle failure
1245 DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
1246 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1247
1248 // Set up object, and link into list
1249 AssignDomainName(&x->type, &t);
1250 x->ClientMachPort = client;
1251 x->results = NULL;
1252 x->lastsuccess = 0;
1253 x->qlist = NULL;
1254 x->next = DNSServiceBrowserList;
1255 DNSServiceBrowserList = x;
1256
1257 if (domain[0])
1258 {
1259 // Start browser for an explicit domain
1260 x->DefaultDomain = mDNSfalse;
1261 if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; }
1262 err = AddDomainToBrowser(x, &d);
1263 if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
1264 }
1265 else
1266 {
1267 // Start browser on all domains
1268 x->DefaultDomain = mDNStrue;
1269 SearchDomains = mDNSPlatformGetSearchDomainList();
1270 if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
1271 for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next)
1272 {
1273 err = AddDomainToBrowser(x, &sdPtr->name);
1274 if (err)
1275 {
1276 // only terminally bail if .local fails
1277 if (!SameDomainName(&localdomain, &sdPtr->name))
1278 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr->name.c);
1279 else { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
1280 }
1281 }
1282 }
1283
1284 // Succeeded: Wrap up and return
1285 EnableDeathNotificationForClient(client, x);
1286 mDNS_FreeDNameList(SearchDomains);
1287 return(mStatus_NoError);
1288
1289 badparam:
1290 err = mStatus_BadParamErr;
1291 fail:
1292 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
1293 if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
1294 return(err);
1295 }
1296
1297 //*************************************************************************************************************
1298 // Resolve Service Info
1299
1300 mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
1301 {
1302 kern_return_t status;
1303 DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
1304 NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)query->info->InterfaceID;
1305 if (query->info->InterfaceID == mDNSInterface_LocalOnly) ifx = mDNSNULL;
1306 struct sockaddr_storage interface;
1307 struct sockaddr_storage address;
1308 char cstring[1024];
1309 int i, pstrlen = query->info->TXTinfo[0];
1310 (void)m; // Unused
1311
1312 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1313
1314 if (query->info->TXTlen > sizeof(cstring)) return;
1315
1316 bzero(&interface, sizeof(interface));
1317 bzero(&address, sizeof(address));
1318
1319 if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
1320 {
1321 struct sockaddr_in *sin = (struct sockaddr_in*)&interface;
1322 sin->sin_len = sizeof(*sin);
1323 sin->sin_family = AF_INET;
1324 sin->sin_port = 0;
1325 sin->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
1326 }
1327 else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
1328 {
1329 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&interface;
1330 sin6->sin6_len = sizeof(*sin6);
1331 sin6->sin6_family = AF_INET6;
1332 sin6->sin6_flowinfo = 0;
1333 sin6->sin6_port = 0;
1334 sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
1335 sin6->sin6_scope_id = ifx->scope_id;
1336 }
1337
1338 if (query->info->ip.type == mDNSAddrType_IPv4)
1339 {
1340 struct sockaddr_in *sin = (struct sockaddr_in*)&address;
1341 sin->sin_len = sizeof(*sin);
1342 sin->sin_family = AF_INET;
1343 sin->sin_port = query->info->port.NotAnInteger;
1344 sin->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger;
1345 }
1346 else
1347 {
1348 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&address;
1349 sin6->sin6_len = sizeof(*sin6);
1350 sin6->sin6_family = AF_INET6;
1351 sin6->sin6_port = query->info->port.NotAnInteger;
1352 sin6->sin6_flowinfo = 0;
1353 sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
1354 sin6->sin6_scope_id = ifx ? ifx->scope_id : 0;
1355 }
1356
1357 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1358 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1359 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1360 // ASCII-1 characters are used in the C-string as boundary markers,
1361 // to indicate the boundaries between the original constituent P-strings.
1362 for (i=1; i<query->info->TXTlen; i++)
1363 {
1364 if (--pstrlen >= 0)
1365 cstring[i-1] = query->info->TXTinfo[i];
1366 else
1367 {
1368 cstring[i-1] = 1;
1369 pstrlen = query->info->TXTinfo[i];
1370 }
1371 }
1372 cstring[i-1] = 0; // Put the terminating NULL on the end
1373
1374 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort,
1375 x->i.name.c, &query->info->ip, mDNSVal16(query->info->port));
1376 status = DNSServiceResolverReply_rpc(x->ClientMachPort,
1377 (char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT);
1378 if (status == MACH_SEND_TIMED_OUT)
1379 AbortBlockedClient(x->ClientMachPort, "resolve", x);
1380 }
1381
1382 mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client,
1383 DNSCString name, DNSCString regtype, DNSCString domain)
1384 {
1385 // Check client parameter
1386 (void)unusedserver; // Unused
1387 mStatus err = mStatus_NoError;
1388 const char *errormsg = "Unknown";
1389 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1390 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1391
1392 // Check other parameters
1393 domainlabel n;
1394 domainname t, d, srv;
1395 if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
1396 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
1397 if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Bad Domain"; goto badparam; }
1398 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
1399
1400 // Allocate memory, and handle failure
1401 DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x));
1402 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1403
1404 // Set up object, and link into list
1405 x->ClientMachPort = client;
1406 x->i.InterfaceID = mDNSInterface_Any;
1407 x->i.name = srv;
1408 x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
1409 x->next = DNSServiceResolverList;
1410 DNSServiceResolverList = x;
1411
1412 // Do the operation
1413 LogOperation("%5d: DNSServiceResolver(%##s) START", client, x->i.name.c);
1414 err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
1415 if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
1416
1417 // Succeeded: Wrap up and return
1418 EnableDeathNotificationForClient(client, x);
1419 return(mStatus_NoError);
1420
1421 badparam:
1422 err = mStatus_BadParamErr;
1423 fail:
1424 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
1425 return(err);
1426 }
1427
1428 //*************************************************************************************************************
1429 // Registration
1430
1431 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
1432 {
1433 m->p->NotifyUser = NonZeroTime(m->timenow + delay);
1434 }
1435
1436 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
1437 {
1438 ServiceInstance *si = (ServiceInstance*)srs->ServiceContext;
1439
1440 if (result == mStatus_NoError)
1441 {
1442 kern_return_t status;
1443 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
1444 status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
1445 if (status == MACH_SEND_TIMED_OUT)
1446 AbortBlockedClient(si->ClientMachPort, "registration success", si);
1447 if (si->autoname && CountPeerRegistrations(m, srs) == 0)
1448 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
1449 }
1450
1451 else if (result == mStatus_NameConflict)
1452 {
1453 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
1454 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1455 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1456 if (si->autoname && CountPeerRegistrations(m, srs) == 0)
1457 {
1458 // On conflict for an autoname service, rename and reregister *all* autoname services
1459 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
1460 m->MainCallback(m, mStatus_ConfigChanged);
1461 }
1462 else if (si->autoname)
1463 {
1464 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
1465 return;
1466 }
1467 else
1468 {
1469 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1470 // of their registration in the usual way (which we will catch via client death notification).
1471 // If the Mach queue is full, we forcibly abort the client immediately.
1472 kern_return_t status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
1473 if (status == MACH_SEND_TIMED_OUT)
1474 AbortBlockedClient(si->ClientMachPort, "registration conflict", NULL);
1475 }
1476 }
1477
1478 else if (result == mStatus_MemFree)
1479 {
1480 if (si->autorename)
1481 {
1482 debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
1483 si->autorename = mDNSfalse;
1484 si->name = m->nicelabel;
1485 mDNS_RenameAndReregisterService(m, srs, &si->name);
1486 }
1487 else
1488 {
1489 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1490 DNSServiceRegistration *r;
1491 for (r = DNSServiceRegistrationList; r; r = r->next)
1492 {
1493 ServiceInstance *sp = r->regs, *prev = NULL;
1494 while (sp)
1495 {
1496 if (sp == si)
1497 {
1498 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name->c);
1499 if (prev) prev->next = sp->next;
1500 else r->regs = sp->next;
1501 break;
1502 }
1503 prev = sp;
1504 sp = sp->next;
1505 }
1506 }
1507 // END SANITY CHECK
1508 FreeServiceInstance(si);
1509 }
1510 }
1511
1512 else if (result != mStatus_NATTraversal)
1513 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
1514 }
1515
1516 mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
1517 {
1518 mStatus err = 0;
1519 ServiceInstance *si = NULL;
1520 AuthRecord *SubTypes = NULL;
1521
1522 for (si = x->regs; si; si = si->next)
1523 {
1524 if (SameDomainName(&si->domain, domain))
1525 { LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; }
1526 }
1527
1528 SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype);
1529 if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr;
1530
1531 si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
1532 if (!si) return mStatus_NoMemoryErr;
1533
1534 si->ClientMachPort = x->ClientMachPort;
1535 si->autorename = mDNSfalse;
1536 si->autoname = x->autoname;
1537 si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
1538 si->domain = *domain;
1539
1540 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);
1541 if (!err)
1542 {
1543 si->next = x->regs;
1544 x->regs = si;
1545 }
1546 else
1547 {
1548 LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
1549 freeL("ServiceInstance", si);
1550 }
1551 return err;
1552 }
1553
1554 mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
1555 {
1556 DNSServiceRegistration *reg;
1557
1558 for (reg = DNSServiceRegistrationList; reg; reg = reg->next)
1559 {
1560 if (reg->DefaultDomain)
1561 {
1562 if (add)
1563 {
1564 AddServiceInstance(reg, d);
1565 }
1566 else
1567 {
1568 ServiceInstance *si = reg->regs, *prev = NULL;
1569 while (si)
1570 {
1571 if (SameDomainName(&si->domain, d))
1572 {
1573 if (prev) prev->next = si->next;
1574 else reg->regs = si->next;
1575 if (mDNS_DeregisterService(&mDNSStorage, &si->srs))
1576 FreeServiceInstance(si); // only free memory synchronously on error
1577 break;
1578 }
1579 prev = si;
1580 si = si->next;
1581 }
1582 if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed
1583 }
1584 }
1585 }
1586 }
1587
1588 mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1589 DNSCString name, DNSCString regtype, DNSCString domain, IPPort IpPort, DNSCString txtRecord)
1590 {
1591 (void)unusedserver; // Unused
1592 mStatus err = mStatus_NoError;
1593 const char *errormsg = "Unknown";
1594
1595 // older versions of this code passed the port via mach IPC as an int.
1596 // we continue to pass it as 4 bytes to maintain binary compatibility,
1597 // but now ensure that the network byte order is preserved by using a struct
1598 mDNSIPPort port;
1599 port.b[0] = IpPort.bytes[2];
1600 port.b[1] = IpPort.bytes[3];
1601
1602 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1603 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1604
1605 // Check for sub-types after the service type
1606 size_t reglen = strlen(regtype) + 1;
1607 if (reglen > MAX_ESCAPED_DOMAIN_NAME) { errormsg = "reglen too long"; goto badparam; }
1608 mDNSs32 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
1609 if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; }
1610
1611 // Check other parameters
1612 domainlabel n;
1613 domainname t, d;
1614 domainname srv;
1615 if (!name[0]) n = mDNSStorage.nicelabel;
1616 else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
1617 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
1618 if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
1619 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
1620
1621 unsigned char txtinfo[1024] = "";
1622 unsigned int data_len = 0;
1623 unsigned int size = sizeof(RDataBody);
1624 unsigned char *pstring = &txtinfo[data_len];
1625 char *ptr = txtRecord;
1626
1627 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1628 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1629 // Hence we have to convert the C-string to a P-string.
1630 // ASCII-1 characters are allowed in the C-string as boundary markers,
1631 // so that a single C-string can be used to represent one or more P-strings.
1632 while (*ptr)
1633 {
1634 if (++data_len >= sizeof(txtinfo)) { errormsg = "TXT record too long"; goto badtxt; }
1635 if (*ptr == 1) // If this is our boundary marker, start a new P-string
1636 {
1637 pstring = &txtinfo[data_len];
1638 pstring[0] = 0;
1639 ptr++;
1640 }
1641 else
1642 {
1643 if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; }
1644 pstring[++pstring[0]] = *ptr++;
1645 }
1646 }
1647
1648 data_len++;
1649 if (size < data_len)
1650 size = data_len;
1651
1652 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1653 // a port number of zero. When two instances of the protected client are allowed to run on one
1654 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1655 if (port.NotAnInteger)
1656 {
1657 int count = CountExistingRegistrations(&srv, port);
1658 if (count)
1659 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1660 client, count+1, srv.c, mDNSVal16(port));
1661 }
1662
1663 // Allocate memory, and handle failure
1664 DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
1665 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1666 bzero(x, sizeof(*x));
1667
1668 // Set up object, and link into list
1669 x->ClientMachPort = client;
1670 x->DefaultDomain = !domain[0];
1671 x->autoname = (!name[0]);
1672 x->rdsize = size;
1673 x->NumSubTypes = NumSubTypes;
1674 memcpy(x->regtype, regtype, reglen);
1675 x->name = n;
1676 x->type = t;
1677 x->port = port;
1678 memcpy(x->txtinfo, txtinfo, 1024);
1679 x->txt_len = data_len;
1680 x->NextRef = 0;
1681 x->regs = NULL;
1682
1683 x->next = DNSServiceRegistrationList;
1684 DNSServiceRegistrationList = x;
1685
1686 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1687 x->ClientMachPort, name, regtype, domain, mDNSVal16(port));
1688
1689 err = AddServiceInstance(x, &d);
1690 if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; } // bail if .local (or explicit domain) fails
1691
1692 if (x->DefaultDomain)
1693 {
1694 DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList();
1695 for (ptr = regdomains; ptr; ptr = ptr->next)
1696 AddServiceInstance(x, &ptr->name);
1697 mDNS_FreeDNameList(regdomains);
1698 }
1699
1700 // Succeeded: Wrap up and return
1701 EnableDeathNotificationForClient(client, x);
1702 return(mStatus_NoError);
1703
1704 badtxt:
1705 LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
1706 badparam:
1707 err = mStatus_BadParamErr;
1708 fail:
1709 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1710 client, name, regtype, domain, mDNSVal16(port), errormsg, err);
1711 return(err);
1712 }
1713
1714 mDNSlocal CFUserNotificationRef gNotification = NULL;
1715 mDNSlocal CFRunLoopSourceRef gNotificationRLS = NULL;
1716 mDNSlocal domainlabel gNotificationPrefHostLabel; // The prefs as they were the last time we saw them
1717 mDNSlocal domainlabel gNotificationPrefNiceLabel;
1718 mDNSlocal domainlabel gNotificationUserHostLabel; // The prefs as they were the last time the user changed them
1719 mDNSlocal domainlabel gNotificationUserNiceLabel;
1720
1721 mDNSlocal void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
1722 {
1723 (void)responseFlags; // Unused
1724 if (userNotification != gNotification) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
1725 if (gNotificationRLS)
1726 {
1727 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
1728 CFRelease(gNotificationRLS);
1729 gNotificationRLS = NULL;
1730 CFRelease(gNotification);
1731 gNotification = NULL;
1732 }
1733 // By dismissing the alert, the user has conceptually acknowleged the rename.
1734 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
1735 // If we get *another* conflict, the new alert should refer to the 'old'.
1736 // name as now being "computer-2.local", not "computer.local"
1737 gNotificationUserHostLabel = gNotificationPrefHostLabel;
1738 gNotificationUserNiceLabel = gNotificationPrefNiceLabel;
1739 }
1740
1741 mDNSlocal void ShowNameConflictNotification(CFStringRef header, CFStringRef subtext)
1742 {
1743 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1744 if (!dictionary) return;
1745 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
1746 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
1747
1748 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
1749 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
1750
1751 if (gNotification) // If notification already on-screen, update it in place
1752 CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
1753 else // else, we need to create it
1754 {
1755 SInt32 error;
1756 gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
1757 if (!gNotification) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
1758 gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
1759 if (!gNotificationRLS) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
1760 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
1761 }
1762
1763 CFRelease(dictionary);
1764 }
1765
1766 // This updates either the text of the field currently labelled "Local Hostname",
1767 // or the text of the field currently labelled "Computer Name"
1768 // in the Sharing Prefs Control Panel
1769 mDNSlocal void RecordUpdatedName(const mDNS *const m, const domainlabel *const olddl, const domainlabel *const newdl,
1770 const char *const msg, const char *const suffix, const CFStringRef subtext)
1771 {
1772 char oldname[MAX_DOMAIN_LABEL+1];
1773 char newname[MAX_DOMAIN_LABEL+1];
1774 ConvertDomainLabelToCString_unescaped(olddl, oldname);
1775 ConvertDomainLabelToCString_unescaped(newdl, newname);
1776 const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
1777 const CFStringRef cfnewname = CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8);
1778 const CFStringRef f1 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
1779 const CFStringRef f2 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
1780 const SCPreferencesRef session = SCPreferencesCreate(NULL, CFSTR("mDNSResponder"), NULL);
1781 if (!cfoldname || !cfnewname || !f1 || !f2 || !session || !SCPreferencesLock(session, 0)) // If we can't get the lock don't wait
1782 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1783 else
1784 {
1785 const CFStringRef s0 = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
1786 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, f1, cfoldname, suffix);
1787 const CFStringRef s2 = CFStringCreateWithFormat(NULL, NULL, f2, cfnewname, suffix);
1788 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
1789 // element of the array individually for us, and then concatenate the results to make the final message.
1790 // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
1791 // On Panther this does not work, so we just build the string directly, and it will not be translated.
1792 const CFMutableStringRef alertHeader =
1793 (OSXVers < 8) ? CFStringCreateMutable(NULL, 0) : (CFMutableStringRef)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1794 Boolean result;
1795 if (newdl == &gNotificationPrefHostLabel) result = SCPreferencesSetLocalHostName(session, cfnewname);
1796 else result = SCPreferencesSetComputerName(session, cfnewname, kCFStringEncodingUTF8);
1797 if (!result || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session) || !s0 || !s1 || !s2 || !alertHeader)
1798 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1799 else if (m->p->NotifyUser)
1800 {
1801 uid_t uid;
1802 gid_t gid;
1803 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
1804 if (userName)
1805 {
1806 CFRelease(userName);
1807 typedef void CFStringAppendFN(CFMutableStringRef theString, CFStringRef appendedString);
1808 CFStringAppendFN *const append = (OSXVers < 8) ? &CFStringAppend : (CFStringAppendFN*)&CFArrayAppendValue;
1809 append(alertHeader, s0);
1810 append(alertHeader, s1);
1811 append(alertHeader, CFSTR("is already in use on this network."));
1812 append(alertHeader, CFSTR(" "));
1813 append(alertHeader, CFSTR("The name has been changed to"));
1814 append(alertHeader, s2);
1815 append(alertHeader, CFSTR("automatically."));
1816 ShowNameConflictNotification(alertHeader, subtext);
1817 }
1818 }
1819 if (s0) CFRelease(s0);
1820 if (s1) CFRelease(s1);
1821 if (s2) CFRelease(s2);
1822 if (alertHeader) CFRelease(alertHeader);
1823 SCPreferencesUnlock(session);
1824 }
1825 if (cfoldname) CFRelease(cfoldname);
1826 if (cfnewname) CFRelease(cfnewname);
1827 if (f1) CFRelease(f1);
1828 if (f2) CFRelease(f2);
1829 if (session) CFRelease(session);
1830 }
1831
1832 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
1833 {
1834 (void)m; // Unused
1835 if (result == mStatus_NoError)
1836 {
1837 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1838 RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond);
1839 }
1840 else if (result == mStatus_ConfigChanged)
1841 {
1842 // If the user-specified hostlabel from System Configuration has changed since the last time
1843 // we saw it, and *we* didn't change it, then that implies that the user has changed it,
1844 // so we auto-dismiss the name conflict alert.
1845 if (!SameDomainLabel(m->p->userhostlabel.c, gNotificationPrefHostLabel.c) ||
1846 !SameDomainLabel(m->p->usernicelabel.c, gNotificationPrefNiceLabel.c))
1847 {
1848 gNotificationUserHostLabel = gNotificationPrefHostLabel = m->p->userhostlabel;
1849 gNotificationUserNiceLabel = gNotificationPrefNiceLabel = m->p->usernicelabel;
1850 // If we're showing a name conflict notification, and the user has manually edited
1851 // the name to remedy the conflict, we should now remove the notification window.
1852 if (gNotificationRLS) CFUserNotificationCancel(gNotification);
1853 }
1854
1855 DNSServiceRegistration *r;
1856 for (r = DNSServiceRegistrationList; r; r=r->next)
1857 if (r->autoname)
1858 {
1859 ServiceInstance *si;
1860 for (si = r->regs; si; si = si->next)
1861 {
1862 if (!SameDomainLabel(si->name.c, m->nicelabel.c))
1863 {
1864 debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
1865 si->autorename = mDNStrue;
1866 if (mDNS_DeregisterService(m, &si->srs)) // If service deregistered already, we can re-register immediately
1867 RegCallback(m, &si->srs, mStatus_MemFree);
1868 }
1869 }
1870 }
1871 udsserver_handle_configchange();
1872 }
1873 else if (result == mStatus_GrowCache)
1874 {
1875 // Allocate another chunk of cache storage
1876 CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
1877 if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
1878 }
1879 }
1880
1881 //*************************************************************************************************************
1882 // Add / Update / Remove records from existing Registration
1883
1884 mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1885 int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
1886 {
1887 // Check client parameter
1888 uint32_t id;
1889 mStatus err = mStatus_NoError;
1890 const char *errormsg = "Unknown";
1891 DNSServiceRegistration *x = DNSServiceRegistrationList;
1892 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1893 ServiceInstance *si;
1894 size_t size;
1895 (void)unusedserver; // Unused
1896 while (x && x->ClientMachPort != client) x = x->next;
1897 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
1898
1899 // Check other parameters
1900 if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
1901 if (data_len > sizeof(RDataBody)) size = data_len;
1902 else size = sizeof(RDataBody);
1903
1904 id = x->NextRef++;
1905 *reference = (natural_t)id;
1906 for (si = x->regs; si; si = si->next)
1907 {
1908 // Allocate memory, and handle failure
1909 ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
1910 if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1911
1912 // Fill in type, length, and data of new record
1913 extra->r.resrec.rrtype = type;
1914 extra->r.rdatastorage.MaxRDLength = size;
1915 extra->r.resrec.rdlength = data_len;
1916 memcpy(&extra->r.rdatastorage.u.data, data, data_len);
1917
1918 // Do the operation
1919 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1920 client, si->srs.RR_SRV.resrec.name->c, type, data_len, extra);
1921 err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl);
1922
1923 if (err)
1924 {
1925 freeL("Extra Resource Record", extra);
1926 errormsg = "mDNS_AddRecordToService";
1927 goto fail;
1928 }
1929
1930 extra->ClientID = id;
1931 }
1932
1933 return mStatus_NoError;
1934
1935 fail:
1936 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x->name.c, type, data_len, errormsg, err);
1937 return mStatus_UnknownErr;
1938 }
1939
1940 mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
1941 {
1942 (void)m; // Unused
1943 if (OldRData != &rr->rdatastorage)
1944 freeL("Old RData", OldRData);
1945 }
1946
1947 mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRecord *rr, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
1948 {
1949 // Check client parameter
1950 mStatus err = mStatus_NoError;
1951 const char *errormsg = "Unknown";
1952 domainname *name = (domainname *)"";
1953
1954 name = srs->RR_SRV.resrec.name;
1955
1956 unsigned int size = sizeof(RDataBody);
1957 if (size < data_len)
1958 size = data_len;
1959
1960 // Allocate memory, and handle failure
1961 RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size);
1962 if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1963
1964 // Fill in new length, and data
1965 newrdata->MaxRDLength = size;
1966 memcpy(&newrdata->u, data, data_len);
1967
1968 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1969 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1970 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1971 if (rr->resrec.rrtype == kDNSType_TXT && data_len == 0) { data_len = 1; newrdata->u.txt.c[0] = 0; }
1972
1973 // Do the operation
1974 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1975 client, srs->RR_SRV.resrec.name->c, data_len);
1976
1977 err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
1978 if (err)
1979 {
1980 errormsg = "mDNS_Update";
1981 freeL("RData", newrdata);
1982 return err;
1983 }
1984 return(mStatus_NoError);
1985
1986 fail:
1987 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err);
1988 return(err);
1989 }
1990
1991 mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1992 natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
1993 {
1994 // Check client parameter
1995 mStatus err = mStatus_NoError;
1996 const char *errormsg = "Unknown";
1997 domainname *name = (domainname *)"";
1998 ServiceInstance *si;
1999
2000 (void)unusedserver; // unused
2001 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
2002 DNSServiceRegistration *x = DNSServiceRegistrationList;
2003 while (x && x->ClientMachPort != client) x = x->next;
2004 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
2005
2006 // Check other parameters
2007 if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
2008
2009 for (si = x->regs; si; si = si->next)
2010 {
2011 AuthRecord *r = NULL;
2012
2013 // Find the record we're updating. NULL reference means update the primary TXT record
2014 if (!reference) r = &si->srs.RR_TXT;
2015 else
2016 {
2017 ExtraResourceRecord *ptr;
2018 for (ptr = si->srs.Extras; ptr; ptr = ptr->next)
2019 {
2020 if ((natural_t)ptr->ClientID == reference)
2021 { r = &ptr->r; break; }
2022 }
2023 if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
2024 }
2025 err = UpdateRecord(&si->srs, client, r, data, data_len, ttl);
2026 if (err) goto fail; //!!!KRS this will cause failures for non-local defaults!
2027 }
2028
2029 return mStatus_NoError;
2030
2031 fail:
2032 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
2033 return(err);
2034 }
2035
2036 mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
2037 {
2038 domainname *name = srs->RR_SRV.resrec.name;
2039 mStatus err = mStatus_NoError;
2040
2041 // Do the operation
2042 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name->c);
2043
2044 err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
2045 if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
2046
2047 return err;
2048 }
2049
2050 mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
2051 natural_t reference)
2052 {
2053 // Check client parameter
2054 (void)unusedserver; // Unused
2055 mStatus err = mStatus_NoError;
2056 const char *errormsg = "Unknown";
2057 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
2058 DNSServiceRegistration *x = DNSServiceRegistrationList;
2059 ServiceInstance *si;
2060
2061 while (x && x->ClientMachPort != client) x = x->next;
2062 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
2063
2064 for (si = x->regs; si; si = si->next)
2065 {
2066 ExtraResourceRecord *e;
2067 for (e = si->srs.Extras; e; e = e->next)
2068 {
2069 if ((natural_t)e->ClientID == reference)
2070 {
2071 err = RemoveRecord(&si->srs, e, client);
2072 break;
2073 }
2074 }
2075 if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
2076 }
2077
2078 return mStatus_NoError;
2079
2080 fail:
2081 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
2082 return(err);
2083 }
2084
2085 //*************************************************************************************************************
2086 // Support Code
2087
2088 mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
2089 {
2090 mig_reply_error_t *request = msg;
2091 mig_reply_error_t *reply;
2092 mach_msg_return_t mr;
2093 int options;
2094 (void)port; // Unused
2095 (void)size; // Unused
2096 (void)info; // Unused
2097
2098 /* allocate a reply buffer */
2099 reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
2100
2101 /* call the MiG server routine */
2102 (void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head);
2103
2104 if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS))
2105 {
2106 if (reply->RetCode == MIG_NO_REPLY)
2107 {
2108 /*
2109 * This return code is a little tricky -- it appears that the
2110 * demux routine found an error of some sort, but since that
2111 * error would not normally get returned either to the local
2112 * user or the remote one, we pretend it's ok.
2113 */
2114 CFAllocatorDeallocate(NULL, reply);
2115 return;
2116 }
2117
2118 /*
2119 * destroy any out-of-line data in the request buffer but don't destroy
2120 * the reply port right (since we need that to send an error message).
2121 */
2122 request->Head.msgh_remote_port = MACH_PORT_NULL;
2123 mach_msg_destroy(&request->Head);
2124 }
2125
2126 if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
2127 {
2128 /* no reply port, so destroy the reply */
2129 if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
2130 mach_msg_destroy(&reply->Head);
2131 CFAllocatorDeallocate(NULL, reply);
2132 return;
2133 }
2134
2135 /*
2136 * send reply.
2137 *
2138 * We don't want to block indefinitely because the client
2139 * isn't receiving messages from the reply port.
2140 * If we have a send-once right for the reply port, then
2141 * this isn't a concern because the send won't block.
2142 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2143 * To avoid falling off the kernel's fast RPC path unnecessarily,
2144 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2145 */
2146
2147 options = MACH_SEND_MSG;
2148 if (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
2149 options |= MACH_SEND_TIMEOUT;
2150
2151 mr = mach_msg(&reply->Head, /* msg */
2152 options, /* option */
2153 reply->Head.msgh_size, /* send_size */
2154 0, /* rcv_size */
2155 MACH_PORT_NULL, /* rcv_name */
2156 MACH_MSG_TIMEOUT_NONE, /* timeout */
2157 MACH_PORT_NULL); /* notify */
2158
2159 /* Has a message error occurred? */
2160 switch (mr)
2161 {
2162 case MACH_SEND_INVALID_DEST:
2163 case MACH_SEND_TIMED_OUT:
2164 /* the reply can't be delivered, so destroy it */
2165 mach_msg_destroy(&reply->Head);
2166 break;
2167
2168 default :
2169 /* Includes success case. */
2170 break;
2171 }
2172
2173 CFAllocatorDeallocate(NULL, reply);
2174 }
2175
2176 mDNSlocal kern_return_t registerBootstrapService()
2177 {
2178 kern_return_t status;
2179 mach_port_t service_send_port, service_rcv_port;
2180
2181 debugf("Registering Bootstrap Service");
2182
2183 /*
2184 * See if our service name is already registered and if we have privilege to check in.
2185 */
2186 status = bootstrap_check_in(bootstrap_port, (char*)kmDNSBootstrapName, &service_rcv_port);
2187 if (status == KERN_SUCCESS)
2188 {
2189 /*
2190 * If so, we must be a followup instance of an already defined server. In that case,
2191 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2192 * that in case we have to unregister later (which requires the privilege port).
2193 */
2194 server_priv_port = bootstrap_port;
2195 restarting_via_mach_init = TRUE;
2196 }
2197 else if (status == BOOTSTRAP_UNKNOWN_SERVICE)
2198 {
2199 status = bootstrap_create_server(bootstrap_port, "/usr/sbin/mDNSResponder", getuid(),
2200 FALSE /* relaunch immediately, not on demand */, &server_priv_port);
2201 if (status != KERN_SUCCESS) return status;
2202
2203 status = bootstrap_create_service(server_priv_port, (char*)kmDNSBootstrapName, &service_send_port);
2204 if (status != KERN_SUCCESS)
2205 {
2206 mach_port_deallocate(mach_task_self(), server_priv_port);
2207 return status;
2208 }
2209
2210 status = bootstrap_check_in(server_priv_port, (char*)kmDNSBootstrapName, &service_rcv_port);
2211 if (status != KERN_SUCCESS)
2212 {
2213 mach_port_deallocate(mach_task_self(), server_priv_port);
2214 mach_port_deallocate(mach_task_self(), service_send_port);
2215 return status;
2216 }
2217 assert(service_send_port == service_rcv_port);
2218 }
2219
2220 /*
2221 * We have no intention of responding to requests on the service port. We are not otherwise
2222 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2223 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2224 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2225 */
2226 mach_port_destroy(mach_task_self(), service_rcv_port);
2227 return status;
2228 }
2229
2230 mDNSlocal kern_return_t destroyBootstrapService()
2231 {
2232 debugf("Destroying Bootstrap Service");
2233 return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
2234 }
2235
2236 mDNSlocal void ExitCallback(int signal)
2237 {
2238 LogMsgIdent(mDNSResponderVersionString, "stopping");
2239
2240 debugf("ExitCallback");
2241 if (!mDNS_DebugMode && !started_via_launchdaemon && signal != SIGHUP)
2242 destroyBootstrapService();
2243
2244 debugf("ExitCallback: Aborting MIG clients");
2245 while (DNSServiceDomainEnumerationList)
2246 AbortClient(DNSServiceDomainEnumerationList->ClientMachPort, DNSServiceDomainEnumerationList);
2247 while (DNSServiceBrowserList)
2248 AbortClient(DNSServiceBrowserList ->ClientMachPort, DNSServiceBrowserList);
2249 while (DNSServiceResolverList)
2250 AbortClient(DNSServiceResolverList ->ClientMachPort, DNSServiceResolverList);
2251 while (DNSServiceRegistrationList)
2252 AbortClient(DNSServiceRegistrationList ->ClientMachPort, DNSServiceRegistrationList);
2253
2254 debugf("ExitCallback: mDNS_Close");
2255 mDNS_Close(&mDNSStorage);
2256 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2257 exit(0);
2258 }
2259
2260 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2261 mDNSlocal void HandleSIG(int signal)
2262 {
2263 debugf(" ");
2264 debugf("HandleSIG %d", signal);
2265 mach_msg_header_t header;
2266 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
2267 header.msgh_remote_port = signal_port;
2268 header.msgh_local_port = MACH_PORT_NULL;
2269 header.msgh_size = sizeof(header);
2270 header.msgh_id = signal;
2271 if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
2272 {
2273 LogMsg("HandleSIG %d: mach_msg_send failed", signal);
2274 if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1);
2275 }
2276 }
2277
2278 mDNSlocal void INFOCallback(void)
2279 {
2280 mDNSs32 utc = mDNSPlatformUTC();
2281 DNSServiceDomainEnumeration *e;
2282 DNSServiceBrowser *b;
2283 DNSServiceResolver *l;
2284 DNSServiceRegistration *r;
2285 NetworkInterfaceInfoOSX *i;
2286
2287 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
2288
2289 udsserver_info(&mDNSStorage);
2290
2291 for (e = DNSServiceDomainEnumerationList; e; e=e->next)
2292 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
2293
2294 for (b = DNSServiceBrowserList; b; b=b->next)
2295 {
2296 DNSServiceBrowserQuestion *qptr;
2297 for (qptr = b->qlist; qptr; qptr = qptr->next)
2298 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c);
2299 }
2300 for (l = DNSServiceResolverList; l; l=l->next)
2301 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
2302
2303 for (r = DNSServiceRegistrationList; r; r=r->next)
2304 {
2305 ServiceInstance *si;
2306 for (si = r->regs; si; si = si->next)
2307 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));
2308 }
2309
2310 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
2311 {
2312 if (!i->Exists)
2313 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2314 i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, utc - i->LastSeen);
2315 else
2316 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2317 i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
2318 i->ifinfo.InterfaceActive ? "Active" : " ",
2319 i->ifinfo.IPv4Available ? "v4" : " ", i->ss.sktv4,
2320 i->ifinfo.IPv6Available ? "v6" : " ", i->ss.sktv6,
2321 i->ifinfo.InterfaceID,
2322 i->ifinfo.Advertise ? "Adv" : " ",
2323 i->ifinfo.McastTxRx ? "TxRx" : " ",
2324 &i->ifinfo.ip);
2325 }
2326
2327 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
2328 }
2329
2330 mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
2331 {
2332 (void)port; // Unused
2333 (void)size; // Unused
2334 (void)info; // Unused
2335 mach_msg_header_t *m = (mach_msg_header_t *)msg;
2336 switch(m->msgh_id)
2337 {
2338 case SIGHUP:
2339 case SIGINT:
2340 case SIGTERM: ExitCallback(m->msgh_id); break;
2341 case SIGINFO: INFOCallback(); break;
2342 case SIGUSR1: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2343 mDNSMacOSXNetworkChanged(&mDNSStorage); break;
2344 default: LogMsg("SignalCallback: Unknown signal %d", m->msgh_id); break;
2345 }
2346 }
2347
2348 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2349 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2350
2351 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
2352 {
2353 mStatus err;
2354 CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
2355 CFMachPortRef s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
2356 CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
2357 mach_port_t m_port = CFMachPortGetPort(s_port);
2358 char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2359 kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
2360 CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
2361 CFRunLoopSourceRef s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
2362 CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
2363
2364 if (status)
2365 {
2366 if (status == 1103)
2367 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2368 else
2369 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
2370 return(status);
2371 }
2372
2373 err = mDNS_Init(&mDNSStorage, &PlatformStorage,
2374 rrcachestorage, RR_CACHE_SIZE,
2375 mDNS_Init_AdvertiseLocalAddresses,
2376 mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
2377
2378 if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
2379
2380 gNotificationUserHostLabel = gNotificationPrefHostLabel = PlatformStorage.userhostlabel;
2381 gNotificationUserNiceLabel = gNotificationPrefNiceLabel = PlatformStorage.usernicelabel;
2382
2383 client_death_port = CFMachPortGetPort(d_port);
2384 signal_port = CFMachPortGetPort(i_port);
2385
2386 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
2387 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
2388 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
2389 CFRelease(d_rls);
2390 CFRelease(s_rls);
2391 CFRelease(i_rls);
2392 if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
2393 return(err);
2394 }
2395
2396 mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
2397 {
2398 mDNSs32 now = mDNS_TimeNow(m);
2399
2400 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2401 // Detailed reason:
2402 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2403 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2404 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2405 // we then systematically lose our own looped-back packets.
2406 if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m);
2407
2408 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2409 mDNSs32 nextevent = mDNS_Execute(m);
2410
2411 if (m->p->NetworkChanged)
2412 if (nextevent - m->p->NetworkChanged > 0)
2413 nextevent = m->p->NetworkChanged;
2414
2415 // 3. Deliver any waiting browse messages to clients
2416 DNSServiceBrowser *b = DNSServiceBrowserList;
2417
2418 while (b)
2419 {
2420 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2421 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2422 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2423 DNSServiceBrowser *x = b;
2424 b = b->next;
2425 if (x->results) // Try to deliver the list of results
2426 {
2427 while (x->results)
2428 {
2429 DNSServiceBrowserResult *const r = x->results;
2430 domainlabel name;
2431 domainname type, domain;
2432 DeconstructServiceName(&r->result, &name, &type, &domain); // Don't need to check result; already validated in FoundInstance()
2433 char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2434 char ctype[MAX_ESCAPED_DOMAIN_NAME];
2435 char cdom [MAX_ESCAPED_DOMAIN_NAME];
2436 ConvertDomainLabelToCString_unescaped(&name, cname);
2437 ConvertDomainNameToCString(&type, ctype);
2438 ConvertDomainNameToCString(&domain, cdom);
2439 DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0;
2440 kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, cname, ctype, cdom, flags, 1);
2441 // If we failed to send the mach message, try again in one second
2442 if (status == MACH_SEND_TIMED_OUT)
2443 {
2444 if (nextevent - now > mDNSPlatformOneSecond)
2445 nextevent = now + mDNSPlatformOneSecond;
2446 break;
2447 }
2448 else
2449 {
2450 x->lastsuccess = now;
2451 x->results = x->results->next;
2452 freeL("DNSServiceBrowserResult", r);
2453 }
2454 }
2455 // If this client hasn't read a single message in the last 60 seconds, abort it
2456 if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond)
2457 AbortBlockedClient(x->ClientMachPort, "browse", x);
2458 }
2459 }
2460
2461 DNSServiceResolver *l;
2462 for (l = DNSServiceResolverList; l; l=l->next)
2463 if (l->ReportTime && now - l->ReportTime >= 0)
2464 {
2465 l->ReportTime = 0;
2466 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2467 "This places considerable burden on the network.", l->i.name.c);
2468 }
2469
2470 if (m->p->NotifyUser)
2471 {
2472 if (m->p->NotifyUser - now < 0)
2473 {
2474 if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c))
2475 {
2476 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
2477 gNotificationPrefNiceLabel = m->p->usernicelabel = m->nicelabel;
2478 RecordUpdatedName(m, &gNotificationUserNiceLabel, &gNotificationPrefNiceLabel, "The name of your computer", "",
2479 CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
2480 "Then type the name in the Computer Name field."));
2481 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2482 m->p->NotifyUser = 0;
2483 }
2484 if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c))
2485 {
2486 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
2487 gNotificationPrefHostLabel = m->p->userhostlabel = m->hostlabel;
2488 RecordUpdatedName(m, &gNotificationUserHostLabel, &gNotificationPrefHostLabel, "This computer’s local hostname", ".local",
2489 CFSTR("To change the local hostname, open System Preferences and click Sharing. "
2490 "Then click Edit and type the name in the Local Hostname field."));
2491 }
2492 m->p->NotifyUser = 0;
2493 }
2494 else
2495 if (nextevent - m->p->NotifyUser > 0)
2496 nextevent = m->p->NotifyUser;
2497 }
2498
2499 return(nextevent);
2500 }
2501
2502 mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
2503 {
2504 mDNS_Lock(m);
2505
2506 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2507
2508 if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
2509 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2510 m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
2511 if (m->NewLocalOnlyQuestions)
2512 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2513 m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
2514 if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
2515 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
2516 if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
2517 LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending);
2518 #ifndef UNICAST_DISABLED
2519 if (m->timenow - m->uDNS_info.nextevent >= 0)
2520 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m->timenow - m->uDNS_info.nextevent);
2521 #endif
2522 if (m->timenow - m->NextCacheCheck >= 0)
2523 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck);
2524 if (m->timenow - m->NextScheduledQuery >= 0)
2525 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery);
2526 if (m->timenow - m->NextScheduledProbe >= 0)
2527 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe);
2528 if (m->timenow - m->NextScheduledResponse >= 0)
2529 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
2530
2531 mDNS_Unlock(&mDNSStorage);
2532 }
2533
2534 mDNSexport int main(int argc, char **argv)
2535 {
2536 int i;
2537 kern_return_t status;
2538
2539 for (i=1; i<argc; i++)
2540 {
2541 if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
2542 if (!strcmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
2543 }
2544
2545 signal(SIGHUP, HandleSIG); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2546 signal(SIGINT, HandleSIG); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2547 signal(SIGPIPE, SIG_IGN ); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2548 signal(SIGTERM, HandleSIG); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2549 signal(SIGINFO, HandleSIG); // (Debugging) Write state snapshot to syslog
2550 signal(SIGUSR1, HandleSIG); // (Debugging) Simulate network change notification from System Configuration Framework
2551
2552 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2553 if (!mDNS_DebugMode && !started_via_launchdaemon)
2554 {
2555 registerBootstrapService();
2556 if (!restarting_via_mach_init) exit(0); // mach_init will restart us immediately as a daemon
2557 int fd = open(_PATH_DEVNULL, O_RDWR, 0);
2558 if (fd < 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno, strerror(errno));
2559 else
2560 {
2561 // Avoid unnecessarily duplicating a file descriptor to itself
2562 if (fd != STDIN_FILENO) if (dup2(fd, STDIN_FILENO) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno, strerror(errno));
2563 if (fd != STDOUT_FILENO) if (dup2(fd, STDOUT_FILENO) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno, strerror(errno));
2564 if (fd != STDERR_FILENO) if (dup2(fd, STDERR_FILENO) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno, strerror(errno));
2565 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) (void)close(fd);
2566 }
2567 }
2568
2569 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2570 // The sooner we do this, the faster the machine will boot.
2571 status = udsserver_init();
2572 if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
2573
2574 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2575 LogMsgIdent(mDNSResponderVersionString, "starting");
2576 OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
2577 status = mDNSDaemonInitialize();
2578
2579 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2580 // Now that we're finished with anything privileged, switch over to running as "nobody"
2581 const struct passwd *pw = getpwnam("nobody");
2582 if (pw != NULL)
2583 setuid(pw->pw_uid);
2584 else
2585 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2586 #endif
2587
2588 if (status == 0)
2589 {
2590 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
2591 int numevents = 0;
2592 int RunLoopStatus = kCFRunLoopRunTimedOut;
2593
2594 // This is the main work loop:
2595 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2596 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2597 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2598 // (4) On wakeup we first process *all* events
2599 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2600 while (RunLoopStatus == kCFRunLoopRunTimedOut)
2601 {
2602 // 1. Before going into a blocking wait call and letting our process to go sleep,
2603 // call mDNSDaemonIdle to allow any deferred work to be completed.
2604 mDNSs32 nextevent = mDNSDaemonIdle(&mDNSStorage);
2605 nextevent = udsserver_idle(nextevent);
2606
2607 // 2. Work out how long we expect to sleep before the next scheduled task
2608 mDNSs32 ticks = nextevent - mDNS_TimeNow(&mDNSStorage);
2609 static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
2610 if (ticks > 1)
2611 RepeatedBusy = 0;
2612 else
2613 {
2614 ticks = 1;
2615 if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
2616 }
2617 CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
2618
2619 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2620 // (a) our next wakeup time, or (b) an event occurs.
2621 // The 'true' parameter makes it return after handling any event that occurs
2622 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2623 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents, ticks);
2624 numevents = 0;
2625 RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
2626
2627 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2628 while (RunLoopStatus == kCFRunLoopRunHandledSource)
2629 {
2630 numevents++;
2631 RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
2632 }
2633 }
2634
2635 LogMsg("ERROR: CFRunLoopRun Exiting.");
2636 mDNS_Close(&mDNSStorage);
2637 }
2638
2639 LogMsgIdent(mDNSResponderVersionString, "exiting");
2640
2641 exit:
2642 if (!mDNS_DebugMode && !started_via_launchdaemon) destroyBootstrapService();
2643 return(status);
2644 }
2645
2646 // uds_daemon.c support routines /////////////////////////////////////////////
2647
2648 // We keep a list of client-supplied event sources in PosixEventSource records
2649 struct CFSocketEventSource
2650 {
2651 udsEventCallback Callback;
2652 void *Context;
2653 int fd;
2654 struct CFSocketEventSource *Next;
2655 CFSocketRef cfs;
2656 CFRunLoopSourceRef RLS;
2657 };
2658 typedef struct CFSocketEventSource CFSocketEventSource;
2659
2660 static GenLinkedList gEventSources; // linked list of CFSocketEventSource's
2661
2662 mDNSlocal void cf_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
2663 // Called by CFSocket when data appears on socket
2664 {
2665 (void)s; // Unused
2666 (void)t; // Unused
2667 (void)dr; // Unused
2668 (void)c; // Unused
2669 CFSocketEventSource *source = (CFSocketEventSource*) i;
2670 source->Callback(source->Context);
2671 }
2672
2673 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
2674 // Arrange things so that callback is called with context when data appears on fd
2675 {
2676 CFSocketEventSource *newSource;
2677 CFSocketContext cfContext = { 0, NULL, NULL, NULL, NULL };
2678
2679 if (gEventSources.LinkOffset == 0)
2680 InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
2681
2682 if (fd >= FD_SETSIZE || fd < 0)
2683 return mStatus_UnsupportedErr;
2684 if (callback == NULL)
2685 return mStatus_BadParamErr;
2686
2687 newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource);
2688 if (NULL == newSource)
2689 return mStatus_NoMemoryErr;
2690
2691 newSource->Callback = callback;
2692 newSource->Context = context;
2693 newSource->fd = fd;
2694
2695 cfContext.info = newSource;
2696 if ( NULL != (newSource->cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack,
2697 cf_callback, &cfContext)) &&
2698 NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->cfs, 0)))
2699 {
2700 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
2701 AddToTail(&gEventSources, newSource);
2702 }
2703 else
2704 {
2705 if (newSource->cfs)
2706 {
2707 CFSocketInvalidate(newSource->cfs); // Note: Also closes the underlying socket
2708 CFRelease(newSource->cfs);
2709 }
2710 return mStatus_NoMemoryErr;
2711 }
2712
2713 return mStatus_NoError;
2714 }
2715
2716 mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
2717 // Reverse what was done in udsSupportAddFDToEventLoop().
2718 {
2719 CFSocketEventSource *iSource;
2720
2721 for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
2722 {
2723 if (fd == iSource->fd)
2724 {
2725 RemoveFromList(&gEventSources, iSource);
2726 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
2727 CFRunLoopSourceInvalidate(iSource->RLS);
2728 CFRelease(iSource->RLS);
2729 CFSocketInvalidate(iSource->cfs); // Note: Also closes the underlying socket
2730 CFRelease(iSource->cfs);
2731 free(iSource);
2732 return mStatus_NoError;
2733 }
2734 }
2735 return mStatus_NoSuchNameErr;
2736 }
2737
2738 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2739 const char *__crashreporter_info__ = mDNSResponderVersionString;
2740 asm(".desc ___crashreporter_info__, 0x10");
2741
2742 // For convenience when using the "strings" command, this is the last thing in the file
2743 mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";