]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/daemon.c
mDNSResponder-171.4.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / daemon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Formatting notes:
18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
29
30 Change History (most recent first):
31
32 $Log: daemon.c,v $
33 Revision 1.358 2008/03/06 21:26:11 cheshire
34 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
35
36 Revision 1.357 2008/02/13 17:40:43 cheshire
37 <rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
38
39 Revision 1.356 2007/12/18 00:28:56 cheshire
40 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
41 Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
42
43 Revision 1.355 2007/12/17 22:29:22 cheshire
44 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
45 Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
46
47 Revision 1.354 2007/12/15 01:12:28 cheshire
48 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
49
50 Revision 1.353 2007/12/14 19:14:02 cheshire
51 Added (commented out) code for testing sleep/wake
52
53 Revision 1.352 2007/12/14 00:58:29 cheshire
54 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
55 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
56 until TLS/TCP deregistrations have completed (up to five seconds maximum)
57
58 Revision 1.351 2007/12/12 21:34:18 cheshire
59 Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
60 it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
61 confirmed that the bug is definitely fixed we'll remove the workaround altogether.
62
63 Revision 1.350 2007/12/07 00:45:58 cheshire
64 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
65
66 Revision 1.349 2007/12/04 22:00:54 cheshire
67 Fixed mistake in comment
68
69 Revision 1.348 2007/12/01 00:27:43 cheshire
70 Fixed compile warning: declaration of 'r' shadows a previous local
71
72 Revision 1.347 2007/11/02 22:00:13 cheshire
73 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
74 Need to hold the lock while calling SetDomainSecrets
75
76 Revision 1.346 2007/11/02 20:18:13 cheshire
77 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
78
79 Revision 1.345 2007/10/17 18:41:21 cheshire
80 For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
81
82 Revision 1.344 2007/09/29 01:06:17 mcguire
83 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
84
85 Revision 1.343 2007/09/24 05:02:41 cheshire
86 Debugging: In SIGINFO output, indicate explicitly when a given section is empty
87
88 Revision 1.342 2007/09/18 19:09:02 cheshire
89 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
90
91 Revision 1.341 2007/09/12 01:22:13 cheshire
92 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
93
94 Revision 1.340 2007/09/07 22:44:03 mcguire
95 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
96
97 Revision 1.339 2007/09/06 19:08:29 cheshire
98 LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
99
100 Revision 1.338 2007/09/05 23:34:27 mcguire
101 Revert logging change
102
103 Revision 1.337 2007/09/05 20:45:50 cheshire
104 Added list of KQSocketEventSources in SIGINFO output
105
106 Revision 1.336 2007/08/31 17:15:37 cheshire
107 Reordered startup log messages so that "mDNSResponder ... starting" is the first message
108
109 Revision 1.335 2007/08/31 02:00:16 cheshire
110 Added comment explaining use of zero-width non-breaking space character to tag literal strings
111
112 Revision 1.334 2007/08/24 23:40:24 cheshire
113 Added comment about FreeServiceInstance
114
115 Revision 1.333 2007/08/23 21:02:35 cheshire
116 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
117
118 Revision 1.332 2007/08/22 23:54:54 mcguire
119 <rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
120
121 Revision 1.331 2007/08/18 01:02:03 mcguire
122 <rdar://problem/5415593> No Bonjour services are getting registered at boot
123
124 Revision 1.330 2007/08/10 22:25:57 mkrochma
125 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
126
127 Revision 1.329 2007/08/08 22:34:58 mcguire
128 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
129
130 Revision 1.328 2007/07/27 22:43:37 cheshire
131 Improved mallocL/freeL "suspiciously large" debugging messages
132
133 Revision 1.327 2007/07/27 19:30:41 cheshire
134 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
135 to properly reflect tri-state nature of the possible responses
136
137 Revision 1.326 2007/07/24 17:23:33 cheshire
138 <rdar://problem/5357133> Add list validation checks for debugging
139
140 Revision 1.325 2007/07/11 23:43:43 cheshire
141 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
142
143 Revision 1.324 2007/07/11 22:44:40 cheshire
144 <rdar://problem/5328801> SIGHUP should purge the cache
145
146 Revision 1.323 2007/07/11 03:01:50 cheshire
147 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
148
149 Revision 1.322 2007/07/06 18:58:16 cheshire
150 Check m->NextScheduledNATOp in ShowTaskSchedulingError()
151
152 Revision 1.321 2007/07/02 21:54:20 cheshire
153 Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
154
155 Revision 1.320 2007/06/28 21:16:27 cheshire
156 Rename "m->nextevent" as more informative "m->NextuDNSEvent"
157
158 Revision 1.319 2007/06/22 20:47:08 cheshire
159 <rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
160 Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
161
162 Revision 1.318 2007/06/20 01:45:40 cheshire
163 When showing dormant interfaces, display last-seen IP address for that dormant interface
164
165 Revision 1.317 2007/06/20 01:10:12 cheshire
166 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
167
168 Revision 1.316 2007/06/19 19:27:11 cheshire
169 <rdar://problem/5141540> Sandbox mDNSResponder
170 Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
171
172 Revision 1.315 2007/06/15 21:54:51 cheshire
173 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
174
175 Revision 1.314 2007/06/15 19:23:17 cheshire
176 <rdar://problem/5254053> mDNSResponder renames my host without asking
177 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
178
179 Revision 1.313 2007/05/25 16:02:05 cheshire
180 When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
181
182 Revision 1.312 2007/05/22 19:07:21 cheshire
183 Add comment explaining RR_CACHE_SIZE calculation
184
185 Revision 1.311 2007/05/15 21:47:21 cheshire
186 Get rid of "#pragma unused(m)"
187
188 Revision 1.310 2007/05/08 00:56:17 cheshire
189 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
190
191 Revision 1.309 2007/04/30 21:33:38 cheshire
192 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
193 is iterating through the m->ServiceRegistrations list
194
195 Revision 1.308 2007/04/28 01:31:59 cheshire
196 Improve debugging support for catching memory corruption problems
197
198 Revision 1.307 2007/04/24 18:32:00 cheshire
199 Grab a copy of KQtask string pointer in case KQcallback deletes the task
200
201 Revision 1.306 2007/04/22 19:11:51 cheshire
202 Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
203 if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
204 from the project and just using simple vanilla C linked-list manipulation instead.
205
206 Revision 1.305 2007/04/22 06:02:03 cheshire
207 <rdar://problem/4615977> Query should immediately return failure when no server
208
209 Revision 1.304 2007/04/21 21:47:47 cheshire
210 <rdar://problem/4376383> Daemon: Add watchdog timer
211
212 Revision 1.303 2007/04/18 00:50:47 cheshire
213 <rdar://problem/5141540> Sandbox mDNSResponder
214
215 Revision 1.302 2007/04/07 01:01:48 cheshire
216 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
217
218 Revision 1.301 2007/04/05 19:13:48 cheshire
219 Use better name in SCPreferencesCreate
220
221 Revision 1.300 2007/04/04 21:22:18 cheshire
222 Suppress "Local Hostname changed" syslog message when name has not actually changed
223
224 Revision 1.299 2007/04/03 19:19:33 cheshire
225 Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
226
227 Revision 1.298 2007/03/30 21:51:45 cheshire
228 Minor code tidying
229
230 Revision 1.297 2007/03/27 22:47:19 cheshire
231 On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
232
233 Revision 1.296 2007/03/24 01:23:29 cheshire
234 Call validator for uDNS data structures
235
236 Revision 1.295 2007/03/20 23:32:49 cheshire
237 Minor textual tidying
238
239 Revision 1.294 2007/03/07 02:50:50 cheshire
240 <rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
241
242 Revision 1.293 2007/03/06 22:59:01 cheshire
243 <rdar://problem/4157921> Security: Null dereference possible in daemon.c
244
245 Revision 1.292 2007/02/28 21:55:10 cheshire
246 <rdar://problem/3862944> UI: Name conflict notifications should be localized
247 Additional fix: We were not getting our NotificationCallBackDismissed messages
248 because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
249 (We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
250
251 Revision 1.291 2007/02/28 03:51:24 cheshire
252 <rdar://problem/3862944> UI: Name conflict notifications should be localized
253 Moved curly quotes out of the literal text and into the localized text, so they
254 can be replaced with alternate characters as appropriate for other languages.
255
256 Revision 1.290 2007/02/14 01:58:19 cheshire
257 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
258
259 Revision 1.289 2007/02/07 19:32:00 cheshire
260 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
261
262 Revision 1.288 2007/02/07 01:01:24 cheshire
263 <rdar://problem/3956518> Need to go native with launchd
264 Additional refinements -- was unnecessarily calling launch_data_free()
265
266 Revision 1.287 2007/02/06 19:06:48 cheshire
267 <rdar://problem/3956518> Need to go native with launchd
268
269 Revision 1.286 2007/01/06 01:00:33 cheshire
270 Improved SIGINFO output
271
272 Revision 1.285 2007/01/05 08:30:47 cheshire
273 Trim excessive "$Log" checkin history from before 2006
274 (checkin history still available via "cvs log ..." of course)
275
276 Revision 1.284 2007/01/05 05:44:35 cheshire
277 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
278 so that mDNSPosix embedded clients will compile again
279
280 Revision 1.283 2007/01/04 23:11:14 cheshire
281 <rdar://problem/4720673> uDNS: Need to start caching unicast records
282 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
283
284 Revision 1.282 2006/12/21 00:09:45 cheshire
285 Use mDNSPlatformMemZero instead of bzero
286
287 Revision 1.281 2006/11/18 05:01:32 cheshire
288 Preliminary support for unifying the uDNS and mDNS code,
289 including caching of uDNS answers
290
291 Revision 1.280 2006/11/10 00:54:16 cheshire
292 <rdar://problem/4816598> Changing case of Computer Name doesn't work
293
294 Revision 1.279 2006/11/02 17:44:01 cheshire
295 No longer have a separate uDNS ActiveQueries list
296
297 Revision 1.278 2006/10/05 04:04:24 herscher
298 Remove embedded uDNS_info struct from DNSQuestion_struct
299
300 Revision 1.277 2006/09/21 21:01:24 cheshire
301 Change 'autorename' to more accurate name 'renameonmemfree'
302
303 Revision 1.276 2006/09/17 19:12:02 cheshire
304 Further changes for removal of uDNS_info substructure from mDNS_struct
305
306 Revision 1.275 2006/09/15 21:20:16 cheshire
307 Remove uDNS_info substructure from mDNS_struct
308
309 Revision 1.274 2006/08/14 23:24:39 cheshire
310 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
311
312 Revision 1.273 2006/07/30 05:43:19 cheshire
313 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
314 Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
315
316 Revision 1.272 2006/07/27 03:24:35 cheshire
317 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
318 Further refinement: Declare KQueueEntry parameter "const"
319
320 Revision 1.271 2006/07/27 02:59:26 cheshire
321 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
322 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
323 after releasing BigMutex, in case actions it took have resulted in new work for the
324 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
325 add new active interfaces to its list, and consequently schedule queries to be sent).
326
327 Revision 1.270 2006/07/25 17:16:36 mkrochma
328 Quick fix to solve kqueue related crashes and hangs
329
330 Revision 1.269 2006/07/22 06:11:37 cheshire
331 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
332
333 Revision 1.268 2006/07/15 02:01:32 cheshire
334 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
335 Fix broken "empty string" browsing
336
337 Revision 1.267 2006/07/07 01:09:10 cheshire
338 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
339 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
340
341 Revision 1.266 2006/07/05 23:34:53 cheshire
342 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
343
344 Revision 1.265 2006/06/29 07:32:08 cheshire
345 Added missing LogOperation logging for DNSServiceBrowse results
346
347 Revision 1.264 2006/06/29 05:33:30 cheshire
348 <rdar://problem/4607043> mDNSResponder conditional compilation options
349
350 Revision 1.263 2006/06/08 23:23:48 cheshire
351 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
352
353 Revision 1.262 2006/03/18 21:49:11 cheshire
354 Added comment in ShowTaskSchedulingError(mDNS *const m)
355
356 Revision 1.261 2006/01/06 01:22:28 cheshire
357 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
358
359 */
360
361 #include <mach/mach.h>
362 #include <mach/mach_error.h>
363 #include <servers/bootstrap.h>
364 #include <sys/types.h>
365 #include <unistd.h>
366 #include <paths.h>
367 #include <fcntl.h>
368 #include <launch.h>
369 #include <pwd.h>
370 #include <sys/event.h>
371 #include <pthread.h>
372 #include <sandbox.h>
373 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
374
375 #include "DNSServiceDiscoveryRequestServer.h"
376 #include "DNSServiceDiscoveryReply.h"
377
378 #include "uDNS.h"
379 #include "DNSCommon.h"
380 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
381
382 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
383
384 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
385 #include "helper.h"
386
387 //*************************************************************************************************************
388 // Globals
389
390 static mDNS_PlatformSupport PlatformStorage;
391
392 // Start off with a default cache of 16K (99 records)
393 // Each time we grow the cache we add another 99 records
394 // 99 * 164 = 16236 bytes.
395 // This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
396 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
397 static CacheEntity rrcachestorage[RR_CACHE_SIZE];
398
399 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
400 static mach_port_t m_port = MACH_PORT_NULL;
401 static mach_port_t client_death_port = MACH_PORT_NULL;
402 static mach_port_t signal_port = MACH_PORT_NULL;
403 static mach_port_t server_priv_port = MACH_PORT_NULL;
404
405 static dnssd_sock_t launchd_fd = dnssd_InvalidSocket;
406
407 // mDNS Mach Message Timeout, in milliseconds.
408 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
409 // fails to service its mach message queue, but long enough to give a well-written
410 // client a chance to service its mach message queue without getting cut off.
411 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
412 // even extra-slow clients a fair chance before we cut them off.
413 #define MDNS_MM_TIMEOUT 250
414
415 static int restarting_via_mach_init = 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
416 static int started_via_launchdaemon = 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
417
418 static int OSXVers;
419
420 static CFRunLoopRef CFRunLoop;
421
422 //*************************************************************************************************************
423 // Active client list structures
424
425 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
426 struct DNSServiceDomainEnumeration_struct
427 {
428 DNSServiceDomainEnumeration *next;
429 mach_port_t ClientMachPort;
430 DNSQuestion dom; // Question asking for domains
431 DNSQuestion def; // Question asking for default domain
432 };
433
434 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
435 struct DNSServiceBrowserResult_struct
436 {
437 DNSServiceBrowserResult *next;
438 int resultType;
439 domainname result;
440 };
441
442 typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
443
444 typedef struct DNSServiceBrowserQuestion
445 {
446 struct DNSServiceBrowserQuestion *next;
447 DNSQuestion q;
448 domainname domain;
449 } DNSServiceBrowserQuestion;
450
451 struct DNSServiceBrowser_struct
452 {
453 DNSServiceBrowser *next;
454 mach_port_t ClientMachPort;
455 DNSServiceBrowserQuestion *qlist;
456 DNSServiceBrowserResult *results;
457 mDNSs32 lastsuccess;
458 mDNSBool DefaultDomain; // was the browse started on an explicit domain?
459 domainname type; // registration type
460 };
461
462 typedef struct DNSServiceResolver_struct DNSServiceResolver;
463 struct DNSServiceResolver_struct
464 {
465 DNSServiceResolver *next;
466 mach_port_t ClientMachPort;
467 ServiceInfoQuery q;
468 ServiceInfo i;
469 mDNSs32 ReportTime;
470 };
471
472 // A single registered service: ServiceRecordSet + bookkeeping
473 // Note that we duplicate some fields from parent DNSServiceRegistration object
474 // to facilitate cleanup, when instances and parent may be deallocated at different times.
475 typedef struct ServiceInstance
476 {
477 struct ServiceInstance *next;
478 mach_port_t ClientMachPort;
479 mDNSBool autoname; // Set if this name is tied to the Computer Name
480 mDNSBool renameonmemfree; // Set if we just got a name conflict and now need to automatically pick a new name
481 domainlabel name;
482 domainname domain;
483 ServiceRecordSet srs;
484 // Don't add any fields after ServiceRecordSet.
485 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
486 } ServiceInstance;
487
488 // A client-created service. May reference several ServiceInstance objects if default
489 // settings cause registration in multiple domains.
490 typedef struct DNSServiceRegistration
491 {
492 struct DNSServiceRegistration *next;
493 mach_port_t ClientMachPort;
494 mDNSBool DefaultDomain;
495 mDNSBool autoname;
496 size_t rdsize;
497 int NumSubTypes;
498 char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
499 domainlabel name; // used only if autoname is false
500 domainname type;
501 mDNSIPPort port;
502 unsigned char txtinfo[1024];
503 size_t txt_len;
504 uint32_t NextRef;
505 ServiceInstance *regs;
506 } DNSServiceRegistration;
507
508 static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
509 static DNSServiceBrowser *DNSServiceBrowserList = NULL;
510 static DNSServiceResolver *DNSServiceResolverList = NULL;
511 static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
512
513 // We keep a list of client-supplied event sources in KQSocketEventSource records
514 typedef struct KQSocketEventSource
515 {
516 struct KQSocketEventSource *next;
517 int fd;
518 KQueueEntry kqs;
519 } KQSocketEventSource;
520
521 static KQSocketEventSource *gEventSources;
522
523 //*************************************************************************************************************
524 // General Utility Functions
525
526 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
527
528 char _malloc_options[] = "AXZ";
529
530 mDNSexport void LogMemCorruption(const char *format, ...)
531 {
532 char buffer[512];
533 va_list ptr;
534 va_start(ptr,format);
535 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
536 va_end(ptr);
537 LogMsg("!!!! %s !!!!", buffer);
538 NotifyOfElusiveBug("Memory Corruption", buffer);
539 #if ForceAlerts
540 *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
541 #endif
542 }
543
544 mDNSlocal void validatelists(mDNS *const m)
545 {
546 // Check local lists
547 KQSocketEventSource *k;
548 for (k = gEventSources; k; k=k->next)
549 if (k->next == (KQSocketEventSource *)~0 || k->fd < 0)
550 LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd);
551
552 // Check Mach client lists
553 DNSServiceDomainEnumeration *e;
554 for (e = DNSServiceDomainEnumerationList; e; e=e->next)
555 if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
556 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort);
557
558 DNSServiceBrowser *b;
559 for (b = DNSServiceBrowserList; b; b=b->next)
560 if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
561 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort);
562
563 DNSServiceResolver *l;
564 for (l = DNSServiceResolverList; l; l=l->next)
565 if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
566 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort);
567
568 DNSServiceRegistration *r;
569 for (r = DNSServiceRegistrationList; r; r=r->next)
570 if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
571 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort);
572
573 // Check Unix Domain Socket client lists (uds_daemon.c)
574 uds_validatelists();
575
576 // Check core mDNS lists
577 AuthRecord *rr;
578 for (rr = m->ResourceRecords; rr; rr=rr->next)
579 {
580 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
581 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
582 if (rr->resrec.name != &rr->namestorage)
583 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
584 rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
585 }
586
587 for (rr = m->DuplicateRecords; rr; rr=rr->next)
588 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
589 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
590
591 rr = m->NewLocalRecords;
592 if (rr)
593 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
594 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
595
596 rr = m->CurrentRecord;
597 if (rr)
598 if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
599 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
600
601 DNSQuestion *q;
602 for (q = m->Questions; q; q=q->next)
603 if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32)~0)
604 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
605
606 CacheGroup *cg;
607 CacheRecord *cr;
608 mDNSu32 slot;
609 FORALL_CACHERECORDS(slot, cg, cr)
610 {
611 if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
612 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
613 if (cr->CRActiveQuestion)
614 {
615 for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
616 if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
617 }
618 }
619
620 // Check core uDNS lists
621 udns_validatelists(m);
622
623 // Check platform-layer lists
624 NetworkInterfaceInfoOSX *i;
625 for (i = m->p->InterfaceList; i; i = i->next)
626 if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->ifa_name || i->ifa_name == (char *)~0)
627 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifa_name);
628
629 ClientTunnel *t;
630 for (t = m->TunnelClients; t; t=t->next)
631 if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63)
632 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
633 }
634
635 void *mallocL(char *msg, unsigned int size)
636 {
637 unsigned long *mem = malloc(size+8);
638 if (!mem)
639 {
640 LogMsg("malloc( %s : %d ) failed", msg, size);
641 return(NULL);
642 }
643 else
644 {
645 if (size > 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]);
646 else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
647 mem[0] = 0xDEAD1234;
648 mem[1] = size;
649 //mDNSPlatformMemZero(&mem[2], size);
650 memset(&mem[2], 0xFF, size);
651 validatelists(&mDNSStorage);
652 return(&mem[2]);
653 }
654 }
655
656 void freeL(char *msg, void *x)
657 {
658 if (!x)
659 LogMsg("free( %s @ NULL )!", msg);
660 else
661 {
662 unsigned long *mem = ((unsigned long *)x) - 2;
663 if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
664 if (mem[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]);
665 else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
666 //mDNSPlatformMemZero(mem, mem[1]+8);
667 memset(mem, 0xFF, mem[1]+8);
668 validatelists(&mDNSStorage);
669 free(mem);
670 }
671 }
672
673 #endif
674
675 //*************************************************************************************************************
676 // Client Death Detection
677
678 // This gets called after ALL constituent records of the Service Record Set have been deregistered
679 mDNSlocal void FreeServiceInstance(ServiceInstance *x)
680 {
681 ServiceRecordSet *s = &x->srs;
682 ExtraResourceRecord *e = x->srs.Extras, *tmp;
683
684 while (e)
685 {
686 e->r.RecordContext = e;
687 tmp = e;
688 e = e->next;
689 FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
690 }
691
692 if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
693 freeL("TXT RData", s->RR_TXT.resrec.rdata);
694
695 if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
696 freeL("ServiceInstance", x);
697 }
698
699 // AbortClient finds whatever client is identified by the given Mach port,
700 // stops whatever operation that client was doing, and frees its memory.
701 // In the case of a service registration, the actual freeing may be deferred
702 // until we get the mStatus_MemFree message, if necessary
703 mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
704 {
705 DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList;
706 DNSServiceBrowser **b = &DNSServiceBrowserList;
707 DNSServiceResolver **l = &DNSServiceResolverList;
708 DNSServiceRegistration **r = &DNSServiceRegistrationList;
709
710 while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next;
711 if (*e)
712 {
713 DNSServiceDomainEnumeration *x = *e;
714 *e = (*e)->next;
715 if (m && m != x)
716 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->dom.qname.c, m, x);
717 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort, x->dom.qname.c);
718 mDNS_StopGetDomains(&mDNSStorage, &x->dom);
719 mDNS_StopGetDomains(&mDNSStorage, &x->def);
720 freeL("DNSServiceDomainEnumeration", x);
721 return;
722 }
723
724 while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
725 if (*b)
726 {
727 DNSServiceBrowser *x = *b;
728 DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist;
729 *b = (*b)->next;
730 while (qptr)
731 {
732 if (m && m != x)
733 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
734 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c);
735 mDNS_StopBrowse(&mDNSStorage, &qptr->q);
736 freePtr = qptr;
737 qptr = qptr->next;
738 freeL("DNSServiceBrowserQuestion", freePtr);
739 }
740 while (x->results)
741 {
742 DNSServiceBrowserResult *t = x->results;
743 x->results = x->results->next;
744 freeL("DNSServiceBrowserResult", t);
745 }
746 freeL("DNSServiceBrowser", x);
747 return;
748 }
749
750 while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next;
751 if (*l)
752 {
753 DNSServiceResolver *x = *l;
754 *l = (*l)->next;
755 if (m && m != x)
756 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
757 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c);
758 mDNS_StopResolveService(&mDNSStorage, &x->q);
759 freeL("DNSServiceResolver", x);
760 return;
761 }
762
763 while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
764 if (*r)
765 {
766 ServiceInstance *si = NULL;
767 DNSServiceRegistration *x = *r;
768 *r = (*r)->next;
769
770 si = x->regs;
771 while (si)
772 {
773 ServiceInstance *instance = si;
774 si = si->next;
775 instance->renameonmemfree = mDNSfalse;
776 if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);
777 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
778
779 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
780 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
781 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
782 // the list, so we should go ahead and free the memory right now
783 if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
784 }
785 x->regs = NULL;
786 freeL("DNSServiceRegistration", x);
787 return;
788 }
789
790 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort);
791 }
792
793 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
794
795 mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m)
796 {
797 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
798 DNSServiceBrowser *b = DNSServiceBrowserList;
799 DNSServiceResolver *l = DNSServiceResolverList;
800 DNSServiceRegistration *r = DNSServiceRegistrationList;
801 DNSServiceBrowserQuestion *qptr;
802
803 while (e && e->ClientMachPort != c) e = e->next;
804 while (b && b->ClientMachPort != c) b = b->next;
805 while (l && l->ClientMachPort != c) l = l->next;
806 while (r && r->ClientMachPort != c) r = r->next;
807
808 if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
809 else if (b)
810 {
811 for (qptr = b->qlist; qptr; qptr = qptr->next)
812 LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
813 }
814 else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
815 else if (r)
816 {
817 ServiceInstance *si;
818 for (si = r->regs; si; si = si->next)
819 LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
820 }
821 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
822
823 AbortClient(c, m);
824 }
825
826 mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
827 {
828 DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
829 DNSServiceBrowser *b = DNSServiceBrowserList;
830 DNSServiceResolver *l = DNSServiceResolverList;
831 DNSServiceRegistration *r = DNSServiceRegistrationList;
832 DNSServiceBrowserQuestion *qptr;
833
834 while (e && e->ClientMachPort != c) e = e->next;
835 while (b && b->ClientMachPort != c) b = b->next;
836 while (l && l->ClientMachPort != c) l = l->next;
837 while (r && r->ClientMachPort != c) r = r->next;
838 if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c);
839 if (b)
840 {
841 for (qptr = b->qlist; qptr; qptr = qptr->next)
842 LogMsg("%5d: Browser(%##s) already exists!", c, qptr->q.qname.c);
843 }
844 if (l) LogMsg("%5d: Resolver(%##s) already exists!", c, l->i.name.c);
845 if (r) LogMsg("%5d: Registration(%##s) already exists!", c, r->regs ? r->regs->srs.RR_SRV.resrec.name->c : NULL);
846 return(e || b || l || r);
847 }
848
849 mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
850 {
851 KQueueLock(&mDNSStorage);
852 mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
853 (void)unusedport; // Unused
854 (void)size; // Unused
855 (void)info; // Unused
856 if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME)
857 {
858 const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg;
859 AbortClient(deathMessage->not_port, NULL);
860
861 /* Deallocate the send right that came in the dead name notification */
862 mach_port_destroy(mach_task_self(), deathMessage->not_port);
863 }
864 KQueueUnlock(&mDNSStorage, "Mach AbortClient");
865 }
866
867 mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
868 {
869 mach_port_t prev;
870 kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0,
871 client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
872 // If the port already died while we were thinking about it, then abort the operation right away
873 if (r != KERN_SUCCESS)
874 AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
875 }
876
877 //*************************************************************************************************************
878 // Domain Enumeration
879
880 mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
881 {
882 kern_return_t status;
883 char buffer[MAX_ESCAPED_DOMAIN_NAME];
884 DNSServiceDomainEnumerationReplyResultType rt;
885 DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
886 (void)m; // Unused
887
888 debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
889 if (answer->rrtype != kDNSType_PTR) return;
890 if (!x) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
891
892 if (AddRecord)
893 {
894 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain;
895 else rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
896 }
897 else
898 {
899 if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain;
900 else return;
901 }
902
903 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
904 x->ClientMachPort, x->dom.qname.c, answer->rdata->u.name.c,
905 !AddRecord ? "RemoveDomain" :
906 question == &x->dom ? "AddDomain" : "AddDomainDefault");
907
908 ConvertDomainNameToCString(&answer->rdata->u.name, buffer);
909 status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, buffer, 0, MDNS_MM_TIMEOUT);
910 if (status == MACH_SEND_TIMED_OUT)
911 AbortBlockedClient(x->ClientMachPort, "enumeration", x);
912 }
913
914 mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
915 int regDom)
916 {
917 // Check client parameter
918 (void)unusedserver; // Unused
919 mStatus err = mStatus_NoError;
920 const char *errormsg = "Unknown";
921 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
922 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
923
924 mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
925 mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
926
927 // Allocate memory, and handle failure
928 DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
929 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
930
931 // Set up object, and link into list
932 x->ClientMachPort = client;
933 x->next = DNSServiceDomainEnumerationList;
934 DNSServiceDomainEnumerationList = x;
935
936 verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
937
938 // Do the operation
939 err = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
940 if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
941 if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
942
943 // Succeeded: Wrap up and return
944 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c);
945 EnableDeathNotificationForClient(client, x);
946 return(mStatus_NoError);
947
948 fail:
949 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err);
950 return(err);
951 }
952
953 //*************************************************************************************************************
954 // Browse for services
955
956 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
957 {
958 (void)m; // Unused
959
960 if (answer->rrtype != kDNSType_PTR)
961 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
962
963 domainlabel name;
964 domainname type, domain;
965 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
966 {
967 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
968 answer->name->c, answer->rdata->u.name.c);
969 return;
970 }
971
972 DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
973 if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
974
975 verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
976 AssignDomainName(&x->result, &answer->rdata->u.name);
977 if (AddRecord)
978 x->resultType = DNSServiceBrowserReplyAddInstance;
979 else x->resultType = DNSServiceBrowserReplyRemoveInstance;
980 x->next = NULL;
981
982 DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext;
983 DNSServiceBrowserResult **p = &browser->results;
984 while (*p) p = &(*p)->next;
985 *p = x;
986
987 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
988 browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
989 }
990
991 mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
992 {
993 mStatus err = mStatus_NoError;
994 DNSServiceBrowserQuestion *ptr, *question = NULL;
995
996 for (ptr = browser->qlist; ptr; ptr = ptr->next)
997 {
998 if (SameDomainName(&ptr->q.qname, d))
999 { debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; }
1000 }
1001
1002 question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
1003 if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
1004 AssignDomainName(&question->domain, d);
1005 question->next = browser->qlist;
1006 browser->qlist = question;
1007 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
1008 err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSInterface_Any, mDNSfalse, FoundInstance, browser);
1009 if (err) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
1010 return err;
1011 }
1012
1013 mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add)
1014 {
1015 DNSServiceBrowser *ptr;
1016 for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
1017 {
1018 if (ptr->DefaultDomain)
1019 {
1020 if (add)
1021 {
1022 mStatus err = AddDomainToBrowser(ptr, d);
1023 if (err && err != mStatus_AlreadyRegistered) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d, ptr->ClientMachPort);
1024 }
1025 else
1026 {
1027 DNSServiceBrowserQuestion **q = &ptr->qlist;
1028 while (*q)
1029 {
1030 if (SameDomainName(&(*q)->domain, d))
1031 {
1032 DNSServiceBrowserQuestion *rem = *q;
1033 *q = (*q)->next;
1034 mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
1035 freeL("DNSServiceBrowserQuestion", rem);
1036 return;
1037 }
1038 q = &(*q)->next;
1039 }
1040 LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
1041 }
1042 }
1043 }
1044 }
1045
1046 mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1047 DNSCString regtype, DNSCString domain)
1048 {
1049 // Check client parameter
1050 (void)unusedserver; // Unused
1051 mStatus err = mStatus_NoError;
1052 const char *errormsg = "Unknown";
1053
1054 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1055 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1056
1057 // Check other parameters
1058 domainname t, d;
1059 t.c[0] = 0;
1060 mDNSs32 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
1061 if (NumSubTypes < 0 || NumSubTypes > 1) { errormsg = "Bad Service SubType"; goto badparam; }
1062 if (NumSubTypes == 1 && !AppendDNSNameString(&t, regtype + strlen(regtype) + 1))
1063 { errormsg = "Bad Service SubType"; goto badparam; }
1064 if (!regtype[0] || !AppendDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
1065 domainname temp;
1066 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
1067 if (temp.c[0] > 15 && (!domain || domain[0] == 0)) domain = "local."; // For over-long service types, we only allow domain "local"
1068
1069 // Allocate memory, and handle failure
1070 DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
1071 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1072
1073 // Set up object, and link into list
1074 AssignDomainName(&x->type, &t);
1075 x->ClientMachPort = client;
1076 x->results = NULL;
1077 x->lastsuccess = 0;
1078 x->qlist = NULL;
1079 x->next = DNSServiceBrowserList;
1080 DNSServiceBrowserList = x;
1081
1082 if (domain[0])
1083 {
1084 // Start browser for an explicit domain
1085 x->DefaultDomain = mDNSfalse;
1086 if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; }
1087 err = AddDomainToBrowser(x, &d);
1088 if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
1089 }
1090 else
1091 {
1092 DNameListElem *sdPtr;
1093 // Start browser on all domains
1094 x->DefaultDomain = mDNStrue;
1095 if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
1096 for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next)
1097 {
1098 err = AddDomainToBrowser(x, &sdPtr->name);
1099 if (err)
1100 {
1101 // only terminally bail if .local fails
1102 if (!SameDomainName(&localdomain, &sdPtr->name))
1103 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr->name.c);
1104 else { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
1105 }
1106 }
1107 }
1108
1109 // Succeeded: Wrap up and return
1110 EnableDeathNotificationForClient(client, x);
1111 return(mStatus_NoError);
1112
1113 badparam:
1114 err = mStatus_BadParamErr;
1115 fail:
1116 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
1117 return(err);
1118 }
1119
1120 //*************************************************************************************************************
1121 // Resolve Service Info
1122
1123 mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
1124 {
1125 kern_return_t status;
1126 DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
1127 NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)query->info->InterfaceID;
1128 if (query->info->InterfaceID == mDNSInterface_LocalOnly) ifx = mDNSNULL;
1129 struct sockaddr_storage interface;
1130 struct sockaddr_storage address;
1131 char cstring[1024];
1132 int i, pstrlen = query->info->TXTinfo[0];
1133 (void)m; // Unused
1134
1135 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1136
1137 if (query->info->TXTlen > sizeof(cstring)) return;
1138
1139 mDNSPlatformMemZero(&interface, sizeof(interface));
1140 mDNSPlatformMemZero(&address, sizeof(address));
1141
1142 if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
1143 {
1144 struct sockaddr_in *s = (struct sockaddr_in*)&interface;
1145 s->sin_len = sizeof(*s);
1146 s->sin_family = AF_INET;
1147 s->sin_port = 0;
1148 s->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
1149 }
1150 else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
1151 {
1152 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&interface;
1153 sin6->sin6_len = sizeof(*sin6);
1154 sin6->sin6_family = AF_INET6;
1155 sin6->sin6_flowinfo = 0;
1156 sin6->sin6_port = 0;
1157 sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
1158 sin6->sin6_scope_id = ifx->scope_id;
1159 }
1160
1161 if (query->info->ip.type == mDNSAddrType_IPv4)
1162 {
1163 struct sockaddr_in *s = (struct sockaddr_in*)&address;
1164 s->sin_len = sizeof(*s);
1165 s->sin_family = AF_INET;
1166 s->sin_port = query->info->port.NotAnInteger;
1167 s->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger;
1168 }
1169 else
1170 {
1171 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&address;
1172 sin6->sin6_len = sizeof(*sin6);
1173 sin6->sin6_family = AF_INET6;
1174 sin6->sin6_port = query->info->port.NotAnInteger;
1175 sin6->sin6_flowinfo = 0;
1176 sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
1177 sin6->sin6_scope_id = ifx ? ifx->scope_id : 0;
1178 }
1179
1180 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1181 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1182 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1183 // ASCII-1 characters are used in the C-string as boundary markers,
1184 // to indicate the boundaries between the original constituent P-strings.
1185 for (i=1; i<query->info->TXTlen; i++)
1186 {
1187 if (--pstrlen >= 0)
1188 cstring[i-1] = query->info->TXTinfo[i];
1189 else
1190 {
1191 cstring[i-1] = 1;
1192 pstrlen = query->info->TXTinfo[i];
1193 }
1194 }
1195 cstring[i-1] = 0; // Put the terminating NULL on the end
1196
1197 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort,
1198 x->i.name.c, &query->info->ip, mDNSVal16(query->info->port));
1199 status = DNSServiceResolverReply_rpc(x->ClientMachPort,
1200 (char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT);
1201 if (status == MACH_SEND_TIMED_OUT)
1202 AbortBlockedClient(x->ClientMachPort, "resolve", x);
1203 }
1204
1205 mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client,
1206 DNSCString name, DNSCString regtype, DNSCString domain)
1207 {
1208 // Check client parameter
1209 (void)unusedserver; // Unused
1210 mStatus err = mStatus_NoError;
1211 const char *errormsg = "Unknown";
1212 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1213 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1214
1215 // Check other parameters
1216 domainlabel n;
1217 domainname t, d, srv;
1218 if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
1219 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
1220 if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Bad Domain"; goto badparam; }
1221 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
1222
1223 // Allocate memory, and handle failure
1224 DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x));
1225 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1226
1227 // Set up object, and link into list
1228 x->ClientMachPort = client;
1229 x->i.InterfaceID = mDNSInterface_Any;
1230 x->i.name = srv;
1231 x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
1232 x->next = DNSServiceResolverList;
1233 DNSServiceResolverList = x;
1234
1235 // Do the operation
1236 LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c);
1237 err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
1238 if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
1239
1240 // Succeeded: Wrap up and return
1241 EnableDeathNotificationForClient(client, x);
1242 return(mStatus_NoError);
1243
1244 badparam:
1245 err = mStatus_BadParamErr;
1246 fail:
1247 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err);
1248 return(err);
1249 }
1250
1251 //*************************************************************************************************************
1252 // Registration
1253
1254 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
1255 {
1256 m->p->NotifyUser = NonZeroTime(m->timenow + delay);
1257 }
1258
1259 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
1260 {
1261 ServiceInstance *si = (ServiceInstance*)srs->ServiceContext;
1262
1263 if (result == mStatus_NoError)
1264 {
1265 kern_return_t status;
1266 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
1267 status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
1268 if (status == MACH_SEND_TIMED_OUT)
1269 AbortBlockedClient(si->ClientMachPort, "registration success", si);
1270 if (si->autoname && CountPeerRegistrations(m, srs) == 0)
1271 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
1272 }
1273
1274 else if (result == mStatus_NameConflict)
1275 {
1276 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
1277 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1278 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1279 if (si->autoname && CountPeerRegistrations(m, srs) == 0)
1280 {
1281 // On conflict for an autoname service, rename and reregister *all* autoname services
1282 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
1283 m->MainCallback(m, mStatus_ConfigChanged);
1284 }
1285 else if (si->autoname)
1286 {
1287 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
1288 return;
1289 }
1290 else
1291 {
1292 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1293 // of their registration in the usual way (which we will catch via client death notification).
1294 // If the Mach queue is full, we forcibly abort the client immediately.
1295 kern_return_t status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
1296 if (status == MACH_SEND_TIMED_OUT)
1297 AbortBlockedClient(si->ClientMachPort, "registration conflict", NULL);
1298 }
1299 }
1300
1301 else if (result == mStatus_MemFree)
1302 {
1303 if (si->renameonmemfree) // We intentionally terminated registration so we could re-register with new name
1304 {
1305 debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
1306 si->renameonmemfree = mDNSfalse;
1307 si->name = m->nicelabel;
1308 mDNS_RenameAndReregisterService(m, srs, &si->name);
1309 }
1310 else
1311 {
1312 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1313 DNSServiceRegistration *r;
1314 for (r = DNSServiceRegistrationList; r; r = r->next)
1315 {
1316 ServiceInstance **sp = &r->regs;
1317 while (*sp)
1318 {
1319 if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; }
1320 sp = &(*sp)->next;
1321 }
1322 }
1323 // END SANITY CHECK
1324 FreeServiceInstance(si);
1325 }
1326 }
1327
1328 else if (result != mStatus_NATTraversal)
1329 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
1330 }
1331
1332 mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
1333 {
1334 mStatus err = 0;
1335 ServiceInstance *si = NULL;
1336 AuthRecord *SubTypes = NULL;
1337
1338 for (si = x->regs; si; si = si->next)
1339 {
1340 if (SameDomainName(&si->domain, domain))
1341 { LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; }
1342 }
1343
1344 SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype);
1345 if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr;
1346
1347 si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
1348 if (!si) return mStatus_NoMemoryErr;
1349
1350 si->ClientMachPort = x->ClientMachPort;
1351 si->renameonmemfree = mDNSfalse;
1352 si->autoname = x->autoname;
1353 si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
1354 si->domain = *domain;
1355
1356 err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL,
1357 x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
1358 if (!err)
1359 {
1360 si->next = x->regs;
1361 x->regs = si;
1362 }
1363 else
1364 {
1365 LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
1366 freeL("ServiceInstance", si);
1367 }
1368 return err;
1369 }
1370
1371 mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add)
1372 {
1373 DNSServiceRegistration *reg;
1374
1375 for (reg = DNSServiceRegistrationList; reg; reg = reg->next)
1376 {
1377 if (reg->DefaultDomain)
1378 {
1379 if (add)
1380 AddServiceInstance(reg, d);
1381 else
1382 {
1383 ServiceInstance **si = &reg->regs;
1384 while (*si)
1385 {
1386 if (SameDomainName(&(*si)->domain, d))
1387 {
1388 ServiceInstance *s = *si;
1389 *si = (*si)->next;
1390 if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s); // only free memory synchronously on error
1391 break;
1392 }
1393 si = &(*si)->next;
1394 }
1395 if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed
1396 }
1397 }
1398 }
1399 }
1400
1401 mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
1402 DNSCString name, DNSCString regtype, DNSCString domain, IPPort IpPort, DNSCString txtRecord)
1403 {
1404 (void)unusedserver; // Unused
1405 mStatus err = mStatus_NoError;
1406 const char *errormsg = "Unknown";
1407
1408 // older versions of this code passed the port via mach IPC as an int.
1409 // we continue to pass it as 4 bytes to maintain binary compatibility,
1410 // but now ensure that the network byte order is preserved by using a struct
1411 mDNSIPPort port;
1412 port.b[0] = IpPort.bytes[2];
1413 port.b[1] = IpPort.bytes[3];
1414
1415 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1416 if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
1417
1418 // Check for sub-types after the service type
1419 size_t reglen = strlen(regtype) + 1;
1420 if (reglen > MAX_ESCAPED_DOMAIN_NAME) { errormsg = "reglen too long"; goto badparam; }
1421 mDNSs32 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
1422 if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; }
1423
1424 // Check other parameters
1425 domainlabel n;
1426 domainname t, d;
1427 domainname srv;
1428 if (!name[0]) n = mDNSStorage.nicelabel;
1429 else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
1430 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
1431 if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
1432 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
1433
1434 unsigned char txtinfo[1024] = "";
1435 unsigned int data_len = 0;
1436 unsigned int size = sizeof(RDataBody);
1437 unsigned char *pstring = &txtinfo[data_len];
1438 char *ptr = txtRecord;
1439
1440 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1441 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1442 // Hence we have to convert the C-string to a P-string.
1443 // ASCII-1 characters are allowed in the C-string as boundary markers,
1444 // so that a single C-string can be used to represent one or more P-strings.
1445 while (*ptr)
1446 {
1447 if (++data_len >= sizeof(txtinfo)) { errormsg = "TXT record too long"; goto badtxt; }
1448 if (*ptr == 1) // If this is our boundary marker, start a new P-string
1449 {
1450 pstring = &txtinfo[data_len];
1451 pstring[0] = 0;
1452 ptr++;
1453 }
1454 else
1455 {
1456 if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; }
1457 pstring[++pstring[0]] = *ptr++;
1458 }
1459 }
1460
1461 data_len++;
1462 if (size < data_len)
1463 size = data_len;
1464
1465 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1466 // a port number of zero. When two instances of the protected client are allowed to run on one
1467 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1468 if (!mDNSIPPortIsZero(port))
1469 {
1470 int count = CountExistingRegistrations(&srv, port);
1471 if (count)
1472 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1473 client, count+1, srv.c, mDNSVal16(port));
1474 }
1475
1476 // Allocate memory, and handle failure
1477 DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
1478 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1479 mDNSPlatformMemZero(x, sizeof(*x));
1480
1481 // Set up object, and link into list
1482 x->ClientMachPort = client;
1483 x->DefaultDomain = !domain[0];
1484 x->autoname = (!name[0]);
1485 x->rdsize = size;
1486 x->NumSubTypes = NumSubTypes;
1487 memcpy(x->regtype, regtype, reglen);
1488 x->name = n;
1489 x->type = t;
1490 x->port = port;
1491 memcpy(x->txtinfo, txtinfo, 1024);
1492 x->txt_len = data_len;
1493 x->NextRef = 0;
1494 x->regs = NULL;
1495
1496 x->next = DNSServiceRegistrationList;
1497 DNSServiceRegistrationList = x;
1498
1499 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1500 x->ClientMachPort, name, regtype, domain, mDNSVal16(port));
1501
1502 err = AddServiceInstance(x, &d);
1503 if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; } // bail if .local (or explicit domain) fails
1504
1505 if (x->DefaultDomain)
1506 {
1507 DNameListElem *p;
1508 for (p = AutoRegistrationDomains; p; p = p->next)
1509 AddServiceInstance(x, &p->name);
1510 }
1511
1512 // Succeeded: Wrap up and return
1513 EnableDeathNotificationForClient(client, x);
1514 return(mStatus_NoError);
1515
1516 badtxt:
1517 LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
1518 badparam:
1519 err = mStatus_BadParamErr;
1520 fail:
1521 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1522 client, name, regtype, domain, mDNSVal16(port), errormsg, err);
1523 return(err);
1524 }
1525
1526 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
1527 {
1528 (void)m; // Unused
1529 if (result == mStatus_NoError)
1530 {
1531 if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
1532 LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
1533 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1534 RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond);
1535 }
1536 else if (result == mStatus_NameConflict)
1537 {
1538 LogOperation("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c);
1539 if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow);
1540 else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
1541 {
1542 // Tell the helper we've given up
1543 mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, NULL);
1544 }
1545 }
1546 else if (result == mStatus_GrowCache)
1547 {
1548 // Allocate another chunk of cache storage
1549 CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
1550 //LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
1551 if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
1552 }
1553 else if (result == mStatus_ConfigChanged)
1554 {
1555 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
1556 mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
1557 mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
1558
1559 // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
1560 DNSServiceRegistration *r;
1561 for (r = DNSServiceRegistrationList; r; r=r->next)
1562 if (r->autoname)
1563 {
1564 ServiceInstance *si;
1565 for (si = r->regs; si; si = si->next)
1566 {
1567 if (!SameDomainLabelCS(si->name.c, m->nicelabel.c))
1568 {
1569 debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
1570 si->renameonmemfree = mDNStrue;
1571 if (mDNS_DeregisterService(m, &si->srs)) // If service deregistered already, we can re-register immediately
1572 RegCallback(m, &si->srs, mStatus_MemFree);
1573 }
1574 }
1575 }
1576
1577 // Then we call into the UDS daemon code, to let it do the same
1578 udsserver_handle_configchange(m);
1579 }
1580 }
1581
1582 //*************************************************************************************************************
1583 // Add / Update / Remove records from existing Registration
1584
1585 mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1586 int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
1587 {
1588 // Check client parameter
1589 uint32_t id;
1590 mStatus err = mStatus_NoError;
1591 const char *errormsg = "Unknown";
1592 DNSServiceRegistration *x = DNSServiceRegistrationList;
1593 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1594 ServiceInstance *si;
1595 size_t size;
1596 (void)unusedserver; // Unused
1597 while (x && x->ClientMachPort != client) x = x->next;
1598 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
1599
1600 // Check other parameters
1601 if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
1602 if (data_len > sizeof(RDataBody)) size = data_len;
1603 else size = sizeof(RDataBody);
1604
1605 id = x->NextRef++;
1606 *reference = (natural_t)id;
1607 for (si = x->regs; si; si = si->next)
1608 {
1609 // Allocate memory, and handle failure
1610 ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
1611 if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1612
1613 // Fill in type, length, and data of new record
1614 extra->r.resrec.rrtype = type;
1615 extra->r.rdatastorage.MaxRDLength = size;
1616 extra->r.resrec.rdlength = data_len;
1617 memcpy(&extra->r.rdatastorage.u.data, data, data_len);
1618
1619 // Do the operation
1620 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1621 client, si->srs.RR_SRV.resrec.name->c, type, data_len, extra);
1622 err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl);
1623
1624 if (err)
1625 {
1626 freeL("Extra Resource Record", extra);
1627 errormsg = "mDNS_AddRecordToService";
1628 goto fail;
1629 }
1630
1631 extra->ClientID = id;
1632 }
1633
1634 return mStatus_NoError;
1635
1636 fail:
1637 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err);
1638 return mStatus_UnknownErr;
1639 }
1640
1641 mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
1642 {
1643 (void)m; // Unused
1644 if (OldRData != &rr->rdatastorage)
1645 freeL("Old RData", OldRData);
1646 }
1647
1648 mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRecord *rr, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
1649 {
1650 // Check client parameter
1651 mStatus err = mStatus_NoError;
1652 const char *errormsg = "Unknown";
1653 const domainname *name = (const domainname *)"";
1654
1655 name = srs->RR_SRV.resrec.name;
1656
1657 unsigned int size = sizeof(RDataBody);
1658 if (size < data_len)
1659 size = data_len;
1660
1661 // Allocate memory, and handle failure
1662 RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size);
1663 if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
1664
1665 // Fill in new length, and data
1666 newrdata->MaxRDLength = size;
1667 memcpy(&newrdata->u, data, data_len);
1668
1669 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1670 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1671 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1672 if (rr->resrec.rrtype == kDNSType_TXT && data_len == 0) { data_len = 1; newrdata->u.txt.c[0] = 0; }
1673
1674 // Do the operation
1675 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1676 client, srs->RR_SRV.resrec.name->c, data_len);
1677
1678 err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
1679 if (err)
1680 {
1681 errormsg = "mDNS_Update";
1682 freeL("RData", newrdata);
1683 return err;
1684 }
1685 return(mStatus_NoError);
1686
1687 fail:
1688 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err);
1689 return(err);
1690 }
1691
1692 mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1693 natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
1694 {
1695 // Check client parameter
1696 mStatus err = mStatus_NoError;
1697 const char *errormsg = "Unknown";
1698 const domainname *name = (const domainname *)"";
1699 ServiceInstance *si;
1700
1701 (void)unusedserver; // unused
1702 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1703 DNSServiceRegistration *x = DNSServiceRegistrationList;
1704 while (x && x->ClientMachPort != client) x = x->next;
1705 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
1706
1707 // Check other parameters
1708 if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
1709
1710 for (si = x->regs; si; si = si->next)
1711 {
1712 AuthRecord *r = NULL;
1713
1714 // Find the record we're updating. NULL reference means update the primary TXT record
1715 if (!reference) r = &si->srs.RR_TXT;
1716 else
1717 {
1718 ExtraResourceRecord *ptr;
1719 for (ptr = si->srs.Extras; ptr; ptr = ptr->next)
1720 {
1721 if ((natural_t)ptr->ClientID == reference)
1722 { r = &ptr->r; break; }
1723 }
1724 if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
1725 }
1726 err = UpdateRecord(&si->srs, client, r, data, data_len, ttl);
1727 if (err) goto fail; //!!!KRS this will cause failures for non-local defaults!
1728 }
1729
1730 return mStatus_NoError;
1731
1732 fail:
1733 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err);
1734 return(err);
1735 }
1736
1737 mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
1738 {
1739 const domainname *const name = srs->RR_SRV.resrec.name;
1740 mStatus err = mStatus_NoError;
1741
1742 // Do the operation
1743 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name->c);
1744
1745 err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
1746 if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
1747
1748 return err;
1749 }
1750
1751 mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
1752 natural_t reference)
1753 {
1754 // Check client parameter
1755 (void)unusedserver; // Unused
1756 mStatus err = mStatus_NoError;
1757 const char *errormsg = "Unknown";
1758 if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
1759 DNSServiceRegistration *x = DNSServiceRegistrationList;
1760 ServiceInstance *si;
1761
1762 while (x && x->ClientMachPort != client) x = x->next;
1763 if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
1764
1765 for (si = x->regs; si; si = si->next)
1766 {
1767 ExtraResourceRecord *e;
1768 for (e = si->srs.Extras; e; e = e->next)
1769 {
1770 if ((natural_t)e->ClientID == reference)
1771 {
1772 err = RemoveRecord(&si->srs, e, client);
1773 break;
1774 }
1775 }
1776 if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
1777 }
1778
1779 return mStatus_NoError;
1780
1781 fail:
1782 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err);
1783 return(err);
1784 }
1785
1786 //*************************************************************************************************************
1787 // Support Code
1788
1789 mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
1790 {
1791 mig_reply_error_t *request = msg;
1792 mig_reply_error_t *reply;
1793 mach_msg_return_t mr;
1794 int options;
1795 (void)port; // Unused
1796 (void)size; // Unused
1797 (void)info; // Unused
1798
1799 KQueueLock(&mDNSStorage);
1800
1801 /* allocate a reply buffer */
1802 reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
1803
1804 /* call the MiG server routine */
1805 (void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head);
1806
1807 if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS))
1808 {
1809 if (reply->RetCode == MIG_NO_REPLY)
1810 {
1811 /*
1812 * This return code is a little tricky -- it appears that the
1813 * demux routine found an error of some sort, but since that
1814 * error would not normally get returned either to the local
1815 * user or the remote one, we pretend it's ok.
1816 */
1817 CFAllocatorDeallocate(NULL, reply);
1818 goto done;
1819 }
1820
1821 /*
1822 * destroy any out-of-line data in the request buffer but don't destroy
1823 * the reply port right (since we need that to send an error message).
1824 */
1825 request->Head.msgh_remote_port = MACH_PORT_NULL;
1826 mach_msg_destroy(&request->Head);
1827 }
1828
1829 if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
1830 {
1831 /* no reply port, so destroy the reply */
1832 if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
1833 mach_msg_destroy(&reply->Head);
1834 CFAllocatorDeallocate(NULL, reply);
1835 goto done;
1836 }
1837
1838 /*
1839 * send reply.
1840 *
1841 * We don't want to block indefinitely because the client
1842 * isn't receiving messages from the reply port.
1843 * If we have a send-once right for the reply port, then
1844 * this isn't a concern because the send won't block.
1845 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1846 * To avoid falling off the kernel's fast RPC path unnecessarily,
1847 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1848 */
1849
1850 options = MACH_SEND_MSG;
1851 if (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
1852 options |= MACH_SEND_TIMEOUT;
1853
1854 mr = mach_msg(&reply->Head, /* msg */
1855 options, /* option */
1856 reply->Head.msgh_size, /* send_size */
1857 0, /* rcv_size */
1858 MACH_PORT_NULL, /* rcv_name */
1859 MACH_MSG_TIMEOUT_NONE, /* timeout */
1860 MACH_PORT_NULL); /* notify */
1861
1862 /* Has a message error occurred? */
1863 switch (mr)
1864 {
1865 case MACH_SEND_INVALID_DEST:
1866 case MACH_SEND_TIMED_OUT:
1867 /* the reply can't be delivered, so destroy it */
1868 mach_msg_destroy(&reply->Head);
1869 break;
1870
1871 default :
1872 /* Includes success case. */
1873 break;
1874 }
1875
1876 CFAllocatorDeallocate(NULL, reply);
1877
1878 done:
1879 KQueueUnlock(&mDNSStorage, "Mach client event");
1880 }
1881
1882 mDNSlocal kern_return_t registerBootstrapService()
1883 {
1884 kern_return_t status;
1885 mach_port_t service_send_port, service_rcv_port;
1886
1887 debugf("Registering Bootstrap Service");
1888
1889 /*
1890 * See if our service name is already registered and if we have privilege to check in.
1891 */
1892 status = bootstrap_check_in(bootstrap_port, (char*)kmDNSBootstrapName, &service_rcv_port);
1893 if (status == KERN_SUCCESS)
1894 {
1895 /*
1896 * If so, we must be a followup instance of an already defined server. In that case,
1897 * the bootstrap port we inherited from our parent is the server's privilege port, so set
1898 * that in case we have to unregister later (which requires the privilege port).
1899 */
1900 server_priv_port = bootstrap_port;
1901 restarting_via_mach_init = TRUE;
1902 }
1903 else if (status == BOOTSTRAP_UNKNOWN_SERVICE)
1904 {
1905 status = bootstrap_create_server(bootstrap_port, "/usr/sbin/mDNSResponder", getuid(),
1906 FALSE /* relaunch immediately, not on demand */, &server_priv_port);
1907 if (status != KERN_SUCCESS) return status;
1908
1909 status = bootstrap_create_service(server_priv_port, (char*)kmDNSBootstrapName, &service_send_port);
1910 if (status != KERN_SUCCESS)
1911 {
1912 mach_port_deallocate(mach_task_self(), server_priv_port);
1913 return status;
1914 }
1915
1916 status = bootstrap_check_in(server_priv_port, (char*)kmDNSBootstrapName, &service_rcv_port);
1917 if (status != KERN_SUCCESS)
1918 {
1919 mach_port_deallocate(mach_task_self(), server_priv_port);
1920 mach_port_deallocate(mach_task_self(), service_send_port);
1921 return status;
1922 }
1923 assert(service_send_port == service_rcv_port);
1924 }
1925
1926 /*
1927 * We have no intention of responding to requests on the service port. We are not otherwise
1928 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
1929 * So, we can dispose of all the rights we have for the service port. We don't destroy the
1930 * send right for the server's privileged bootstrap port - in case we have to unregister later.
1931 */
1932 mach_port_destroy(mach_task_self(), service_rcv_port);
1933 return status;
1934 }
1935
1936 mDNSlocal kern_return_t destroyBootstrapService()
1937 {
1938 debugf("Destroying Bootstrap Service");
1939 return bootstrap_register(server_priv_port, (char*)kmDNSBootstrapName, MACH_PORT_NULL);
1940 }
1941
1942 mDNSlocal void ExitCallback(int sig)
1943 {
1944 (void)sig; // Unused
1945 LogMsgIdent(mDNSResponderVersionString, "stopping");
1946
1947 debugf("ExitCallback");
1948 if (!mDNS_DebugMode && !started_via_launchdaemon)
1949 destroyBootstrapService();
1950
1951 debugf("ExitCallback: Aborting MIG clients");
1952 while (DNSServiceDomainEnumerationList)
1953 AbortClient(DNSServiceDomainEnumerationList->ClientMachPort, DNSServiceDomainEnumerationList);
1954 while (DNSServiceBrowserList)
1955 AbortClient(DNSServiceBrowserList ->ClientMachPort, DNSServiceBrowserList);
1956 while (DNSServiceResolverList)
1957 AbortClient(DNSServiceResolverList ->ClientMachPort, DNSServiceResolverList);
1958 while (DNSServiceRegistrationList)
1959 AbortClient(DNSServiceRegistrationList ->ClientMachPort, DNSServiceRegistrationList);
1960
1961 if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed");
1962
1963 debugf("ExitCallback: mDNS_StartExit");
1964 mDNS_StartExit(&mDNSStorage);
1965 }
1966
1967 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
1968 mDNSlocal void HandleSIG(int sig)
1969 {
1970 debugf(" ");
1971 debugf("HandleSIG %d", sig);
1972 mach_msg_header_t header;
1973 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
1974 header.msgh_remote_port = signal_port;
1975 header.msgh_local_port = MACH_PORT_NULL;
1976 header.msgh_size = sizeof(header);
1977 header.msgh_id = sig;
1978 if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
1979 {
1980 LogMsg("HandleSIG %d: mach_msg_send failed", sig);
1981 if (sig == SIGTERM || sig == SIGINT) exit(-1);
1982 }
1983 }
1984
1985 mDNSlocal void CatchABRT(int sig)
1986 {
1987 LogMsg("Received SIGABRT %d", sig);
1988 sleep(1); // Pause to make sure syslog gets the message
1989 while(1) *(long*)0 = 0; // Generate a CrashReporter stack trace so we can find out what library called abort();
1990 }
1991
1992 mDNSlocal void INFOCallback(void)
1993 {
1994 mDNSs32 utc = mDNSPlatformUTC();
1995 DNSServiceDomainEnumeration *e;
1996 DNSServiceBrowser *b;
1997 DNSServiceResolver *l;
1998 DNSServiceRegistration *r;
1999 NetworkInterfaceInfoOSX *i;
2000 DNSServer *s;
2001
2002 LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
2003
2004 udsserver_info(&mDNSStorage);
2005
2006 LogMsgNoIdent("--------- Mach Clients ---------");
2007 if (!DNSServiceDomainEnumerationList && !DNSServiceBrowserList && !DNSServiceResolverList && !DNSServiceRegistrationList)
2008 LogMsgNoIdent("<None>");
2009 else
2010 {
2011 for (e = DNSServiceDomainEnumerationList; e; e=e->next)
2012 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
2013
2014 for (b = DNSServiceBrowserList; b; b=b->next)
2015 {
2016 DNSServiceBrowserQuestion *qptr;
2017 for (qptr = b->qlist; qptr; qptr = qptr->next)
2018 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c);
2019 }
2020 for (l = DNSServiceResolverList; l; l=l->next)
2021 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
2022
2023 for (r = DNSServiceRegistrationList; r; r=r->next)
2024 {
2025 ServiceInstance *si;
2026 for (si = r->regs; si; si = si->next)
2027 LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
2028 }
2029 }
2030
2031 LogMsgNoIdent("----- KQSocketEventSources -----");
2032 if (!gEventSources) LogMsgNoIdent("<None>");
2033 else
2034 {
2035 KQSocketEventSource *k;
2036 for (k = gEventSources; k; k=k->next)
2037 LogMsgNoIdent("%3d %s", k->fd, k->kqs.KQtask);
2038 }
2039
2040 LogMsgNoIdent("------ Network Interfaces ------");
2041 if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
2042 else
2043 {
2044 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
2045 {
2046 if (!i->Exists)
2047 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds",
2048 i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
2049 &i->ifinfo.ip, utc - i->LastSeen);
2050 else
2051 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a",
2052 i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
2053 i->ifinfo.InterfaceActive ? "Active" : " ",
2054 i->ifinfo.IPv4Available ? "v4" : " ",
2055 i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr,
2056 i->ifinfo.IPv6Available ? "v6" : " ",
2057 i->ifinfo.InterfaceID,
2058 i->ifinfo.Advertise ? "Adv" : " ",
2059 i->ifinfo.McastTxRx ? "TxRx" : " ",
2060 &i->ifinfo.ip);
2061 }
2062 }
2063
2064 LogMsgNoIdent("--------- DNS Servers ----------");
2065 if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
2066 else
2067 {
2068 for (s = mDNSStorage.DNSServers; s; s = s->next)
2069 {
2070 NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)s->interface;
2071 LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
2072 s->domain.c, ifx ? ifx->ifa_name : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
2073 s->teststate == DNSServer_Untested ? "(Untested)" :
2074 s->teststate == DNSServer_Passed ? "" :
2075 s->teststate == DNSServer_Failed ? "(Failed)" :
2076 s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
2077 }
2078 }
2079
2080 mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
2081 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
2082
2083 LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
2084 }
2085
2086 mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
2087 {
2088 (void)port; // Unused
2089 (void)size; // Unused
2090 (void)info; // Unused
2091 mach_msg_header_t *msg_header = (mach_msg_header_t *)msg;
2092 mDNS *const m = &mDNSStorage;
2093
2094 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
2095 KQueueLock(m);
2096 switch(msg_header->msgh_id)
2097 {
2098 case SIGHUP: {
2099 mDNSu32 slot;
2100 CacheGroup *cg;
2101 CacheRecord *rr;
2102 LogMsg("SIGHUP: Purge cache");
2103 FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr);
2104 } break;
2105 case SIGINT:
2106 case SIGTERM: ExitCallback(msg_header->msgh_id); break;
2107 case SIGINFO: INFOCallback(); break;
2108 case SIGUSR1: // mDNSCoreMachineSleep(m, !m->SleepState); break;
2109 LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2110 mDNSMacOSXNetworkChanged(m);
2111
2112 // Simulate KeychainChanged
2113 mDNS_Lock(m);
2114 SetDomainSecrets(m);
2115 mDNS_Unlock(m);
2116
2117 break;
2118 case SIGUSR2: SigLogLevel(); break;
2119 default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break;
2120 }
2121 KQueueUnlock(m, "Unix Signal");
2122 }
2123
2124 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2125 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2126
2127 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
2128 {
2129 mStatus err;
2130 CFMachPortRef s_port;
2131
2132 // If launchd already created our Mach port for us, then use that, else we create a new one of our own
2133 if (m_port != MACH_PORT_NULL)
2134 s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL);
2135 else
2136 {
2137 s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
2138 m_port = CFMachPortGetPort(s_port);
2139 char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2140 kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
2141
2142 if (status)
2143 {
2144 if (status == 1103)
2145 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2146 else
2147 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
2148 return(status);
2149 }
2150 }
2151
2152 CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
2153 CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
2154 CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
2155 CFRunLoopSourceRef s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
2156 CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
2157
2158 err = mDNS_Init(&mDNSStorage, &PlatformStorage,
2159 rrcachestorage, RR_CACHE_SIZE,
2160 mDNS_Init_AdvertiseLocalAddresses,
2161 mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
2162
2163 if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
2164
2165 client_death_port = CFMachPortGetPort(d_port);
2166 signal_port = CFMachPortGetPort(i_port);
2167
2168 CFRunLoop = CFRunLoopGetCurrent();
2169 CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode);
2170 CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode);
2171 CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode);
2172 CFRelease(d_rls);
2173 CFRelease(s_rls);
2174 CFRelease(i_rls);
2175 if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
2176 return(err);
2177 }
2178
2179 mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
2180 {
2181 mDNSs32 now = mDNS_TimeNow(m);
2182
2183 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2184 // Detailed reason:
2185 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2186 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2187 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2188 // we then systematically lose our own looped-back packets.
2189 if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m);
2190
2191 // KeyChain frequently fails to notify clients of change events. To work around this
2192 // we set a timer and periodically poll to detect if any changes have occurred.
2193 // Without this Back To My Mac just does't work for a large number of users.
2194 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
2195 if (m->p->KeyChainBugTimer && now - m->p->KeyChainBugTimer >= 0)
2196 {
2197 m->p->KeyChainBugInterval *= 2;
2198 m->p->KeyChainBugTimer = NonZeroTime(now + m->p->KeyChainBugInterval);
2199 if (m->p->KeyChainBugInterval > 2 * mDNSPlatformOneSecond) m->p->KeyChainBugTimer = 0;
2200 mDNS_Lock(m);
2201 SetDomainSecrets(m);
2202 mDNS_Unlock(m);
2203 }
2204
2205 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2206 mDNSs32 nextevent = mDNS_Execute(m);
2207
2208 if (m->p->NetworkChanged)
2209 if (nextevent - m->p->NetworkChanged > 0)
2210 nextevent = m->p->NetworkChanged;
2211
2212 if (m->p->KeyChainBugTimer)
2213 if (nextevent - m->p->KeyChainBugTimer > 0)
2214 nextevent = m->p->KeyChainBugTimer;
2215
2216 // 3. Deliver any waiting browse messages to clients
2217 DNSServiceBrowser *b = DNSServiceBrowserList;
2218
2219 while (b)
2220 {
2221 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2222 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2223 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2224 DNSServiceBrowser *x = b;
2225 b = b->next;
2226 if (x->results) // Try to deliver the list of results
2227 {
2228 while (x->results)
2229 {
2230 DNSServiceBrowserResult *const r = x->results;
2231 domainlabel name;
2232 domainname type, domain;
2233 DeconstructServiceName(&r->result, &name, &type, &domain); // Don't need to check result; already validated in FoundInstance()
2234 char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2235 char ctype[MAX_ESCAPED_DOMAIN_NAME];
2236 char cdom [MAX_ESCAPED_DOMAIN_NAME];
2237 ConvertDomainLabelToCString_unescaped(&name, cname);
2238 ConvertDomainNameToCString(&type, ctype);
2239 ConvertDomainNameToCString(&domain, cdom);
2240 DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0;
2241 kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, cname, ctype, cdom, flags, 1);
2242 // If we failed to send the mach message, try again in one second
2243 if (status == MACH_SEND_TIMED_OUT)
2244 {
2245 if (nextevent - now > mDNSPlatformOneSecond)
2246 nextevent = now + mDNSPlatformOneSecond;
2247 break;
2248 }
2249 else
2250 {
2251 x->lastsuccess = now;
2252 x->results = x->results->next;
2253 freeL("DNSServiceBrowserResult", r);
2254 }
2255 }
2256 // If this client hasn't read a single message in the last 60 seconds, abort it
2257 if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond)
2258 AbortBlockedClient(x->ClientMachPort, "browse", x);
2259 }
2260 }
2261
2262 DNSServiceResolver *l;
2263 for (l = DNSServiceResolverList; l; l=l->next)
2264 if (l->ReportTime && now - l->ReportTime >= 0)
2265 {
2266 l->ReportTime = 0;
2267 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2268 "This places considerable burden on the network.", l->i.name.c);
2269 }
2270
2271 if (m->p->NotifyUser)
2272 {
2273 if (m->p->NotifyUser - now < 0)
2274 {
2275 if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c))
2276 {
2277 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
2278 mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
2279 m->p->usernicelabel = m->nicelabel;
2280 }
2281 if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
2282 {
2283 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
2284 mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
2285 m->p->HostNameConflict = 0; // Clear our indicator, now name change has been successful
2286 m->p->userhostlabel = m->hostlabel;
2287 }
2288 m->p->NotifyUser = 0;
2289 }
2290 else
2291 if (nextevent - m->p->NotifyUser > 0)
2292 nextevent = m->p->NotifyUser;
2293 }
2294
2295 return(nextevent);
2296 }
2297
2298 mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
2299 {
2300 mDNS_Lock(m);
2301
2302 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2303
2304 // NOTE: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent
2305
2306 if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
2307 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2308 m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
2309 if (m->NewLocalOnlyQuestions)
2310 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2311 m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
2312 if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
2313 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
2314 if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
2315 LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending);
2316 #ifndef UNICAST_DISABLED
2317 if (m->timenow - m->NextuDNSEvent >= 0)
2318 LogMsg("Task Scheduling Error: NextuDNSEvent %d", m->timenow - m->NextuDNSEvent);
2319 #endif
2320 if (m->timenow - m->NextCacheCheck >= 0)
2321 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck);
2322 if (m->timenow - m->NextScheduledQuery >= 0)
2323 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery);
2324 if (m->timenow - m->NextScheduledProbe >= 0)
2325 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe);
2326 if (m->timenow - m->NextScheduledResponse >= 0)
2327 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
2328 if (m->timenow - m->NextScheduledNATOp >= 0)
2329 LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp);
2330
2331 mDNS_Unlock(&mDNSStorage);
2332 }
2333
2334 mDNSlocal mDNSBool ReadyForSleep(mDNS *m)
2335 {
2336 (void)m;
2337
2338 // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server
2339 DNSQuestion *q;
2340 for (q = m->Questions; q; q = q->next)
2341 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) return(mDNSfalse);
2342
2343 // 2. Scan list of registered records
2344 AuthRecord *rr;
2345 for (rr = m->ResourceRecords; rr; rr = rr->next)
2346 if (rr->state == regState_Refresh && rr->tcp) return(mDNSfalse);
2347
2348 // 2. Scan list of registered services
2349 ServiceRecordSet *srs;
2350 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
2351 if (srs->state == regState_NoTarget && srs->tcp) return(mDNSfalse);
2352
2353 return(mDNStrue);
2354 }
2355
2356 mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
2357 {
2358 // Read all of the bytes so we won't wake again.
2359 char buffer[100];
2360 while (recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT) > 0) continue;
2361 }
2362
2363 mDNSlocal void * KQueueLoop(void *m_param)
2364 {
2365 mDNS *m = m_param;
2366 int numevents = 0;
2367
2368 #if USE_SELECT_WITH_KQUEUEFD
2369 fd_set readfds;
2370 FD_ZERO(&readfds);
2371 const int multiplier = 1000000 / mDNSPlatformOneSecond;
2372 #else
2373 const int multiplier = 1000000000 / mDNSPlatformOneSecond;
2374 #endif
2375
2376 pthread_mutex_lock(&PlatformStorage.BigMutex);
2377 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
2378
2379 // This is the main work loop:
2380 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2381 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2382 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2383 // (4) On wakeup we first process *all* events
2384 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2385 for ( ; ; )
2386 {
2387 #define kEventsToReadAtOnce 1
2388 struct kevent new_events[kEventsToReadAtOnce];
2389
2390 // Run mDNS_Execute to find out the time we next need to wake up
2391 mDNSs32 start = mDNSPlatformRawTime();
2392 mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
2393 mDNSs32 end = mDNSPlatformRawTime();
2394 if (end - start >= WatchDogReportingThreshold)
2395 LogOperation("WARNING: Idle task took %dms to complete", end - start);
2396
2397 mDNSs32 now = mDNS_TimeNow(m);
2398
2399 if (m->ShutdownTime)
2400 {
2401 if (mDNS_ExitNow(m, now))
2402 {
2403 LogOperation("mDNS_FinalExit");
2404 mDNS_FinalExit(&mDNSStorage);
2405 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
2406 exit(0);
2407 }
2408 if (nextTimerEvent - m->ShutdownTime >= 0)
2409 nextTimerEvent = m->ShutdownTime;
2410 }
2411
2412 if (m->p->SleepLimit)
2413 {
2414 mDNSBool ready = ReadyForSleep(m);
2415 if (ready || now - m->p->SleepLimit >= 0)
2416 {
2417 LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m->p->SleepCookie,
2418 ready ? "ready for sleep" : "giving up", now, m->p->SleepLimit - now);
2419 m->p->SleepLimit = 0;
2420 IOAllowPowerChange(m->p->PowerConnection, m->p->SleepCookie);
2421 }
2422 else
2423 if (nextTimerEvent - m->p->SleepLimit >= 0)
2424 nextTimerEvent = m->p->SleepLimit;
2425 }
2426
2427 // Convert absolute wakeup time to a relative time from now
2428 mDNSs32 ticks = nextTimerEvent - now;
2429 if (ticks < 1) ticks = 1;
2430
2431 static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
2432 if (ticks > 1)
2433 RepeatedBusy = 0;
2434 else
2435 {
2436 ticks = 1;
2437 if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
2438 }
2439
2440 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents, ticks);
2441 numevents = 0;
2442
2443 // Release the lock, and sleep until:
2444 // 1. Something interesting happens like a packet arriving, or
2445 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
2446 // 3. The timeout expires
2447 pthread_mutex_unlock(&PlatformStorage.BigMutex);
2448
2449 #if USE_SELECT_WITH_KQUEUEFD
2450 struct timeval timeout;
2451 timeout.tv_sec = ticks / mDNSPlatformOneSecond;
2452 timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * multiplier;
2453 FD_SET(KQueueFD, &readfds);
2454 if (select(KQueueFD+1, &readfds, NULL, NULL, &timeout) < 0)
2455 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
2456 #else
2457 struct timespec timeout;
2458 timeout.tv_sec = ticks / mDNSPlatformOneSecond;
2459 timeout.tv_nsec = (ticks % mDNSPlatformOneSecond) * multiplier;
2460 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
2461 // and have it work similarly to the way it does with nevents non-zero --
2462 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
2463 // In fact, what happens if you do this is that it just returns immediately. So, we have
2464 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
2465 if (kevent(KQueueFD, NULL, 0, new_events, 1, &timeout) < 0)
2466 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
2467 #endif
2468
2469 pthread_mutex_lock(&PlatformStorage.BigMutex);
2470 // We have to ignore the event we may have been told about above, because that
2471 // was done without holding the lock, and between the time we woke up and the
2472 // time we reclaimed the lock the other thread could have done something that
2473 // makes the event no longer valid. Now we have the lock, we call kevent again
2474 // and this time we can safely process the events it tells us about.
2475
2476 static const struct timespec zero_timeout = { 0, 0 };
2477 int events_found;
2478 while ((events_found = kevent(KQueueFD, NULL, 0, new_events, kEventsToReadAtOnce, &zero_timeout)) != 0)
2479 {
2480 if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR))
2481 {
2482 // Not sure what to do here, our kqueue has failed us - this isn't ideal
2483 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno));
2484 exit(errno);
2485 }
2486
2487 numevents += events_found;
2488
2489 int i;
2490 for (i = 0; i < events_found; i++)
2491 {
2492 const KQueueEntry *const kqentry = new_events[i].udata;
2493 mDNSs32 stime = mDNSPlatformRawTime();
2494 #if LogAllOperations || MDNS_DEBUGMSGS
2495 const char *const KQtask = kqentry->KQtask; // Grab a copy in case KQcallback deletes the task
2496 #endif
2497 kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext);
2498 mDNSs32 etime = mDNSPlatformRawTime();
2499 if (etime - stime >= WatchDogReportingThreshold)
2500 LogOperation("WARNING: %s took %dms to complete", KQtask, etime - stime);
2501 }
2502 }
2503 }
2504
2505 return NULL;
2506 }
2507
2508 mDNSlocal void LaunchdCheckin(void)
2509 {
2510 launch_data_t msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
2511 launch_data_t resp = launch_msg(msg);
2512 launch_data_free(msg);
2513 if (!resp) { LogMsg("launch_msg returned NULL"); return; }
2514
2515 if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
2516 {
2517 int err = launch_data_get_errno(resp);
2518 // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
2519 if (err != EACCES) LogMsg("launch_msg returned %d", err);
2520 else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err);
2521 }
2522 else
2523 {
2524 launch_data_t skts = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
2525 if (!skts) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
2526 else
2527 {
2528 launch_data_t skt = launch_data_dict_lookup(skts, "Listeners");
2529 if (!skt) LogMsg("launch_data_dict_lookup Listeners returned NULL");
2530 else
2531 {
2532 launch_data_t s = launch_data_array_get_index(skt, 0);
2533 if (!s) LogMsg("launch_data_array_get_index(skt, 0) returned NULL");
2534 else
2535 {
2536 launchd_fd = launch_data_get_fd(s);
2537 LogOperation("Launchd Unix Domain Socket: %d", launchd_fd);
2538 // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
2539 chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
2540 }
2541 }
2542 }
2543
2544 launch_data_t ports = launch_data_dict_lookup(resp, "MachServices");
2545 if (!ports) LogMsg("launch_data_dict_lookup MachServices returned NULL");
2546 else
2547 {
2548 launch_data_t p = launch_data_dict_lookup(ports, "com.apple.mDNSResponder");
2549 if (!p) LogOperation("launch_data_array_get_index(ports, 0) returned NULL");
2550 else
2551 {
2552 m_port = launch_data_get_fd(p);
2553 LogOperation("Launchd Mach Port: %d", m_port);
2554 if (m_port == ~0U) m_port = MACH_PORT_NULL;
2555 }
2556 }
2557 }
2558 launch_data_free(resp);
2559 }
2560
2561 mDNSlocal void DropPrivileges(void)
2562 {
2563 static const char login[] = "_mdnsresponder";
2564 struct passwd *pwd = getpwnam(login);
2565 if (NULL == pwd)
2566 LogMsg("Could not find account name \"%s\". Running as root.", login);
2567 else
2568 {
2569 uid_t uid = pwd->pw_uid;
2570 gid_t gid = pwd->pw_gid;
2571
2572 LogMsg("Started as root. Switching to userid \"%s\".", login);
2573
2574 if (unlink(MDNS_UDS_SERVERPATH) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, errno, strerror(errno));
2575 else
2576 {
2577 static char path[] = "/var/run/mdns/mDNSResponder";
2578 char *p = strrchr(path, '/');
2579 *p = '\0';
2580 if (mkdir(path, 0755) < 0 && errno != EEXIST) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path, errno, strerror(errno));
2581 else if (chown(path, uid, gid) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path, errno, strerror(errno));
2582 else
2583 {
2584 *p = '/';
2585 if (unlink(path) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path, errno, strerror(errno));
2586 else if (symlink(path, MDNS_UDS_SERVERPATH) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, path, errno, strerror(errno));
2587 else LogOperation("DropPrivileges: Created subdirectory and symlink");
2588 }
2589 }
2590
2591 if (0 != initgroups(login, gid)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login, (unsigned long)gid);
2592 if (0 != setgid(gid)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
2593 if (0 != setuid(uid)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid);
2594 }
2595 }
2596
2597 extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import));
2598
2599 mDNSexport int main(int argc, char **argv)
2600 {
2601 int i;
2602 kern_return_t status;
2603 pthread_t KQueueThread;
2604
2605 LogMsgIdent(mDNSResponderVersionString, "starting");
2606
2607 if (0 == geteuid()) DropPrivileges();
2608
2609 for (i=1; i<argc; i++)
2610 {
2611 if (!strcasecmp(argv[i], "-d" )) mDNS_DebugMode = mDNStrue;
2612 if (!strcasecmp(argv[i], "-launchd" )) started_via_launchdaemon = mDNStrue;
2613 if (!strcasecmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
2614 }
2615
2616 signal(SIGHUP, HandleSIG); // (Debugging) Purge the cache to check for cache handling bugs
2617 signal(SIGINT, HandleSIG); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2618 signal(SIGABRT, CatchABRT); // For debugging -- SIGABRT should never happen
2619 signal(SIGPIPE, SIG_IGN ); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2620 signal(SIGTERM, HandleSIG); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2621 signal(SIGINFO, HandleSIG); // (Debugging) Write state snapshot to syslog
2622 signal(SIGUSR1, HandleSIG); // (Debugging) Simulate network change notification from System Configuration Framework
2623 signal(SIGUSR2, HandleSIG); // (Debugging) Change log level
2624
2625 mDNSStorage.p = &PlatformStorage; // Make sure mDNSStorage.p is set up, because validatelists uses it
2626 LaunchdCheckin();
2627
2628 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2629 if (!mDNS_DebugMode && !started_via_launchdaemon)
2630 {
2631 registerBootstrapService();
2632 if (!restarting_via_mach_init) exit(0); // mach_init will restart us immediately as a daemon
2633 int fd = open(_PATH_DEVNULL, O_RDWR, 0);
2634 if (fd < 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno, strerror(errno));
2635 else
2636 {
2637 // Avoid unnecessarily duplicating a file descriptor to itself
2638 if (fd != STDIN_FILENO) if (dup2(fd, STDIN_FILENO) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno, strerror(errno));
2639 if (fd != STDOUT_FILENO) if (dup2(fd, STDOUT_FILENO) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno, strerror(errno));
2640 if (fd != STDERR_FILENO) if (dup2(fd, STDERR_FILENO) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno, strerror(errno));
2641 if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) (void)close(fd);
2642 }
2643 }
2644
2645 // Create the kqueue, mutex and thread to support KQSockets
2646 KQueueFD = kqueue();
2647 if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
2648
2649 i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL);
2650 if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
2651
2652 int fdpair[2] = {0, 0};
2653 i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair);
2654 if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
2655
2656 // Socket pair returned us two identical sockets connected to each other
2657 // We will use the first socket to send the second socket. The second socket
2658 // will be added to the kqueue so it will wake when data is sent.
2659 static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" };
2660 PlatformStorage.WakeKQueueLoopFD = fdpair[0];
2661 KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry);
2662
2663 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
2664 #if MDNS_NO_SANDBOX
2665 LogMsg("Note: Compiled without Apple Sandbox support");
2666 #else
2667 if (!sandbox_init)
2668 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
2669 else
2670 {
2671 char *sandbox_msg;
2672 int sandbox_err = sandbox_init("mDNSResponder", SANDBOX_NAMED, &sandbox_msg);
2673 if (sandbox_err) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg); sandbox_free_error(sandbox_msg); }
2674 else LogOperation("Now running under Apple Sandbox restrictions");
2675 }
2676 #endif
2677
2678 OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
2679 status = mDNSDaemonInitialize();
2680 if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
2681 status = udsserver_init(launchd_fd);
2682 if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
2683
2684 // Start the kqueue thread
2685 i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
2686 if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
2687
2688 if (status == 0)
2689 {
2690 CFRunLoopRun();
2691 LogMsg("ERROR: CFRunLoopRun Exiting.");
2692 mDNS_Close(&mDNSStorage);
2693 }
2694
2695 LogMsgIdent(mDNSResponderVersionString, "exiting");
2696
2697 exit:
2698 if (!mDNS_DebugMode && !started_via_launchdaemon) destroyBootstrapService();
2699 return(status);
2700 }
2701
2702 // uds_daemon.c support routines /////////////////////////////////////////////
2703
2704 // Arrange things so that callback is called with context when data appears on fd
2705 mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
2706 {
2707 KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
2708 if (!newSource) return mStatus_NoMemoryErr;
2709
2710 mDNSPlatformMemZero(newSource, sizeof(*newSource));
2711 newSource->fd = fd;
2712 newSource->kqs.KQcallback = callback;
2713 newSource->kqs.KQcontext = context;
2714 newSource->kqs.KQtask = "UDS client";
2715
2716 if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
2717 {
2718 KQSocketEventSource **p = &gEventSources;
2719 while (*p) p = &(*p)->next;
2720 *p = newSource;
2721 return mStatus_NoError;
2722 }
2723 else
2724 {
2725 close(fd);
2726 free(newSource);
2727 return mStatus_NoMemoryErr;
2728 }
2729 }
2730
2731 mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
2732 {
2733 KQSocketEventSource **p = &gEventSources;
2734 while (*p && (*p)->fd != fd) p = &(*p)->next;
2735 if (*p)
2736 {
2737 KQSocketEventSource *s = *p;
2738 *p = (*p)->next;
2739 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
2740 // causes the kernel to automatically remove any associated kevents
2741 close(s->fd);
2742 freeL("KQSocketEventSource", s);
2743 return mStatus_NoError;
2744 }
2745 return mStatus_NoSuchNameErr;
2746 }
2747
2748 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2749 const char *__crashreporter_info__ = mDNSResponderVersionString;
2750 asm(".desc ___crashreporter_info__, 0x10");
2751
2752 // For convenience when using the "strings" command, this is the last thing in the file
2753 // The "@(#) " pattern is a special prefix the "what" command looks for
2754 mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";