]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/uds_daemon.c
mDNSResponder-108.4.tar.gz
[apple/mdnsresponder.git] / mDNSShared / uds_daemon.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23
24 Change History (most recent first):
25
26 $Log: uds_daemon.c,v $
27 Revision 1.199.2.1 2007/01/06 03:22:03 cheshire
28 <rdar://problem/4912058> Crash at resolve_result_callback + 192
29
30 Revision 1.199 2006/06/28 08:53:39 cheshire
31 Added (commented out) debugging messages
32
33 Revision 1.198 2006/06/27 20:16:07 cheshire
34 Fix code layout
35
36 Revision 1.197 2006/05/18 01:32:35 cheshire
37 <rdar://problem/4472706> iChat: Lost connection with Bonjour
38 (mDNSResponder insufficiently defensive against malformed browsing PTR responses)
39
40 Revision 1.196 2006/05/05 07:07:13 cheshire
41 <rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
42
43 Revision 1.195 2006/04/25 20:56:28 mkrochma
44 Added comment about previous checkin
45
46 Revision 1.194 2006/04/25 18:29:36 mkrochma
47 Workaround for warning: unused variable 'status' when building mDNSPosix
48
49 Revision 1.193 2006/03/19 17:14:38 cheshire
50 <rdar://problem/4483117> Need faster purging of stale records
51 read_rr_from_ipc_msg was not setting namehash and rdatahash
52
53 Revision 1.192 2006/03/18 20:58:32 cheshire
54 Misplaced curly brace
55
56 Revision 1.191 2006/03/10 22:19:43 cheshire
57 Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
58
59 Revision 1.190 2006/03/10 21:56:12 cheshire
60 <rdar://problem/4111464> After record update, old record sometimes remains in cache
61 When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
62 when the TXT data changes, and then immediately afterwards a second callback with the new port number
63 This change suppresses the first unneccessary (and confusing) callback
64
65 Revision 1.189 2006/01/06 00:56:31 cheshire
66 <rdar://problem/4400573> Should remove PID file on exit
67
68 Revision 1.188 2005/10/11 22:15:03 cheshire
69 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
70 Only compile uds_validatelists() when building for Mac OS X
71
72 Revision 1.187 2005/10/11 20:30:27 cheshire
73 <rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
74
75 Revision 1.186 2005/09/12 07:11:53 herscher
76 <rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
77
78 Revision 1.185 2005/07/29 00:55:10 ksekar
79 Removed validation check in uds_validatelists which generated false alarms
80
81 Revision 1.184 2005/07/04 22:40:26 cheshire
82 Additional debugging code to help catch memory corruption
83
84 Revision 1.183 2005/06/13 22:39:11 cheshire
85 <rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
86
87 Revision 1.182 2005/03/21 00:39:31 shersche
88 <rdar://problem/4021486> Fix build warnings on Win32 platform
89
90 Revision 1.181 2005/03/20 20:21:32 shersche
91 <rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
92 Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
93 object is cleaned up correctly when encountering an interface index error.
94
95 Revision 1.180 2005/03/10 00:13:12 cheshire
96 <rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
97 In handle_browse_request(), mStatus err was being set correctly if an error occurred,
98 but the end of the function returned mStatus_NoError intead of err.
99
100 Revision 1.179 2005/03/04 02:47:26 ksekar
101 <rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
102
103 Revision 1.178 2005/02/25 19:35:38 ksekar
104 <rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
105
106 Revision 1.177 2005/02/25 03:05:41 cheshire
107 Change "broken pipe" message to debugf()
108
109 Revision 1.176 2005/02/24 18:44:45 ksekar
110 <rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
111
112 Revision 1.175 2005/02/21 21:31:25 ksekar
113 <rdar://problem/4015162> changed LogMsg to debugf
114
115 Revision 1.174 2005/02/20 01:41:17 cheshire
116 Fix compiler signed/unsigned warning
117
118 Revision 1.173 2005/02/18 01:26:42 cheshire
119 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
120 Log additional information about failed client
121
122 Revision 1.172 2005/02/18 00:58:35 cheshire
123 <rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
124
125 Revision 1.171 2005/02/18 00:43:12 cheshire
126 <rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
127
128 Revision 1.170 2005/02/16 01:15:02 cheshire
129 Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
130
131 Revision 1.169 2005/02/08 01:57:14 cheshire
132 More detailed error reporting in udsserver_init()
133
134 Revision 1.168 2005/02/03 00:44:37 cheshire
135 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
136
137 Revision 1.167 2005/02/02 02:19:32 cheshire
138 Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
139
140 Revision 1.166 2005/02/01 19:58:52 ksekar
141 Shortened cryptic "broken pipe" syslog message
142
143 Revision 1.165 2005/02/01 19:56:47 ksekar
144 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
145
146 Revision 1.164 2005/01/28 06:07:55 cheshire
147 Don't use deliver_error() from within handle_regrecord_request()
148
149 Revision 1.163 2005/01/28 01:39:16 cheshire
150 Include file descriptor number in "broken pipe" message
151
152 Revision 1.162 2005/01/27 23:59:20 cheshire
153 Remove extraneous LogMsg
154
155 Revision 1.161 2005/01/27 22:57:56 cheshire
156 Fix compile errors on gcc4
157
158 Revision 1.160 2005/01/27 20:52:11 cheshire
159 <rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
160
161 Revision 1.159 2005/01/27 01:45:25 cheshire
162 <rdar://problem/3976147> mDNSResponder should never call exit(1);
163
164 Revision 1.158 2005/01/25 17:28:07 ksekar
165 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
166
167 Revision 1.157 2005/01/21 02:20:39 cheshire
168 Fix mistake in LogOperation() format string
169
170 Revision 1.156 2005/01/19 19:15:36 ksekar
171 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
172
173 Revision 1.155 2005/01/19 03:00:47 cheshire
174 Show Add/Rmv in DNSServiceBrowse LogOperation() message
175
176 Revision 1.154 2005/01/15 00:56:42 ksekar
177 <rdar://problem/3954575> Unicast services don't disappear when logging
178 out of VPN
179
180 Revision 1.153 2005/01/14 18:44:28 ksekar
181 <rdar://problem/3954609> mDNSResponder is crashing when changing domains
182
183 Revision 1.152 2005/01/13 17:16:38 ksekar
184 Back out checkin 1.150 - correct fix is on clientstub side
185
186 Revision 1.151 2005/01/11 21:06:29 ksekar
187 Changed now-benign LogMsg to debugf
188
189 Revision 1.150 2005/01/07 23:59:15 ksekar
190 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
191
192 Revision 1.149 2004/12/20 23:20:35 cheshire
193 <rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
194 Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
195
196 Revision 1.148 2004/12/20 20:37:35 cheshire
197 AllowRemoteQuery not set for the extras in a ServiceRecordSet
198
199 Revision 1.147 2004/12/20 00:15:41 cheshire
200 Include client file descriptor numbers in udsserver_info() output
201
202 Revision 1.146 2004/12/17 05:25:47 cheshire
203 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
204
205 Revision 1.145 2004/12/16 21:39:46 cheshire
206 Include CacheGroup objects in CacheUsed count
207
208 Revision 1.144 2004/12/16 21:27:38 ksekar
209 Fixed build failures when compiled with verbose debugging messages
210
211 Revision 1.143 2004/12/16 20:13:02 cheshire
212 <rdar://problem/3324626> Cache memory management improvements
213
214 Revision 1.142 2004/12/16 08:07:33 shersche
215 Fix compiler error (mixed declarations and code) on Windows
216
217 Revision 1.141 2004/12/16 01:56:21 cheshire
218 Improve DNSServiceEnumerateDomains syslog message
219
220 Revision 1.140 2004/12/14 03:02:10 ksekar
221 <rdar://problem/3919016> Rare race condition can cause crash
222
223 Revision 1.139 2004/12/13 21:18:45 ksekar
224 Include uDNS registrations in CountPeerRegistrations
225
226 Revision 1.138 2004/12/13 18:23:18 ksekar
227 <rdar://problem/3915805> mDNSResponder error when quitting iChat -
228 don't close sockets delivering errors to blocked clients
229
230 Revision 1.137 2004/12/13 00:09:22 ksekar
231 <rdar://problem/3915805> mDNSResponder error when quitting iChat
232
233 Revision 1.136 2004/12/11 01:52:10 cheshire
234 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
235
236 Revision 1.135 2004/12/10 20:46:37 cheshire
237 Change LogOperation message to debugf
238
239 Revision 1.134 2004/12/10 13:19:37 cheshire
240 Add verbosedebugf() logging message in CountPeerRegistrations()
241
242 Revision 1.133 2004/12/10 05:27:26 cheshire
243 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
244
245 Revision 1.132 2004/12/10 04:28:28 cheshire
246 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
247
248 Revision 1.131 2004/12/10 02:09:25 cheshire
249 <rdar://problem/3898376> Modify default TTLs
250
251 Revision 1.130 2004/12/10 00:55:24 cheshire
252 Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
253
254 Revision 1.129 2004/12/09 03:17:23 ksekar
255 <rdar://problem/3910435> DomainEnumeration interface index should be zero
256
257 Revision 1.128 2004/12/07 21:26:05 ksekar
258 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
259
260 Revision 1.127 2004/12/07 20:42:34 cheshire
261 Add explicit context parameter to mDNS_RemoveRecordFromService()
262
263 Revision 1.126 2004/12/07 17:23:55 ksekar
264 Fixed LogOperation
265
266 Revision 1.125 2004/12/06 21:15:23 ksekar
267 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
268
269 Revision 1.124 2004/11/30 02:19:14 cheshire
270 <rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
271
272 Revision 1.123 2004/11/29 23:50:57 cheshire
273 Checkin 1.122 not necessary
274
275 Revision 1.122 2004/11/24 17:55:01 ksekar
276 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
277
278 Revision 1.121 2004/11/24 04:45:52 cheshire
279 Spelling mistake
280
281 Revision 1.120 2004/11/24 00:10:44 cheshire
282 <rdar://problem/3869241> For unicast operations, verify that service types are legal
283
284 Revision 1.119 2004/11/23 23:54:17 ksekar
285 <rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
286 can crash mDNSResponder
287
288 Revision 1.118 2004/11/23 22:33:01 cheshire
289 <rdar://problem/3654910> Remove temporary workaround code for iChat
290
291 Revision 1.117 2004/11/23 20:23:10 ksekar
292 Fixed LogOperation that causes crash on connected service deregistrations
293
294 Revision 1.116 2004/11/23 03:39:47 cheshire
295 Let interface name/index mapping capability live directly in JNISupport.c,
296 instead of having to call through to the daemon via IPC to get this information.
297
298 Revision 1.115 2004/11/13 00:12:53 ksekar
299 Fixed some LogOperation printf converstions for debug builds.
300
301 Revision 1.114 2004/11/12 18:25:45 shersche
302 Tidy up cross platform usleep code fragment.
303
304 Revision 1.113 2004/11/12 03:21:41 rpantos
305 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
306
307 Revision 1.112 2004/11/11 16:58:32 ksekar
308 Removed unused code (previously wrapped in #if 0)
309
310 Revision 1.111 2004/11/05 22:47:37 shersche
311 Conditionally compile usleep(1000) to be Sleep(1) on Windows
312 Submitted by: Pavel Repin <prepin@gmail.com>
313
314 Revision 1.110 2004/11/05 19:56:56 ksekar
315 <rdar://problem/3862646> We no longer need to browse .Mac domains by
316 default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
317
318 Revision 1.109 2004/11/04 03:40:45 cheshire
319 More debugging messages
320
321 Revision 1.108 2004/11/03 02:25:51 cheshire
322 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
323
324 Revision 1.107 2004/11/02 19:39:23 ksekar
325 <rdar://problem/3862646> We no longer need to browse .Mac domains by default
326
327 Revision 1.106 2004/11/02 02:12:21 cheshire
328 <rdar://problem/3839111> Remove unnecessary memory allocations
329
330 Revision 1.105 2004/10/28 19:07:19 cheshire
331 Add some more debugging checks and improved LogOperation() messages
332
333 Revision 1.104 2004/10/26 18:53:15 cheshire
334 Avoid unused variable warning
335
336 Revision 1.103 2004/10/26 07:15:55 cheshire
337 Add file descriptor number to all LogOperation messages
338
339 Revision 1.102 2004/10/26 06:11:42 cheshire
340 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
341
342 Revision 1.101 2004/10/26 04:31:44 cheshire
343 Rename CountSubTypes() as ChopSubTypes()
344
345 Revision 1.100 2004/10/26 01:17:48 cheshire
346 Use "#if 0" instead of commenting out code
347
348 Revision 1.99 2004/10/19 21:33:22 cheshire
349 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
350 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
351 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
352
353 Revision 1.98 2004/10/14 01:59:33 cheshire
354 <rdar://problem/3839208> UDS resolves don't work for uDNS services
355
356 Revision 1.97 2004/10/13 00:58:35 cheshire
357 <rdar://problem/3832738> Registering a proxy doesn't work
358
359 Revision 1.96 2004/09/30 00:25:00 ksekar
360 <rdar://problem/3695802> Dynamically update default registration domains on config change
361
362 Revision 1.95 2004/09/26 23:20:36 ksekar
363 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
364
365 Revision 1.94 2004/09/22 18:27:06 ksekar
366 <rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
367 default record TTL
368
369 Revision 1.93 2004/09/22 02:39:44 cheshire
370 <rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
371
372 Revision 1.92 2004/09/22 02:34:04 cheshire
373 Rename parameter "ttl" to "GetTTL" for clarity
374
375 Revision 1.91 2004/09/22 02:25:43 cheshire
376 Fix spelling errors
377
378 Revision 1.90 2004/09/21 23:40:12 ksekar
379 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
380
381 Revision 1.89 2004/09/21 23:29:51 cheshire
382 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
383
384 Revision 1.88 2004/09/21 23:12:46 cheshire
385 Reorder initialization of question fields to match structure order
386
387 Revision 1.87 2004/09/21 22:18:33 cheshire
388 In SIGINFO output, display a '-' next to records that have the Unique bit set
389
390 Revision 1.86 2004/09/21 21:05:11 cheshire
391 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
392 into mDNSShared/uds_daemon.c
393
394 Revision 1.85 2004/09/18 01:11:58 ksekar
395 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
396
397 Revision 1.84 2004/09/17 01:08:55 cheshire
398 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
399 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
400 declared in that file are ONLY appropriate to single-address-space embedded applications.
401 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
402
403 Revision 1.83 2004/09/16 23:26:33 cheshire
404 Move version check inside preceeding "if" that checks we have a complete header
405
406 Revision 1.82 2004/09/16 23:14:25 cheshire
407 Changes for Windows compatibility
408
409 Revision 1.81 2004/09/16 21:46:38 ksekar
410 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
411
412 Revision 1.80 2004/09/16 01:58:23 cheshire
413 Fix compiler warnings
414
415 Revision 1.79 2004/09/16 00:24:49 cheshire
416 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
417
418 Revision 1.78 2004/09/15 21:44:20 cheshire
419 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
420 Show time value in log to help diagnose errors
421
422 Revision 1.77 2004/09/15 00:19:18 cheshire
423 <rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
424
425 Revision 1.76 2004/09/02 06:39:52 cheshire
426 Minor textual cleanup for clarity
427
428 Revision 1.75 2004/09/02 03:48:47 cheshire
429 <rdar://problem/3709039> Disable targeted unicast query support by default
430 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
431 2. New field AllowRemoteQuery in AuthRecord structure
432 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
433 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
434
435 Revision 1.74 2004/08/25 02:32:47 cheshire
436 Minor cleanup: replace "&regtype[0]" with "regtype"
437
438 Revision 1.73 2004/08/25 02:30:40 cheshire
439 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
440
441 Revision 1.72 2004/08/14 03:22:42 cheshire
442 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
443 Add GetUserSpecifiedDDNSName() routine
444 Convert ServiceRegDomain to domainname instead of C string
445 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
446
447 Revision 1.71 2004/08/11 04:21:21 rpantos
448 Fix Windows build.
449
450 Revision 1.70 2004/08/11 02:07:00 cheshire
451 Remove "mDNS *globalInstance" parameter from udsserver_init()
452 Move CheckForDuplicateRegistrations from daemon.c
453 <rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
454
455 Revision 1.69 2004/08/10 16:14:48 cheshire
456 Fix debug builds (oops)
457
458 Revision 1.68 2004/08/10 06:24:56 cheshire
459 Use types with precisely defined sizes for 'op' and 'reg_index', for better
460 compatibility if the daemon and the client stub are built using different compilers
461
462 Revision 1.67 2004/07/27 07:14:16 shersche
463 make error socket non-blocking after call to connect()
464
465 Revision 1.66 2004/07/13 21:24:25 rpantos
466 Fix for <rdar://problem/3701120>.
467
468 Revision 1.65 2004/06/26 03:17:14 shersche
469 implement cross-platform strerror function
470
471 Submitted by: herscher
472
473 Revision 1.64 2004/06/25 00:26:27 rpantos
474 Changes to fix the Posix build on Solaris.
475
476 Revision 1.63 2004/06/24 03:43:44 rpantos
477 Fix previous checkin so it builds on Windows.
478
479 Revision 1.62 2004/06/24 00:57:08 ksekar
480 Replaced code acccidentally removed in checkin 1.59.
481
482 Revision 1.61 2004/06/19 00:09:39 cheshire
483 Remove unused strsep() implementation
484
485 Revision 1.60 2004/06/18 19:10:00 cheshire
486 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
487
488 Revision 1.59 2004/06/18 05:10:31 rpantos
489 Changes to allow code to be used on Windows
490
491 Revision 1.58 2004/06/15 03:54:08 cheshire
492 Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
493
494 Revision 1.57 2004/06/12 01:47:27 ksekar
495 <rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
496 udsserver_idle compared time in ticks to interval in seconds.
497
498 Revision 1.56 2004/06/12 01:35:47 cheshire
499 Changes for Windows compatibility
500
501 Revision 1.55 2004/06/05 00:04:27 cheshire
502 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
503
504 Revision 1.54 2004/06/01 22:22:52 ksekar
505 <rdar://problem/3668635>: wide-area default registrations should be in
506 .local too
507
508 Revision 1.53 2004/05/28 23:42:37 ksekar
509 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
510
511 Revision 1.52 2004/05/26 00:39:49 ksekar
512 <rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
513 Finder
514 Use local-only InterfaceID for GetDomains calls for sockets-API
515
516 Revision 1.51 2004/05/18 23:51:27 cheshire
517 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
518
519 Revision 1.50 2004/05/14 16:39:47 ksekar
520 Browse for iChat locally for now.
521
522 Revision 1.49 2004/05/13 21:33:52 ksekar
523 Clean up non-local registration control via config file. Force iChat
524 registrations to be local for now.
525
526 Revision 1.48 2004/05/13 04:13:19 ksekar
527 Updated SIGINFO handler for multi-domain browses
528
529 Revision 1.47 2004/05/12 22:04:01 ksekar
530 Implemented multi-domain browsing by default for uds_daemon.
531
532 Revision 1.46 2004/05/06 18:42:58 ksekar
533 General dns_sd.h API cleanup, including the following radars:
534 <rdar://problem/3592068>: Remove flags with zero value
535 <rdar://problem/3479569>: Passing in NULL causes a crash.
536
537 Revision 1.45 2004/03/12 08:49:28 cheshire
538 #include <sys/socket.h>
539
540 Revision 1.44 2004/02/25 01:25:27 ksekar
541 <rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
542
543 Revision 1.43 2004/02/24 01:46:40 cheshire
544 Manually reinstate lost checkin 1.36
545
546 Revision 1.42 2004/02/05 19:39:29 cheshire
547 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
548 so that all platforms get this functionality
549
550 Revision 1.41 2004/02/03 18:59:02 cheshire
551 Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
552
553 Revision 1.40 2004/01/28 03:41:00 cheshire
554 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
555
556 Revision 1.39 2004/01/25 00:03:21 cheshire
557 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
558
559 Revision 1.38 2004/01/19 19:51:46 cheshire
560 Fix compiler error (mixed declarations and code) on some versions of Linux
561
562 Revision 1.37 2003/12/08 21:11:42 rpantos
563 Changes necessary to support mDNSResponder on Linux.
564
565 Revision 1.36 2003/12/04 23:40:57 cheshire
566 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
567 Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
568
569 Revision 1.35 2003/12/03 19:10:22 ksekar
570 <rdar://problem/3498644>: malloc'd data not zero'd
571
572 Revision 1.34 2003/12/03 02:00:01 ksekar
573 <rdar://problem/3498644>: malloc'd data not zero'd
574
575 Revision 1.33 2003/11/22 01:18:46 ksekar
576 <rdar://problem/3486646>: config change handler not called for dns-sd services
577
578 Revision 1.32 2003/11/20 21:46:12 ksekar
579 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
580
581 Revision 1.31 2003/11/20 20:33:05 ksekar
582 <rdar://problem/3486635>: leak: DNSServiceRegisterRecord
583
584 Revision 1.30 2003/11/20 02:10:55 ksekar
585 <rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
586
587 Revision 1.29 2003/11/14 21:18:32 cheshire
588 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
589 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
590
591 Revision 1.28 2003/11/08 22:18:29 cheshire
592 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
593
594 Revision 1.27 2003/11/05 22:44:57 ksekar
595 <rdar://problem/3335230>: No bounds checking when reading data from client
596 Reviewed by: Stuart Cheshire
597
598 Revision 1.26 2003/10/23 17:51:04 ksekar
599 <rdar://problem/3335216>: handle blocked clients more efficiently
600 Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
601
602 Revision 1.25 2003/10/22 23:37:49 ksekar
603 <rdar://problem/3459141>: crash/hang in abort_client
604
605 Revision 1.24 2003/10/21 20:59:40 ksekar
606 <rdar://problem/3335216>: handle blocked clients more efficiently
607
608 Revision 1.23 2003/09/23 02:12:43 cheshire
609 Also include port number in list of services registered via new UDS API
610
611 Revision 1.22 2003/08/19 16:03:55 ksekar
612 <rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
613 Check termination_context for NULL before dereferencing.
614
615 Revision 1.21 2003/08/19 05:39:43 cheshire
616 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
617
618 Revision 1.20 2003/08/16 03:39:01 cheshire
619 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
620
621 Revision 1.19 2003/08/15 20:16:03 cheshire
622 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
623 We want to avoid touching the rdata pages, so we don't page them in.
624 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
625 Moved this from the RData to the ResourceRecord object.
626 2. To avoid unnecessarily touching the rdata just to compare it,
627 compute a hash of the rdata and store the hash in the ResourceRecord object.
628
629 Revision 1.18 2003/08/15 00:38:00 ksekar
630 <rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
631
632 Revision 1.17 2003/08/14 02:18:21 cheshire
633 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
634
635 Revision 1.16 2003/08/13 23:58:52 ksekar
636 <rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
637 Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
638
639 Revision 1.15 2003/08/13 17:30:33 ksekar
640 <rdar://problem/3374671>: DNSServiceAddRecord doesn't work
641 Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
642
643 Revision 1.14 2003/08/12 19:56:25 cheshire
644 Update to APSL 2.0
645
646 */
647
648 #if defined(_WIN32)
649 #include <process.h>
650 #define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
651 #define dnssd_strerror(X) win32_strerror(X)
652 #define usleep(X) Sleep(((X)+999)/1000)
653 static char * win32_strerror(int inErrorCode);
654 #else
655 #include <fcntl.h>
656 #include <errno.h>
657 #include <sys/ioctl.h>
658 #include <sys/types.h>
659 #include <sys/time.h>
660 #include <sys/resource.h>
661 #define dnssd_strerror(X) strerror(X)
662 #endif
663
664 #include <stdlib.h>
665 #include <stdio.h>
666 #include "mDNSEmbeddedAPI.h"
667 #include "DNSCommon.h"
668 #include "uds_daemon.h"
669 #include "dns_sd.h"
670 #include "dnssd_ipc.h"
671
672 // Apple specific configuration functionality, not required for other platforms
673 #ifdef __MACOSX__
674 #include <sys/ucred.h>
675 #ifndef LOCAL_PEERCRED
676 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
677 #endif // LOCAL_PEERCRED
678 #endif //__MACOSX__
679
680 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
681 extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
682 #endif
683
684 // Types and Data Structures
685 // ----------------------------------------------------------------------
686
687 typedef enum
688 {
689 t_uninitialized,
690 t_morecoming,
691 t_complete,
692 t_error,
693 t_terminated
694 } transfer_state;
695
696 typedef void (*req_termination_fn)(void *);
697
698 typedef struct registered_record_entry
699 {
700 uint32_t key;
701 AuthRecord *rr;
702 struct registered_record_entry *next;
703 client_context_t client_context;
704 struct request_state *rstate;
705 } registered_record_entry;
706
707 // A single registered service: ServiceRecordSet + bookkeeping
708 // Note that we duplicate some fields from parent service_info object
709 // to facilitate cleanup, when instances and parent may be deallocated at different times.
710 typedef struct service_instance
711 {
712 struct service_instance *next;
713 mDNSBool autoname; // Set if this name is tied to the Computer Name
714 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
715 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
716 mDNSBool rename_on_memfree; // Set on config change when we deregister original name
717 domainlabel name;
718 domainname domain;
719 mDNSBool default_local; // is this the "local." from an empty-string registration?
720 struct request_state *request;
721 dnssd_sock_t sd;
722 AuthRecord *subtypes;
723 ServiceRecordSet srs; // note - must be last field in struct
724 } service_instance;
725
726 // A client-created service. May reference several service_info objects if default
727 // settings cause registration in multiple domains.
728 typedef struct
729 {
730 uint16_t txtlen;
731 void *txtdata;
732 mDNSIPPort port;
733 domainlabel name;
734 char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
735 domainname type;
736 mDNSBool default_domain;
737 domainname host;
738 mDNSBool autoname; // Set if this name is tied to the Computer Name
739 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
740 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
741 int num_subtypes;
742 mDNSInterfaceID InterfaceID;
743 service_instance *instances;
744 struct request_state *request;
745 } service_info;
746
747 // for multi-domain default browsing
748 typedef struct browser_t
749 {
750 DNSQuestion q;
751 domainname domain;
752 struct browser_t *next;
753 } browser_t;
754
755 // parent struct for browser instances: list pointer plus metadata
756 typedef struct
757 {
758 mDNSBool default_domain;
759 mDNSBool ForceMCast;
760 domainname regtype;
761 mDNSInterfaceID interface_id;
762 struct request_state *rstate;
763 browser_t *browsers;
764 } browser_info_t;
765
766 typedef struct
767 {
768 mStatus err; // Note: This field is in NETWORK byte order
769 int nwritten;
770 dnssd_sock_t sd;
771 } undelivered_error_t;
772
773 typedef struct request_state
774 {
775 // connection structures
776 dnssd_sock_t sd;
777
778 // state of read (in case message is read over several recv() calls)
779 transfer_state ts;
780 uint32_t hdr_bytes; // bytes of header already read
781 ipc_msg_hdr hdr;
782 uint32_t data_bytes; // bytes of message data already read
783 char *msgbuf; // pointer to data storage to pass to free()
784 char *msgdata; // pointer to data to be read from (may be modified)
785 int bufsize; // size of data storage
786
787 // reply, termination, error, and client context info
788 int no_reply; // don't send asynchronous replies to client
789 int time_blocked; // record time of a blocked client
790 void *client_context; // don't touch this - pointer only valid in client's addr space
791 struct reply_state *replies; // corresponding (active) reply list
792 undelivered_error_t *u_err;
793 void *termination_context;
794 req_termination_fn terminate;
795
796 //!!!KRS toss these pointers in a union
797 // registration context associated with this request (null if not applicable)
798 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
799 service_info *service_registration;
800 browser_info_t *browser_info;
801 struct request_state *next;
802 } request_state;
803
804 // struct physically sits between ipc message header and call-specific fields in the message buffer
805 typedef struct
806 {
807 DNSServiceFlags flags; // Note: This field is in NETWORK byte order
808 uint32_t ifi; // Note: This field is in NETWORK byte order
809 DNSServiceErrorType error; // Note: This field is in NETWORK byte order
810 } reply_hdr;
811
812 typedef struct reply_state
813 {
814 // state of the transmission
815 dnssd_sock_t sd;
816 transfer_state ts;
817 uint32_t nwriten;
818 uint32_t len;
819 // context of the reply
820 struct request_state *request; // the request that this answers
821 struct reply_state *next; // if there are multiple unsent replies
822 // pointer into message buffer - allows fields to be changed after message is formatted
823 ipc_msg_hdr *mhdr;
824 reply_hdr *rhdr;
825 char *sdata; // pointer to start of call-specific data
826 // pointer to malloc'd buffer
827 char *msgbuf;
828 } reply_state;
829
830 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
831 // structures to handle callbacks
832 typedef struct
833 {
834 DNSQuestion question;
835 mDNS_DomainType type;
836 request_state *rstate;
837 } domain_enum_t;
838
839 typedef struct
840 {
841 domain_enum_t *all;
842 domain_enum_t *def;
843 request_state *rstate;
844 } enum_termination_t;
845
846 typedef struct
847 {
848 request_state *rstate;
849 DNSQuestion qtxt;
850 DNSQuestion qsrv;
851 // const ResourceRecord *txt;
852 // const ResourceRecord *srv;
853 mDNSBool srv;
854 mDNSBool txt;
855 rdataSRV srvdata;
856 mDNSu16 txtlen;
857 mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
858 } resolve_termination_t;
859
860 #ifdef _HAVE_SETDOMAIN_SUPPORT_
861 typedef struct default_browse_list_t
862 {
863 struct default_browse_list_t *next;
864 uid_t uid;
865 AuthRecord ptr_rec;
866 } default_browse_list_t;
867
868 static default_browse_list_t *default_browse_list = NULL;
869 #endif // _HAVE_SETDOMAIN_SUPPORT_
870
871 // globals
872 mDNSexport mDNS mDNSStorage;
873 #define gmDNS (&mDNSStorage)
874
875 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
876 static request_state * all_requests = NULL;
877
878 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
879 // terminating connection
880 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
881 // n get_string() calls w/o buffer overrun
882 // private function prototypes
883 mDNSlocal void connect_callback(void *info);
884 mDNSlocal int read_msg(request_state *rs);
885 mDNSlocal int send_msg(reply_state *rs);
886 mDNSlocal void abort_request(request_state *rs);
887 mDNSlocal void request_callback(void *info);
888 mDNSlocal void handle_resolve_request(request_state *rstate);
889 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
890 mDNSlocal void question_termination_callback(void *context);
891 mDNSlocal void handle_browse_request(request_state *request);
892 mDNSlocal void browse_termination_callback(void *context);
893 mDNSlocal void handle_regservice_request(request_state *request);
894 mDNSlocal void regservice_termination_callback(void *context);
895 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
896 mDNSlocal mStatus handle_add_request(request_state *rstate);
897 mDNSlocal mStatus handle_update_request(request_state *rstate);
898 mDNSlocal void append_reply(request_state *req, reply_state *rep);
899 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
900 mDNSlocal void enum_termination_callback(void *context);
901 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
902 mDNSlocal void handle_query_request(request_state *rstate);
903 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
904 mDNSlocal void handle_enum_request(request_state *rstate);
905 mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
906 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
907 mDNSlocal void connected_registration_termination(void *context);
908 mDNSlocal void handle_reconfirm_request(request_state *rstate);
909 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
910 mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
911 mDNSlocal void reset_connected_rstate(request_state *rstate);
912 mDNSlocal int deliver_error(request_state *rstate, mStatus err);
913 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
914 mDNSlocal transfer_state send_undelivered_error(request_state *rs);
915 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
916 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
917 mDNSlocal void my_perror(char *errmsg);
918 mDNSlocal void unlink_request(request_state *rs);
919 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
920 mDNSlocal void resolve_termination_callback(void *context);
921 mDNSlocal int validate_message(request_state *rstate);
922 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
923 mDNSlocal mStatus remove_record(request_state *rstate);
924 mDNSlocal void free_service_instance(service_instance *srv);
925 mDNSlocal uint32_t dnssd_htonl(uint32_t l);
926 mDNSlocal void handle_setdomain_request(request_state *rstate);
927
928 // initialization, setup/teardown functions
929
930 // If a platform specifies its own PID file name, we use that
931 #ifndef PID_FILE
932 #define PID_FILE "/var/run/mDNSResponder.pid"
933 #endif
934
935 mDNSlocal void LogClientInfo(request_state *req)
936 {
937 void *t = req->termination_context;
938 if (t)
939 {
940 if (req->terminate == regservice_termination_callback)
941 {
942 service_instance *ptr;
943 for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
944 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
945 }
946 else if (req->terminate == browse_termination_callback)
947 {
948 browser_t *blist;
949 for (blist = req->browser_info->browsers; blist; blist = blist->next)
950 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
951 }
952 else if (req->terminate == resolve_termination_callback)
953 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
954 else if (req->terminate == question_termination_callback)
955 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req->sd, ((DNSQuestion *) t)->qname.c);
956 else if (req->terminate == enum_termination_callback)
957 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
958 }
959 }
960
961 mDNSlocal void FatalError(char *errmsg)
962 {
963 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
964 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
965 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
966 }
967
968 int udsserver_init(void)
969 {
970 dnssd_sockaddr_t laddr;
971 int ret;
972 #if defined(_WIN32)
973 u_long opt = 1;
974 #endif
975
976 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
977 if (PID_FILE[0])
978 {
979 FILE *fp = fopen(PID_FILE, "w");
980 if (fp != NULL)
981 {
982 fprintf(fp, "%d\n", getpid());
983 fclose(fp);
984 }
985 }
986
987 if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
988 {
989 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
990 goto error;
991 }
992
993 bzero(&laddr, sizeof(laddr));
994
995 #if defined(USE_TCP_LOOPBACK)
996 {
997 laddr.sin_family = AF_INET;
998 laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
999 laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1000 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1001 if (ret < 0)
1002 {
1003 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1004 goto error;
1005 }
1006 }
1007 #else
1008 {
1009 mode_t mask = umask(0);
1010 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
1011 laddr.sun_family = AF_LOCAL;
1012 #ifndef NOT_HAVE_SA_LEN
1013 // According to Stevens (section 3.2), there is no portable way to
1014 // determine whether sa_len is defined on a particular platform.
1015 laddr.sun_len = sizeof(struct sockaddr_un);
1016 #endif
1017 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
1018 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1019 umask(mask);
1020 if (ret < 0)
1021 {
1022 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1023 goto error;
1024 }
1025 }
1026 #endif
1027
1028 #if defined(_WIN32)
1029 //
1030 // SEH: do we even need to do this on windows? this socket
1031 // will be given to WSAEventSelect which will automatically
1032 // set it to non-blocking
1033 //
1034 if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
1035 #else
1036 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
1037 #endif
1038 {
1039 my_perror("ERROR: could not set listen socket to non-blocking mode");
1040 goto error;
1041 }
1042
1043 if (listen(listenfd, LISTENQ) != 0)
1044 {
1045 my_perror("ERROR: could not listen on listen socket");
1046 goto error;
1047 }
1048
1049 if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
1050 {
1051 my_perror("ERROR: could not add listen socket to event loop");
1052 goto error;
1053 }
1054
1055 #if !defined(PLATFORM_NO_RLIMIT)
1056 {
1057 // Set maximum number of open file descriptors
1058 #define MIN_OPENFILES 10240
1059 struct rlimit maxfds, newfds;
1060
1061 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
1062 // you have to get and set rlimits once before getrlimit will return sensible values
1063 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1064 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1065
1066 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1067 newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
1068 newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
1069 if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
1070 if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1071
1072 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1073 debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
1074 debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
1075 }
1076 #endif
1077
1078 return 0;
1079
1080 error:
1081
1082 my_perror("ERROR: udsserver_init");
1083 return -1;
1084 }
1085
1086 int udsserver_exit(void)
1087 {
1088 dnssd_close(listenfd);
1089
1090 #if !defined(USE_TCP_LOOPBACK)
1091 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1092 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1093 // It would be nice if we could find a solution to this problem
1094 if (unlink(MDNS_UDS_SERVERPATH))
1095 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
1096 #endif
1097
1098 if (PID_FILE[0]) unlink(PID_FILE);
1099
1100 return 0;
1101 }
1102
1103 mDNSs32 udsserver_idle(mDNSs32 nextevent)
1104 {
1105 request_state *req = all_requests, *tmp, *prev = NULL;
1106 reply_state *fptr;
1107 transfer_state result;
1108 mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
1109
1110 while(req)
1111 {
1112 result = t_uninitialized;
1113 if (req->u_err)
1114 result = send_undelivered_error(req);
1115 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
1116 (req->ts == t_complete || req->ts == t_morecoming))
1117 {
1118 while(req->replies)
1119 {
1120 if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
1121 result = send_msg(req->replies);
1122 if (result == t_complete)
1123 {
1124 fptr = req->replies;
1125 req->replies = req->replies->next;
1126 freeL("udsserver_idle", fptr);
1127 req->time_blocked = 0; // reset failure counter after successful send
1128 }
1129 else if (result == t_terminated || result == t_error)
1130 {
1131 abort_request(req);
1132 break;
1133 }
1134 else if (result == t_morecoming) break; // client's queues are full, move to next
1135 }
1136 }
1137 if (result == t_morecoming)
1138 {
1139 if (!req->time_blocked) req->time_blocked = now;
1140 debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
1141 if (now - req->time_blocked >= MAX_TIME_BLOCKED)
1142 {
1143 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
1144 LogClientInfo(req);
1145 abort_request(req);
1146 result = t_terminated;
1147 }
1148 else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
1149 }
1150 if (result == t_terminated || result == t_error)
1151 //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
1152 {
1153 tmp = req;
1154 if (prev) prev->next = req->next;
1155 if (req == all_requests) all_requests = all_requests->next;
1156 req = req->next;
1157 freeL("udsserver_idle", tmp);
1158 }
1159 else
1160 {
1161 prev = req;
1162 req = req->next;
1163 }
1164 }
1165 return nextevent;
1166 }
1167
1168 mDNSexport void udsserver_info(mDNS *const m)
1169 {
1170 mDNSs32 now = mDNS_TimeNow(m);
1171 mDNSu32 CacheUsed = 0, CacheActive = 0;
1172 mDNSu32 slot;
1173 CacheGroup *cg;
1174 CacheRecord *rr;
1175 request_state *req;
1176
1177 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1178
1179 LogMsgNoIdent("Slt Q TTL U Type if len rdata");
1180 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
1181 for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1182 {
1183 CacheUsed++; // Count one cache entity for the CacheGroup object
1184 for (rr = cg->members; rr; rr=rr->next)
1185 {
1186 mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
1187 CacheUsed++;
1188 if (rr->CRActiveQuestion) CacheActive++;
1189 LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
1190 slot,
1191 rr->CRActiveQuestion ? "*" : " ",
1192 remain,
1193 (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
1194 DNSTypeName(rr->resrec.rrtype),
1195 ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
1196 CRDisplayString(m, rr));
1197 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1198 }
1199 }
1200
1201 if (m->rrcache_totalused != CacheUsed)
1202 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
1203 if (m->rrcache_active != CacheActive)
1204 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
1205 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
1206
1207 for (req = all_requests; req; req=req->next)
1208 LogClientInfo(req);
1209
1210 now = mDNS_TimeNow(m);
1211 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1212 }
1213
1214 #if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
1215 mDNSexport void uds_validatelists(void)
1216 {
1217 request_state *req;
1218 for (req = all_requests; req; req=req->next)
1219 if (req->sd < 0 && req->sd != -2)
1220 LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
1221 }
1222 #endif
1223
1224 mDNSlocal void rename_service(service_instance *srv)
1225 {
1226 if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
1227 {
1228 srv->rename_on_memfree = 1;
1229 if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
1230 regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
1231 }
1232 }
1233
1234 mDNSexport void udsserver_handle_configchange(void)
1235 {
1236 request_state *req;
1237
1238 for (req = all_requests; req; req = req->next)
1239 {
1240 if (req->service_registration)
1241 {
1242 service_instance *ptr;
1243 for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
1244 rename_service(ptr);
1245 }
1246 }
1247 }
1248
1249 mDNSlocal void connect_callback(void *info)
1250 {
1251 dnssd_sock_t sd;
1252 dnssd_socklen_t len;
1253 unsigned long optval;
1254 dnssd_sockaddr_t cliaddr;
1255 request_state *rstate;
1256 (void)info; // Unused
1257
1258 len = (dnssd_socklen_t) sizeof(cliaddr);
1259
1260 sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
1261
1262 if (sd == dnssd_InvalidSocket)
1263 {
1264 if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
1265 my_perror("ERROR: accept");
1266 return;
1267 }
1268 optval = 1;
1269
1270 #ifdef SO_NOSIGPIPE
1271 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1272 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
1273 {
1274 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1275 dnssd_close(sd);
1276 return;
1277 }
1278 #endif
1279
1280 #if defined(_WIN32)
1281 if (ioctlsocket(sd, FIONBIO, &optval) != 0)
1282 #else
1283 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
1284 #endif
1285 {
1286 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1287 dnssd_close(sd);
1288 return;
1289 }
1290
1291 // allocate a request_state struct that will live with the socket
1292 rstate = mallocL("connect_callback", sizeof(request_state));
1293 if (!rstate) FatalError("ERROR: malloc");
1294 bzero(rstate, sizeof(request_state));
1295 rstate->ts = t_morecoming;
1296 rstate->sd = sd;
1297
1298 LogOperation("%3d: Adding FD", rstate->sd);
1299 if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
1300 return;
1301 rstate->next = all_requests;
1302 all_requests = rstate;
1303 }
1304
1305 // handler
1306 mDNSlocal void request_callback(void *info)
1307 {
1308 request_state *rstate = info;
1309 transfer_state result;
1310 dnssd_sockaddr_t cliaddr;
1311 int dedicated_error_socket;
1312 #if defined(_WIN32)
1313 u_long opt = 1;
1314 #endif
1315
1316 result = read_msg(rstate);
1317 if (result == t_morecoming)
1318 {
1319 return;
1320 }
1321 if (result == t_terminated)
1322 {
1323 abort_request(rstate);
1324 unlink_request(rstate);
1325 return;
1326 }
1327 if (result == t_error)
1328 {
1329 abort_request(rstate);
1330 unlink_request(rstate);
1331 return;
1332 }
1333
1334 if (rstate->hdr.version != VERSION)
1335 {
1336 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1337 "daemon version = %d)\n", rstate->hdr.version, VERSION);
1338 abort_request(rstate);
1339 unlink_request(rstate);
1340 return;
1341 }
1342
1343 if (validate_message(rstate) < 0)
1344 {
1345 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1346 // may be contained in the (invalid) message body for some message types
1347 abort_request(rstate);
1348 unlink_request(rstate);
1349 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1350 return;
1351 }
1352
1353 // check if client wants silent operation
1354 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
1355
1356 dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
1357 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
1358
1359 if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
1360 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
1361
1362 // check if primary socket is to be used for synchronous errors, else open new socket
1363 if (dedicated_error_socket)
1364 {
1365 mStatus err = 0;
1366 int nwritten;
1367 dnssd_sock_t errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
1368 if (errfd == dnssd_InvalidSocket)
1369 {
1370 my_perror("ERROR: socket");
1371 abort_request(rstate);
1372 unlink_request(rstate);
1373 return;
1374 }
1375
1376 //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
1377
1378 #if defined(USE_TCP_LOOPBACK)
1379 {
1380 mDNSOpaque16 port;
1381 port.b[0] = rstate->msgdata[0];
1382 port.b[1] = rstate->msgdata[1];
1383 rstate->msgdata += 2;
1384 cliaddr.sin_family = AF_INET;
1385 cliaddr.sin_port = port.NotAnInteger;
1386 cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1387 }
1388 #else
1389 {
1390 char ctrl_path[MAX_CTLPATH];
1391 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
1392 bzero(&cliaddr, sizeof(cliaddr));
1393 cliaddr.sun_family = AF_LOCAL;
1394 strcpy(cliaddr.sun_path, ctrl_path);
1395 }
1396 #endif
1397 //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
1398 if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
1399 {
1400 //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
1401 my_perror("ERROR: connect");
1402 abort_request(rstate);
1403 unlink_request(rstate);
1404 return;
1405 }
1406 #if defined(_WIN32)
1407 if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
1408 #else
1409 if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
1410 #endif
1411 {
1412 my_perror("ERROR: could not set control socket to non-blocking mode");
1413 abort_request(rstate);
1414 unlink_request(rstate);
1415 return;
1416 }
1417
1418 switch(rstate->hdr.op)
1419 {
1420 case reg_record_request: err = handle_regrecord_request (rstate); break;
1421 case add_record_request: err = handle_add_request (rstate); break;
1422 case update_record_request: err = handle_update_request (rstate); break;
1423 case remove_record_request: err = handle_removerecord_request(rstate); break;
1424 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1425 }
1426
1427 //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
1428 err = dnssd_htonl(err);
1429 nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
1430 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1431 // If not, we don't attempt to handle this failure, but we do log it.
1432 if (nwritten < (int)sizeof(err))
1433 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1434 nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1435 //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
1436 dnssd_close(errfd);
1437 //LogOperation("request_callback: Closed errfd %d", errfd);
1438 reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
1439 }
1440 else
1441 {
1442 switch(rstate->hdr.op)
1443 {
1444 case resolve_request: handle_resolve_request (rstate); break;
1445 case query_request: handle_query_request (rstate); break;
1446 case browse_request: handle_browse_request (rstate); break;
1447 case reg_service_request: handle_regservice_request(rstate); break;
1448 case enumeration_request: handle_enum_request (rstate); break;
1449 case reconfirm_record_request: handle_reconfirm_request (rstate); break;
1450 case setdomain_request: handle_setdomain_request (rstate); break;
1451 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1452 }
1453 }
1454 }
1455
1456 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1457 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1458 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1459 // the mDNSCore operation if the client dies or closes its socket.
1460
1461 // query and resolve calls have separate request handlers that parse the arguments from the client and
1462 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1463 // delivering the result to the client, and termination) are identical.
1464
1465 mDNSlocal void handle_query_request(request_state *rstate)
1466 {
1467 DNSServiceFlags flags;
1468 uint32_t ifi;
1469 char name[256];
1470 uint16_t rrtype, rrclass;
1471 char *ptr;
1472 mStatus result;
1473 mDNSInterfaceID InterfaceID;
1474 DNSQuestion *q;
1475
1476 if (rstate->ts != t_complete)
1477 {
1478 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1479 goto error;
1480 }
1481 ptr = rstate->msgdata;
1482 if (!ptr)
1483 {
1484 LogMsg("ERROR: handle_query_request - NULL msgdata");
1485 goto error;
1486 }
1487
1488 flags = get_flags(&ptr);
1489 ifi = get_long(&ptr);
1490 if (get_string(&ptr, name, 256) < 0) goto bad_param;
1491 rrtype = get_short(&ptr);
1492 rrclass = get_short(&ptr);
1493 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1494 if (ifi && !InterfaceID) goto bad_param;
1495
1496 q = mallocL("DNSQuestion", sizeof(DNSQuestion));
1497 if (!q) FatalError("ERROR: handle_query - malloc");
1498 bzero(q, sizeof(DNSQuestion));
1499
1500 q->InterfaceID = InterfaceID;
1501 q->Target = zeroAddr;
1502 if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
1503 q->qtype = rrtype;
1504 q->qclass = rrclass;
1505 q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
1506 q->ExpectUnique = mDNSfalse;
1507 q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1508 q->QuestionCallback = question_result_callback;
1509 q->QuestionContext = rstate;
1510
1511 rstate->termination_context = q;
1512 rstate->terminate = question_termination_callback;
1513
1514 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
1515 result = mDNS_StartQuery(gmDNS, q);
1516 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
1517
1518 if (result) rstate->terminate = NULL;
1519 if (deliver_error(rstate, result) < 0) goto error;
1520 return;
1521
1522 bad_param:
1523 deliver_error(rstate, mStatus_BadParamErr);
1524 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
1525 error:
1526 abort_request(rstate);
1527 unlink_request(rstate);
1528 return;
1529 }
1530
1531 mDNSlocal void handle_resolve_request(request_state *rstate)
1532 {
1533 DNSServiceFlags flags;
1534 uint32_t interfaceIndex;
1535 mDNSInterfaceID InterfaceID;
1536 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1537 char *ptr; // message data pointer
1538 domainname fqdn;
1539 resolve_termination_t *term;
1540 mStatus err;
1541
1542 if (rstate->ts != t_complete)
1543 {
1544 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1545 abort_request(rstate);
1546 unlink_request(rstate);
1547 return;
1548 }
1549
1550 // extract the data from the message
1551 ptr = rstate->msgdata;
1552 if (!ptr)
1553 {
1554 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1555 abort_request(rstate);
1556 unlink_request(rstate);
1557 return;
1558 }
1559 flags = get_flags(&ptr);
1560 interfaceIndex = get_long(&ptr);
1561 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1562 if (interfaceIndex && !InterfaceID)
1563 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
1564 if (get_string(&ptr, name, 256) < 0 ||
1565 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1566 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1567 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
1568
1569 // free memory in rstate since we don't need it anymore
1570 freeL("handle_resolve_request", rstate->msgbuf);
1571 rstate->msgbuf = NULL;
1572
1573 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1574 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
1575
1576 // set up termination info
1577 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
1578 bzero(term, sizeof(*term));
1579 if (!term) FatalError("ERROR: malloc");
1580
1581 // format questions
1582 term->qsrv.InterfaceID = InterfaceID;
1583 term->qsrv.Target = zeroAddr;
1584 memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
1585 term->qsrv.qtype = kDNSType_SRV;
1586 term->qsrv.qclass = kDNSClass_IN;
1587 term->qsrv.LongLived = mDNSfalse;
1588 term->qsrv.ExpectUnique = mDNStrue;
1589 term->qsrv.ForceMCast = mDNSfalse;
1590 term->qsrv.QuestionCallback = resolve_result_callback;
1591 term->qsrv.QuestionContext = rstate;
1592
1593 term->qtxt.InterfaceID = InterfaceID;
1594 term->qtxt.Target = zeroAddr;
1595 memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
1596 term->qtxt.qtype = kDNSType_TXT;
1597 term->qtxt.qclass = kDNSClass_IN;
1598 term->qtxt.LongLived = mDNSfalse;
1599 term->qtxt.ExpectUnique = mDNStrue;
1600 term->qtxt.ForceMCast = mDNSfalse;
1601 term->qtxt.QuestionCallback = resolve_result_callback;
1602 term->qtxt.QuestionContext = rstate;
1603
1604 term->rstate = rstate;
1605 rstate->termination_context = term;
1606 rstate->terminate = resolve_termination_callback;
1607
1608 // ask the questions
1609 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
1610 err = mDNS_StartQuery(gmDNS, &term->qsrv);
1611 if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
1612
1613 if (err)
1614 {
1615 freeL("handle_resolve_request", term);
1616 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
1617 }
1618 if (deliver_error(rstate, err) < 0 || err)
1619 {
1620 abort_request(rstate);
1621 unlink_request(rstate);
1622 }
1623 return;
1624
1625 bad_param:
1626 deliver_error(rstate, mStatus_BadParamErr);
1627 abort_request(rstate);
1628 unlink_request(rstate);
1629 }
1630
1631 mDNSlocal void resolve_termination_callback(void *context)
1632 {
1633 resolve_termination_t *term = context;
1634 request_state *rs;
1635
1636 if (!term)
1637 {
1638 LogMsg("ERROR: resolve_termination_callback: double termination");
1639 return;
1640 }
1641 rs = term->rstate;
1642 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
1643
1644 mDNS_StopQuery(gmDNS, &term->qtxt);
1645 mDNS_StopQuery(gmDNS, &term->qsrv);
1646
1647 freeL("resolve_termination_callback", term);
1648 rs->termination_context = NULL;
1649 }
1650
1651 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1652 {
1653 size_t len = 0;
1654 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1655 char *data;
1656 transfer_state result;
1657 reply_state *rep;
1658 request_state *rs = question->QuestionContext;
1659 resolve_termination_t *res = rs->termination_context;
1660 (void)m; // Unused
1661
1662 LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
1663 rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
1664
1665 // This code used to do this trick of just keeping a copy of the pointer to
1666 // the answer record in the cache, but the unicast query code doesn't currently
1667 // put its answer records in the cache, so for now we can't do this.
1668
1669 if (!AddRecord)
1670 {
1671 // After unicast query code is updated to store its records in the common cache, use this...
1672 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1673 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1674 // intead of this...
1675 if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
1676 res->srv = mDNSfalse;
1677 if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
1678 res->txt = mDNSfalse;
1679 return;
1680 }
1681
1682 // After unicast query code is updated to store its records in the common cache, use this...
1683 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1684 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1685 // intead of this...
1686 if (answer->rrtype == kDNSType_SRV)
1687 {
1688 // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object
1689 // (to economize on space) and reading past the end may run into unmapped memory, causing a crash.
1690 //res->srvdata = answer->rdata->u.srv;
1691 // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not
1692 // try to copy the full 255 bytes which may not all be there.
1693 AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target);
1694 res->srvdata.port = answer->rdata->u.srv.port;
1695 res->srv = mDNStrue;
1696 }
1697 if (answer->rrtype == kDNSType_TXT)
1698 {
1699 if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
1700 res->txtlen = answer->rdlength;
1701 mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
1702 res->txt = mDNStrue;
1703 }
1704
1705 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1706
1707 ConvertDomainNameToCString(answer->name, fullname);
1708 ConvertDomainNameToCString(&res->srvdata.target, target);
1709
1710 // calculate reply length
1711 len += sizeof(DNSServiceFlags);
1712 len += sizeof(uint32_t); // interface index
1713 len += sizeof(DNSServiceErrorType);
1714 len += strlen(fullname) + 1;
1715 len += strlen(target) + 1;
1716 len += 2 * sizeof(uint16_t); // port, txtLen
1717 len += res->txtlen;
1718
1719 // allocate/init reply header
1720 rep = create_reply(resolve_reply, len, rs);
1721 rep->rhdr->flags = dnssd_htonl(0);
1722 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1723 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1724
1725 data = rep->sdata;
1726
1727 // write reply data to message
1728 put_string(fullname, &data);
1729 put_string(target, &data);
1730 *data++ = res->srvdata.port.b[0];
1731 *data++ = res->srvdata.port.b[1];
1732 put_short(res->txtlen, &data);
1733 put_rdata(res->txtlen, res->txtdata, &data);
1734
1735 result = send_msg(rep);
1736 if (result == t_error || result == t_terminated)
1737 {
1738 abort_request(rs);
1739 unlink_request(rs);
1740 freeL("resolve_result_callback", rep);
1741 }
1742 else if (result == t_complete) freeL("resolve_result_callback", rep);
1743 else append_reply(rs, rep);
1744 }
1745
1746 // what gets called when a resolve is completed and we need to send the data back to the client
1747 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1748 {
1749 char *data;
1750 char name[MAX_ESCAPED_DOMAIN_NAME];
1751 request_state *req = question->QuestionContext;
1752 reply_state *rep;
1753 size_t len;
1754 (void)m; // Unused
1755
1756 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1757 //mDNS_StopQuery(m, question);
1758
1759 // calculate reply data length
1760 len = sizeof(DNSServiceFlags);
1761 len += 2 * sizeof(uint32_t); // if index + ttl
1762 len += sizeof(DNSServiceErrorType);
1763 len += 3 * sizeof(uint16_t); // type, class, rdlen
1764 len += answer->rdlength;
1765 ConvertDomainNameToCString(answer->name, name);
1766 len += strlen(name) + 1;
1767
1768 rep = create_reply(query_reply, len, req);
1769
1770 rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
1771 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1772 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1773
1774 data = rep->sdata;
1775
1776 put_string(name, &data);
1777 put_short(answer->rrtype, &data);
1778 put_short(answer->rrclass, &data);
1779 put_short(answer->rdlength, &data);
1780 put_rdata(answer->rdlength, answer->rdata->u.data, &data);
1781 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1782
1783 append_reply(req, rep);
1784 return;
1785 }
1786
1787 mDNSlocal void question_termination_callback(void *context)
1788 {
1789 DNSQuestion *q = context;
1790 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
1791 mDNS_StopQuery(gmDNS, q); // no need to error check
1792 freeL("question_termination_callback", q);
1793 }
1794
1795 // If there's a comma followed by another character,
1796 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1797 // Otherwise, it returns a pointer to the final nul at the end of the string
1798 mDNSlocal char *FindFirstSubType(char *p)
1799 {
1800 while (*p)
1801 {
1802 if (p[0] == '\\' && p[1]) p += 2;
1803 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1804 else p++;
1805 }
1806 return(p);
1807 }
1808
1809 // If there's a comma followed by another character,
1810 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1811 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1812 // Otherwise, it returns a pointer to the final nul at the end of the string
1813 mDNSlocal char *FindNextSubType(char *p)
1814 {
1815 while (*p)
1816 {
1817 if (p[0] == '\\' && p[1]) // If escape character
1818 p += 2; // ignore following character
1819 else if (p[0] == ',') // If we found a comma
1820 {
1821 if (p[1]) *p++ = 0;
1822 return(p);
1823 }
1824 else if (p[0] == '.')
1825 return(mDNSNULL);
1826 else p++;
1827 }
1828 return(p);
1829 }
1830
1831 // Returns -1 if illegal subtype found
1832 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1833 {
1834 mDNSs32 NumSubTypes = 0;
1835 char *stp = FindFirstSubType(regtype);
1836 while (stp && *stp) // If we found a comma...
1837 {
1838 if (*stp == ',') return(-1);
1839 NumSubTypes++;
1840 stp = FindNextSubType(stp);
1841 }
1842 if (!stp) return(-1);
1843 return(NumSubTypes);
1844 }
1845
1846 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1847 {
1848 AuthRecord *st = mDNSNULL;
1849 if (NumSubTypes)
1850 {
1851 mDNSs32 i;
1852 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1853 if (!st) return(mDNSNULL);
1854 for (i = 0; i < NumSubTypes; i++)
1855 {
1856 mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1857 while (*p) p++;
1858 p++;
1859 if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
1860 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1861 }
1862 }
1863 return(st);
1864 }
1865
1866 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1867 mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
1868 {
1869 (void)m; // unused
1870 if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
1871 }
1872 #endif
1873
1874 mDNSlocal void handle_setdomain_request(request_state *request)
1875 {
1876 mStatus err = mStatus_NoError;
1877 char *ptr;
1878 char domainstr[MAX_ESCAPED_DOMAIN_NAME];
1879 domainname domain;
1880 DNSServiceFlags flags;
1881 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1882 struct xucred xuc;
1883 socklen_t xuclen;
1884 #endif
1885
1886 if (request->ts != t_complete)
1887 {
1888 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1889 abort_request(request);
1890 unlink_request(request);
1891 return;
1892 }
1893
1894 // extract flags/domain from message
1895 ptr = request->msgdata;
1896 flags = get_flags(&ptr);
1897 if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1898 !MakeDomainNameFromDNSNameString(&domain, domainstr))
1899 { err = mStatus_BadParamErr; goto end; }
1900
1901 freeL("handle_setdomain_request", request->msgbuf);
1902 request->msgbuf = NULL;
1903
1904 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
1905
1906 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1907 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1908 // the existence of this socket option
1909 xuclen = sizeof(xuc);
1910 if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
1911 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
1912 if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
1913 LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
1914
1915 if (flags & kDNSServiceFlagsAdd)
1916 {
1917 // register a local-only PRT record
1918 default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
1919 if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
1920 mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
1921 MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
1922 AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
1923 AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
1924 newelem->uid = xuc.cr_uid;
1925 err = mDNS_Register(gmDNS, &newelem->ptr_rec);
1926 if (err) free(newelem);
1927 else
1928 {
1929 // link into list
1930 newelem->next = default_browse_list;
1931 default_browse_list = newelem;
1932 }
1933
1934 }
1935 else
1936 {
1937 // remove - find in list, deregister
1938 default_browse_list_t *ptr = default_browse_list, *prev = NULL;
1939 while (ptr)
1940 {
1941 if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
1942 {
1943 if (prev) prev->next = ptr->next;
1944 else default_browse_list = ptr->next;
1945 err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
1946 break;
1947 }
1948 prev = ptr;
1949 ptr = ptr->next;
1950 }
1951 if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
1952 }
1953 #else
1954 err = mStatus_NoError;
1955 #endif // _HAVE_SETDOMAIN_SUPPORT_
1956
1957 end:
1958 deliver_error(request, err);
1959 abort_request(request);
1960 unlink_request(request);
1961 }
1962
1963 // Generates a response message giving name, type, domain, plus interface index,
1964 // suitable for a browse result or service registration result.
1965 // On successful completion rep is set to point to a malloc'd reply_state struct
1966 mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1967 {
1968 domainlabel name;
1969 domainname type, dom;
1970 *rep = NULL;
1971 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1972 return kDNSServiceErr_Invalid;
1973 else
1974 {
1975 char namestr[MAX_DOMAIN_LABEL+1];
1976 char typestr[MAX_ESCAPED_DOMAIN_NAME];
1977 char domstr [MAX_ESCAPED_DOMAIN_NAME];
1978 int len;
1979 char *data;
1980
1981 ConvertDomainLabelToCString_unescaped(&name, namestr);
1982 ConvertDomainNameToCString(&type, typestr);
1983 ConvertDomainNameToCString(&dom, domstr);
1984
1985 // Calculate reply data length
1986 len = sizeof(DNSServiceFlags);
1987 len += sizeof(uint32_t); // if index
1988 len += sizeof(DNSServiceErrorType);
1989 len += (int) (strlen(namestr) + 1);
1990 len += (int) (strlen(typestr) + 1);
1991 len += (int) (strlen(domstr) + 1);
1992
1993 // Build reply header
1994 *rep = create_reply(query_reply, len, request);
1995 (*rep)->rhdr->flags = dnssd_htonl(0);
1996 (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
1997 (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1998
1999 // Build reply body
2000 data = (*rep)->sdata;
2001 put_string(namestr, &data);
2002 put_string(typestr, &data);
2003 put_string(domstr, &data);
2004
2005 return mStatus_NoError;
2006 }
2007 }
2008
2009 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2010 {
2011 request_state *req = question->QuestionContext;
2012 reply_state *rep;
2013 (void)m; // Unused
2014
2015 if (answer->rrtype != kDNSType_PTR)
2016 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
2017
2018 if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
2019 {
2020 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2021 req->sd, answer->name->c, answer->rdata->u.name.c);
2022 return;
2023 }
2024
2025 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
2026 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2027
2028 if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
2029 append_reply(req, rep);
2030 }
2031
2032 mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
2033 {
2034 browser_t *b, *p;
2035 mStatus err;
2036
2037 for (p = info->browsers; p; p = p->next)
2038 {
2039 if (SameDomainName(&p->domain, d))
2040 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
2041 }
2042
2043 b = mallocL("browser_t", sizeof(*b));
2044 if (!b) return mStatus_NoMemoryErr;
2045 AssignDomainName(&b->domain, d);
2046 err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
2047 if (err)
2048 {
2049 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
2050 freeL("browser_t", b);
2051 }
2052 else
2053 {
2054 b->next = info->browsers;
2055 info->browsers = b;
2056 }
2057 return err;
2058 }
2059
2060 mDNSlocal void handle_browse_request(request_state *request)
2061 {
2062 DNSServiceFlags flags;
2063 uint32_t interfaceIndex;
2064 mDNSInterfaceID InterfaceID;
2065 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
2066 domainname typedn, d, temp;
2067 mDNSs32 NumSubTypes;
2068 char *ptr;
2069 mStatus err = mStatus_NoError;
2070 DNameListElem *search_domain_list, *sdom;
2071 browser_info_t *info = NULL;
2072
2073 if (request->ts != t_complete)
2074 {
2075 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
2076 abort_request(request);
2077 unlink_request(request);
2078 return;
2079 }
2080
2081 // extract data from message
2082 ptr = request->msgdata;
2083 flags = get_flags(&ptr);
2084 interfaceIndex = get_long(&ptr);
2085 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2086 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
2087 { err = mStatus_BadParamErr; goto error; }
2088 freeL("handle_browse_request", request->msgbuf);
2089 request->msgbuf = NULL;
2090
2091 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
2092 if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
2093
2094 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
2095 if ( !domain || ( domain[0] == '\0' ) )
2096 {
2097 dDNS_RegisterSearchDomains( gmDNS );
2098 }
2099 #endif
2100
2101 typedn.c[0] = 0;
2102 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
2103 if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
2104 if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
2105 { err = mStatus_BadParamErr; goto error; }
2106
2107 if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
2108
2109 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
2110 if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
2111
2112 // allocate and set up browser info
2113 info = mallocL("browser_info_t", sizeof(*info));
2114 if (!info) { err = mStatus_NoMemoryErr; goto error; }
2115
2116 request->browser_info = info;
2117 info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
2118 info->interface_id = InterfaceID;
2119 AssignDomainName(&info->regtype, &typedn);
2120 info->rstate = request;
2121 info->default_domain = !domain[0];
2122 info->browsers = NULL;
2123
2124 // setup termination context
2125 request->termination_context = info;
2126 request->terminate = browse_termination_callback;
2127
2128 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
2129 if (domain[0])
2130 {
2131 if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
2132 err = add_domain_to_browser(info, &d);
2133 }
2134
2135 else
2136 {
2137 search_domain_list = mDNSPlatformGetSearchDomainList();
2138 for (sdom = search_domain_list; sdom; sdom = sdom->next)
2139 {
2140 err = add_domain_to_browser(info, &sdom->name);
2141 if (err)
2142 {
2143 if (SameDomainName(&sdom->name, &localdomain)) break;
2144 else err = mStatus_NoError; // suppress errors for non-local "default" domains
2145 }
2146
2147 }
2148 mDNS_FreeDNameList(search_domain_list);
2149 }
2150
2151 deliver_error(request, err);
2152 return;
2153
2154 error:
2155 if (info) freeL("browser_info_t", info);
2156 if (request->termination_context) request->termination_context = NULL;
2157 deliver_error(request, err);
2158 abort_request(request);
2159 unlink_request(request);
2160 }
2161
2162 mDNSlocal void browse_termination_callback(void *context)
2163 {
2164 browser_info_t *info = context;
2165 browser_t *ptr;
2166
2167 if (!info) return;
2168
2169 while(info->browsers)
2170 {
2171 ptr = info->browsers;
2172 info->browsers = ptr->next;
2173 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
2174 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
2175 freeL("browse_termination_callback", ptr);
2176 }
2177
2178 info->rstate->termination_context = NULL;
2179 freeL("browser_info", info);
2180 }
2181
2182 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
2183 {
2184 request_state *r;
2185
2186 for (r = all_requests; r; r = r->next)
2187 {
2188 browser_info_t *info = r->browser_info;
2189
2190 if (!info || !info->default_domain) continue;
2191 if (add) add_domain_to_browser(info, d);
2192 else
2193 {
2194 browser_t **ptr = &info->browsers;
2195 while (*ptr)
2196 {
2197 if (SameDomainName(&(*ptr)->domain, d))
2198 {
2199 browser_t *remove = *ptr;
2200 *ptr = (*ptr)->next;
2201 if (remove->q.LongLived)
2202 {
2203 // give goodbyes for known answers.
2204 // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
2205 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
2206 while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
2207 }
2208 mDNS_StopBrowse(gmDNS, &remove->q);
2209 freeL("browser_t", remove);
2210 return;
2211 }
2212 ptr = &(*ptr)->next;
2213 }
2214 LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
2215 }
2216 }
2217 }
2218
2219 // Count how many other service records we have locally with the same name, but different rdata.
2220 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2221 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2222 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
2223 {
2224 int count = 0;
2225 ResourceRecord *r = &srs->RR_SRV.resrec;
2226 AuthRecord *rr;
2227 ServiceRecordSet *s;
2228
2229 for (rr = m->ResourceRecords; rr; rr=rr->next)
2230 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2231 count++;
2232
2233 for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
2234 if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2235 count++;
2236
2237 for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
2238 if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
2239 count++;
2240
2241 verbosedebugf("%d peer registrations for %##s", count, r->name->c);
2242 return(count);
2243 }
2244
2245 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
2246 {
2247 int count = 0;
2248 AuthRecord *rr;
2249 for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
2250 if (rr->resrec.rrtype == kDNSType_SRV &&
2251 rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
2252 SameDomainName(rr->resrec.name, srv))
2253 count++;
2254 return(count);
2255 }
2256
2257 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
2258 {
2259 service_info *info = request->service_registration;
2260 service_instance *ptr, *instance;
2261 int instance_size;
2262 mStatus result;
2263
2264 for (ptr = info->instances; ptr; ptr = ptr->next)
2265 {
2266 if (SameDomainName(&ptr->domain, domain))
2267 { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
2268 }
2269
2270 instance_size = sizeof(*instance);
2271 if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
2272 instance = mallocL("service_instance", instance_size);
2273 if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
2274
2275 instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
2276 if (info->num_subtypes && !instance->subtypes)
2277 { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
2278 instance->request = request;
2279 instance->sd = request->sd;
2280 instance->autoname = info->autoname;
2281 instance->autorename = info->autorename;
2282 instance->allowremotequery = info->allowremotequery;
2283 instance->rename_on_memfree = 0;
2284 instance->name = info->name;
2285 AssignDomainName(&instance->domain, domain);
2286 instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
2287 result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
2288 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
2289
2290 if (result) free_service_instance(instance);
2291 else
2292 {
2293 instance->next = info->instances;
2294 info->instances = instance;
2295 }
2296 return result;
2297 }
2298
2299 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
2300 {
2301 request_state *rstate;
2302 service_info *info;
2303
2304 LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
2305 for (rstate = all_requests; rstate; rstate = rstate->next)
2306 {
2307 if (rstate->terminate != regservice_termination_callback) continue;
2308 info = rstate->service_registration;
2309 if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2310 if (!info->default_domain) continue;
2311
2312 // valid default registration
2313 if (add) register_service_instance(rstate, d);
2314 else
2315 {
2316 // find the instance to remove
2317 service_instance *si = rstate->service_registration->instances, *prev = NULL;
2318 while (si)
2319 {
2320 if (SameDomainName(&si->domain, d))
2321 {
2322 mStatus err;
2323 if (prev) prev->next = si->next;
2324 else info->instances = si->next;
2325 err = mDNS_DeregisterService(gmDNS, &si->srs);
2326 if (err)
2327 {
2328 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
2329 free_service_instance(si);
2330 }
2331 break;
2332 }
2333 prev = si;
2334 si = si->next;
2335 }
2336 if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
2337 }
2338 }
2339 }
2340
2341 // service registration
2342 mDNSlocal void handle_regservice_request(request_state *request)
2343 {
2344 DNSServiceFlags flags;
2345 uint32_t ifi;
2346 char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2347 char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2348 char *ptr;
2349 domainname d, srv;
2350 mStatus result;
2351 service_info *service = NULL;
2352
2353 if (request->ts != t_complete)
2354 {
2355 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2356 abort_request(request);
2357 unlink_request(request);
2358 return;
2359 }
2360
2361 service = mallocL("service_info", sizeof(*service));
2362 if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2363
2364 service->instances = NULL;
2365 service->request = request;
2366 service->txtlen = 0;
2367 service->txtdata = NULL;
2368 request->service_registration = service;
2369 request->termination_context = request->service_registration;
2370 request->terminate = regservice_termination_callback;
2371
2372 // extract data from message
2373 ptr = request->msgdata;
2374 flags = get_flags(&ptr);
2375 ifi = get_long(&ptr);
2376 service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2377 if (ifi && !service->InterfaceID)
2378 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
2379 if (get_string(&ptr, name, sizeof(name)) < 0 ||
2380 get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2381 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2382 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
2383 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
2384
2385 service->port.b[0] = *ptr++;
2386 service->port.b[1] = *ptr++;
2387
2388 service->txtlen = get_short(&ptr);
2389 if (service->txtlen)
2390 {
2391 service->txtdata = mallocL("txtdata", service->txtlen);
2392 if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2393 memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
2394 }
2395 else service->txtdata = NULL;
2396
2397 // Check for sub-types after the service type
2398 service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
2399 if (service->num_subtypes < 0)
2400 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
2401
2402 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2403 if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
2404 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
2405
2406 if (!name[0])
2407 {
2408 service->name = (gmDNS)->nicelabel;
2409 service->autoname = mDNStrue;
2410 }
2411 else
2412 {
2413 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2414 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2415 {
2416 int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2417 name[newlen] = 0;
2418 }
2419 if (!MakeDomainLabelFromLiteralString(&service->name, name))
2420 { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2421 service->autoname = mDNSfalse;
2422 }
2423
2424 if (*domain)
2425 {
2426 service->default_domain = mDNSfalse;
2427 if (!MakeDomainNameFromDNSNameString(&d, domain))
2428 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2429 }
2430 else
2431 {
2432 service->default_domain = mDNStrue;
2433 MakeDomainNameFromDNSNameString(&d, "local.");
2434 }
2435
2436 if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
2437 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
2438
2439 if (!MakeDomainNameFromDNSNameString(&service->host, host))
2440 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2441 service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
2442 service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2443
2444 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2445 // a port number of zero. When two instances of the protected client are allowed to run on one
2446 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2447 if (service->port.NotAnInteger)
2448 {
2449 int count = CountExistingRegistrations(&srv, service->port);
2450 if (count)
2451 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2452 count+1, srv.c, mDNSVal16(service->port));
2453 }
2454
2455 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2456 request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
2457 result = register_service_instance(request, &d);
2458
2459 if (!result && !*domain)
2460 {
2461 DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
2462 for (ptr = def_domains; ptr; ptr = ptr->next)
2463 register_service_instance(request, &ptr->name);
2464 // note that we don't report errors for non-local, non-explicit domains
2465 mDNS_FreeDNameList(def_domains);
2466 }
2467
2468 finish:
2469 deliver_error(request, result);
2470 if (result != mStatus_NoError)
2471 {
2472 abort_request(request);
2473 unlink_request(request);
2474 }
2475 else
2476 reset_connected_rstate(request); // prepare to receive add/remove messages
2477
2478 return;
2479
2480 bad_param:
2481 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2482 deliver_error(request, mStatus_BadParamErr);
2483 abort_request(request);
2484 unlink_request(request);
2485 }
2486
2487 // service registration callback performs three duties - frees memory for deregistered services,
2488 // handles name conflicts, and delivers completed registration information to the client (via
2489 // process_service_registraion())
2490
2491 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
2492 {
2493 mStatus err;
2494 mDNSBool SuppressError = mDNSfalse;
2495 service_instance *instance = srs->ServiceContext;
2496 (void)m; // Unused
2497 if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
2498 if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
2499
2500 if (instance->request && instance->request->service_registration)
2501 {
2502 service_info *info = instance->request->service_registration;
2503 if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
2504 // don't send errors up to client for wide-area, empty-string registrations
2505 }
2506
2507 if (result == mStatus_NoError)
2508 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2509 else if (result == mStatus_MemFree)
2510 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2511 else if (result == mStatus_NameConflict)
2512 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2513 else
2514 LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
2515
2516 if (result == mStatus_NoError)
2517 {
2518 request_state *req = instance->request;
2519 if (instance->allowremotequery)
2520 {
2521 ExtraResourceRecord *e;
2522 srs->RR_ADV.AllowRemoteQuery = mDNStrue;
2523 srs->RR_PTR.AllowRemoteQuery = mDNStrue;
2524 srs->RR_SRV.AllowRemoteQuery = mDNStrue;
2525 srs->RR_TXT.AllowRemoteQuery = mDNStrue;
2526 for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
2527 }
2528
2529 if (!req) LogMsg("ERROR: regservice_callback - null request object");
2530 else
2531 {
2532 reply_state *rep;
2533 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
2534 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
2535 else
2536 {
2537 transfer_state send_result = send_msg(rep);
2538 if (send_result == t_error || send_result == t_terminated)
2539 { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
2540 else if (send_result == t_complete) freeL("regservice_callback", rep);
2541 else append_reply(req, rep);
2542 }
2543 }
2544 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2545 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
2546 return;
2547 }
2548 else if (result == mStatus_MemFree)
2549 {
2550 if (instance->rename_on_memfree)
2551 {
2552 instance->rename_on_memfree = 0;
2553 instance->name = gmDNS->nicelabel;
2554 err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
2555 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
2556 // error should never happen - safest to log and continue
2557 }
2558 else
2559 {
2560 free_service_instance(instance);
2561 return;
2562 }
2563 }
2564 else if (result == mStatus_NameConflict)
2565 {
2566 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2567 {
2568 // On conflict for an autoname service, rename and reregister *all* autoname services
2569 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
2570 m->MainCallback(m, mStatus_ConfigChanged);
2571 }
2572 else if (instance->autoname || instance->autorename)
2573 {
2574 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
2575 return;
2576 }
2577 else
2578 {
2579 request_state *rs = instance->request;
2580 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2581 free_service_instance(instance);
2582 if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
2583 {
2584 abort_request(rs);
2585 unlink_request(rs);
2586 }
2587 return;
2588 }
2589 }
2590 else
2591 {
2592 request_state *rs = instance->request;
2593 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2594 if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
2595 free_service_instance(instance);
2596 if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
2597 {
2598 abort_request(rs);
2599 unlink_request(rs);
2600 }
2601 return;
2602 }
2603 }
2604
2605 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
2606 {
2607 ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
2608 (void)m; //unused
2609
2610 if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
2611
2612 debugf("%##s: MemFree", rr->resrec.name->c);
2613 if (rr->resrec.rdata != &rr->rdatastorage)
2614 freeL("Extra RData", rr->resrec.rdata);
2615 freeL("ExtraResourceRecord", extra);
2616 }
2617
2618 mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
2619 {
2620 ServiceRecordSet *srs = &instance->srs;
2621 ExtraResourceRecord *extra;
2622 mStatus result;
2623 int size;
2624
2625 if (rdlen > sizeof(RDataBody)) size = rdlen;
2626 else size = sizeof(RDataBody);
2627
2628 extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
2629 if (!extra)
2630 {
2631 my_perror("ERROR: malloc");
2632 return mStatus_NoMemoryErr;
2633 }
2634
2635 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
2636 extra->r.resrec.rrtype = rrtype;
2637 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
2638 extra->r.resrec.rdlength = rdlen;
2639 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
2640
2641 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
2642 if (result) { freeL("ExtraResourceRecord", extra); return result; }
2643
2644 extra->ClientID = rstate->hdr.reg_index;
2645 return result;
2646 }
2647
2648 mDNSlocal mStatus handle_add_request(request_state *rstate)
2649 {
2650 uint32_t ttl;
2651 uint16_t rrtype, rdlen;
2652 char *ptr, *rdata;
2653 mStatus result = mStatus_UnknownErr;
2654 DNSServiceFlags flags;
2655 service_info *srvinfo = rstate->service_registration;
2656 service_instance *i;
2657
2658 if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2659
2660 ptr = rstate->msgdata;
2661 flags = get_flags(&ptr);
2662 rrtype = get_short(&ptr);
2663 rdlen = get_short(&ptr);
2664 rdata = get_rdata(&ptr, rdlen);
2665 ttl = get_long(&ptr);
2666
2667 if (!ttl) ttl = DefaultTTLforRRType(rrtype);
2668
2669 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
2670 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
2671
2672 for (i = srvinfo->instances; i; i = i->next)
2673 {
2674 result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
2675 if (result && i->default_local) break;
2676 else result = mStatus_NoError; // suppress non-local default errors
2677 }
2678
2679 return(result);
2680 }
2681
2682 mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
2683 {
2684 int rdsize;
2685 RData *newrd;
2686 mStatus result;
2687
2688 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
2689 else rdsize = sizeof(RDataBody);
2690 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
2691 if (!newrd) FatalError("ERROR: malloc");
2692 newrd->MaxRDLength = (mDNSu16) rdsize;
2693 memcpy(&newrd->u, rdata, rdlen);
2694
2695 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2696 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2697 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2698 if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
2699
2700 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
2701 if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
2702 return result;
2703 }
2704
2705 mDNSlocal mStatus handle_update_request(request_state *rstate)
2706 {
2707 uint16_t rdlen;
2708 char *ptr, *rdata;
2709 uint32_t ttl;
2710 mStatus result = mStatus_BadReferenceErr;
2711 service_info *srvinfo = rstate->service_registration;
2712 service_instance *i;
2713 AuthRecord *rr = NULL;
2714
2715 // get the message data
2716 ptr = rstate->msgdata;
2717 get_flags(&ptr); // flags unused
2718 rdlen = get_short(&ptr);
2719 rdata = get_rdata(&ptr, rdlen);
2720 ttl = get_long(&ptr);
2721
2722 if (rstate->reg_recs)
2723 {
2724 // update an individually registered record
2725 registered_record_entry *reptr;
2726 for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
2727 {
2728 if (reptr->key == rstate->hdr.reg_index)
2729 {
2730 result = update_record(reptr->rr, rdlen, rdata, ttl);
2731 goto end;
2732 }
2733 }
2734 result = mStatus_BadReferenceErr;
2735 goto end;
2736 }
2737
2738 // update a record from a service record set
2739 if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
2740 for (i = srvinfo->instances; i; i = i->next)
2741 {
2742 if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
2743 else
2744 {
2745 ExtraResourceRecord *e;
2746 for (e = i->srs.Extras; e; e = e->next)
2747 if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
2748 }
2749
2750 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
2751 result = update_record(rr, rdlen, rdata, ttl);
2752 if (result && i->default_local) goto end;
2753 else result = mStatus_NoError; // suppress non-local default errors
2754 }
2755
2756 end:
2757 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
2758 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
2759 rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
2760
2761 return(result);
2762 }
2763
2764 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
2765 {
2766 (void)m; // Unused
2767 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
2768 }
2769
2770 mDNSlocal void free_service_instance(service_instance *srv)
2771 {
2772 request_state *rstate = srv->request;
2773 ExtraResourceRecord *e = srv->srs.Extras, *tmp;
2774
2775 // clear pointers from parent struct
2776 if (rstate)
2777 {
2778 service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
2779 while (ptr)
2780 {
2781 if (ptr == srv)
2782 {
2783 if (prev) prev->next = ptr->next;
2784 else rstate->service_registration->instances = ptr->next;
2785 break;
2786 }
2787 prev = ptr;
2788 ptr = ptr->next;
2789 }
2790 }
2791
2792 while(e)
2793 {
2794 e->r.RecordContext = e;
2795 tmp = e;
2796 e = e->next;
2797 FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
2798 }
2799
2800 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
2801 freeL("regservice_callback", srv);
2802 }
2803
2804 mDNSlocal void regservice_termination_callback(void *context)
2805 {
2806 service_info *info = context;
2807 service_instance *i, *p;
2808 if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
2809 if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2810 i = info->instances;
2811 while (i)
2812 {
2813 p = i;
2814 i = i->next;
2815 p->request = NULL; // clear back pointer
2816 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2817 LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
2818 if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
2819 }
2820 info->request->service_registration = NULL; // clear pointer from request back to info
2821 if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
2822 freeL("service_info", info);
2823 }
2824
2825 mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
2826 {
2827 AuthRecord *rr;
2828 registered_record_entry *re;
2829 mStatus result;
2830
2831 if (rstate->ts != t_complete)
2832 {
2833 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2834 abort_request(rstate);
2835 unlink_request(rstate);
2836 return(-1);
2837 }
2838
2839 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
2840 if (!rr) return(mStatus_BadParamErr);
2841
2842 // allocate registration entry, link into list
2843 re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
2844 if (!re) FatalError("ERROR: malloc");
2845 re->key = rstate->hdr.reg_index;
2846 re->rr = rr;
2847 re->rstate = rstate;
2848 re->client_context = rstate->hdr.client_context;
2849 rr->RecordContext = re;
2850 rr->RecordCallback = regrecord_callback;
2851 re->next = rstate->reg_recs;
2852 rstate->reg_recs = re;
2853
2854 if (!rstate->terminate)
2855 {
2856 rstate->terminate = connected_registration_termination;
2857 rstate->termination_context = rstate;
2858 }
2859
2860 if (rr->resrec.rroriginalttl == 0)
2861 rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
2862
2863 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
2864 result = mDNS_Register(gmDNS, rr);
2865 return(result);
2866 }
2867
2868 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
2869 {
2870 registered_record_entry *re = rr->RecordContext;
2871 request_state *rstate = re ? re->rstate : NULL;
2872 int len;
2873 reply_state *reply;
2874 transfer_state ts;
2875 (void)m; // Unused
2876
2877 if (!re)
2878 {
2879 // parent struct alreadt freed by termination callback
2880 if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2881 else
2882 {
2883 if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
2884 freeL("regrecord_callback", rr);
2885 }
2886 return;
2887 }
2888
2889 // format result, add to the list for the request, including the client context in the header
2890 len = sizeof(DNSServiceFlags);
2891 len += sizeof(uint32_t); //interfaceIndex
2892 len += sizeof(DNSServiceErrorType);
2893
2894 reply = create_reply(reg_record_reply, len, rstate);
2895 reply->mhdr->client_context = re->client_context;
2896 reply->rhdr->flags = dnssd_htonl(0);
2897 reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
2898 reply->rhdr->error = dnssd_htonl(result);
2899
2900 if (result)
2901 {
2902 // unlink from list, free memory
2903 registered_record_entry **ptr = &re->rstate->reg_recs;
2904 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
2905 if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
2906 *ptr = (*ptr)->next;
2907 freeL("regrecord_callback", re->rr);
2908 re->rr = rr = NULL;
2909 freeL("regrecord_callback", re);
2910 re = NULL;
2911 }
2912
2913 ts = send_msg(reply);
2914
2915 if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
2916 else if (ts == t_complete) freeL("regrecord_callback", reply);
2917 else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
2918 }
2919
2920 mDNSlocal void connected_registration_termination(void *context)
2921 {
2922 int shared;
2923 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
2924 while(ptr)
2925 {
2926 fptr = ptr;
2927 ptr = ptr->next;
2928 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
2929 fptr->rr->RecordContext = NULL;
2930 mDNS_Deregister(gmDNS, fptr->rr);
2931 freeL("connected_registration_termination", fptr);
2932 }
2933 }
2934
2935 mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
2936 {
2937 mStatus err = mStatus_BadReferenceErr;
2938 char *ptr;
2939 service_info *srvinfo = rstate->service_registration;
2940
2941 ptr = rstate->msgdata;
2942 get_flags(&ptr); // flags unused
2943
2944 if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
2945 else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
2946 else
2947 {
2948 service_instance *i;
2949 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
2950 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
2951 for (i = srvinfo->instances; i; i = i->next)
2952 {
2953 err = remove_extra(rstate, i);
2954 if (err && i->default_local) break;
2955 else err = mStatus_NoError; // suppress non-local default errors
2956 }
2957 }
2958
2959 return(err);
2960 }
2961
2962 // remove a resource record registered via DNSServiceRegisterRecord()
2963 mDNSlocal mStatus remove_record(request_state *rstate)
2964 {
2965 int shared;
2966 mStatus err = mStatus_UnknownErr;
2967 registered_record_entry *e, **ptr = &rstate->reg_recs;
2968
2969 while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
2970 if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
2971 e = *ptr;
2972 *ptr = e->next; // unlink
2973
2974 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
2975 shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
2976 e->rr->RecordContext = NULL;
2977 err = mDNS_Deregister(gmDNS, e->rr);
2978 if (err)
2979 {
2980 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
2981 freeL("remove_record", e->rr);
2982 freeL("remove_record", e);
2983 }
2984 return err;
2985 }
2986
2987 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
2988 {
2989 mStatus err = mStatus_BadReferenceErr;
2990 ExtraResourceRecord *ptr;
2991
2992 for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
2993 {
2994 if (ptr->ClientID == rstate->hdr.reg_index) // found match
2995 return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
2996 }
2997 return err;
2998 }
2999
3000 // domain enumeration
3001 mDNSlocal void handle_enum_request(request_state *rstate)
3002 {
3003 DNSServiceFlags flags;
3004 uint32_t ifi;
3005 mDNSInterfaceID InterfaceID;
3006 char *ptr = rstate->msgdata;
3007 domain_enum_t *def, *all;
3008 enum_termination_t *term;
3009 mStatus err;
3010 int result;
3011
3012 if (rstate->ts != t_complete)
3013 {
3014 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
3015 abort_request(rstate);
3016 unlink_request(rstate);
3017 return;
3018 }
3019
3020 flags = get_flags(&ptr);
3021 ifi = get_long(&ptr);
3022 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
3023 if (ifi && !InterfaceID)
3024 {
3025 deliver_error(rstate, mStatus_BadParamErr);
3026 abort_request(rstate);
3027 unlink_request(rstate);
3028 return;
3029 }
3030
3031 // allocate context structures
3032 def = mallocL("handle_enum_request", sizeof(domain_enum_t));
3033 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
3034 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
3035 if (!def || !all || !term) FatalError("ERROR: malloc");
3036
3037 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
3038 dDNS_RegisterSearchDomains( gmDNS );
3039 #endif
3040
3041 // enumeration requires multiple questions, so we must link all the context pointers so that
3042 // necessary context can be reached from the callbacks
3043 def->rstate = rstate;
3044 all->rstate = rstate;
3045 term->def = def;
3046 term->all = all;
3047 term->rstate = rstate;
3048 rstate->termination_context = term;
3049 rstate->terminate = enum_termination_callback;
3050 def->question.QuestionContext = def;
3051 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3052 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
3053 all->question.QuestionContext = all;
3054 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3055 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
3056
3057 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
3058 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
3059
3060 // make the calls
3061 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
3062 (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
3063 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
3064 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
3065 if (err == mStatus_NoError)
3066 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
3067 result = deliver_error(rstate, err); // send error *before* returning local domain
3068
3069 if (result < 0 || err)
3070 {
3071 abort_request(rstate);
3072 unlink_request(rstate);
3073 return;
3074 }
3075 }
3076
3077 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
3078 {
3079 char domain[MAX_ESCAPED_DOMAIN_NAME];
3080 domain_enum_t *de = question->QuestionContext;
3081 DNSServiceFlags flags = 0;
3082 reply_state *reply;
3083 (void)m; // Unused
3084
3085 if (answer->rrtype != kDNSType_PTR) return;
3086 if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
3087
3088 if (AddRecord)
3089 {
3090 flags |= kDNSServiceFlagsAdd;
3091 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
3092 flags |= kDNSServiceFlagsDefault;
3093 }
3094 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
3095 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3096 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3097 // network, so we just pass kDNSServiceInterfaceIndexAny
3098 reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
3099 if (!reply)
3100 {
3101 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
3102 return;
3103 }
3104 reply->next = NULL;
3105 append_reply(de->rstate, reply);
3106 return;
3107 }
3108
3109 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
3110 {
3111 size_t len;
3112 reply_state *reply;
3113 char *data;
3114
3115 len = sizeof(DNSServiceFlags);
3116 len += sizeof(uint32_t);
3117 len += sizeof(DNSServiceErrorType);
3118 len += strlen(domain) + 1;
3119
3120 reply = create_reply(enumeration_reply, len, rstate);
3121 reply->rhdr->flags = dnssd_htonl(flags);
3122 reply->rhdr->ifi = dnssd_htonl(ifi);
3123 reply->rhdr->error = dnssd_htonl(err);
3124 data = reply->sdata;
3125 put_string(domain, &data);
3126 return reply;
3127 }
3128
3129 mDNSlocal void enum_termination_callback(void *context)
3130 {
3131 enum_termination_t *t = context;
3132 mDNS *coredata = gmDNS;
3133
3134 mDNS_StopGetDomains(coredata, &t->all->question);
3135 mDNS_StopGetDomains(coredata, &t->def->question);
3136 freeL("enum_termination_callback", t->all);
3137 freeL("enum_termination_callback", t->def);
3138 t->rstate->termination_context = NULL;
3139 freeL("enum_termination_callback", t);
3140 }
3141
3142 mDNSlocal void handle_reconfirm_request(request_state *rstate)
3143 {
3144 AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
3145 if (rr)
3146 {
3147 mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
3148 LogOperation(
3149 (status == mStatus_NoError) ?
3150 "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
3151 "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
3152 rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
3153 mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
3154 status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
3155 }
3156 abort_request(rstate);
3157 unlink_request(rstate);
3158 freeL("handle_reconfirm_request", rr);
3159 }
3160
3161 // setup rstate to accept new reg/dereg requests
3162 mDNSlocal void reset_connected_rstate(request_state *rstate)
3163 {
3164 rstate->ts = t_morecoming;
3165 rstate->hdr_bytes = 0;
3166 rstate->data_bytes = 0;
3167 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
3168 rstate->msgbuf = NULL;
3169 rstate->bufsize = 0;
3170 }
3171
3172 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3173 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3174 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3175 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
3176 {
3177 char *rdata, name[256];
3178 AuthRecord *rr;
3179 DNSServiceFlags flags;
3180 uint32_t interfaceIndex;
3181 uint16_t type, class, rdlen;
3182 int storage_size;
3183
3184 flags = get_flags(&msgbuf);
3185 if (validate_flags &&
3186 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
3187 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
3188 {
3189 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3190 return NULL;
3191 }
3192
3193 interfaceIndex = get_long(&msgbuf);
3194 if (get_string(&msgbuf, name, 256) < 0)
3195 {
3196 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3197 return NULL;
3198 }
3199 type = get_short(&msgbuf);
3200 class = get_short(&msgbuf);
3201 rdlen = get_short(&msgbuf);
3202
3203 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
3204 else storage_size = sizeof(RDataBody);
3205
3206 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
3207 if (!rr) FatalError("ERROR: malloc");
3208 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
3209
3210 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
3211 type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
3212
3213 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
3214 {
3215 LogMsg("ERROR: bad name: %s", name);
3216 freeL("read_rr_from_ipc_msg", rr);
3217 return NULL;
3218 }
3219
3220 if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
3221 rr->resrec.rrclass = class;
3222 rr->resrec.rdlength = rdlen;
3223 rr->resrec.rdata->MaxRDLength = rdlen;
3224 rdata = get_rdata(&msgbuf, rdlen);
3225 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
3226 if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
3227 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3228 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
3229 return rr;
3230 }
3231
3232 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
3233 {
3234 domainlabel n;
3235 domainname d, t;
3236
3237 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
3238 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
3239 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
3240 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
3241 return 0;
3242 }
3243
3244 // append a reply to the list in a request object
3245 mDNSlocal void append_reply(request_state *req, reply_state *rep)
3246 {
3247 reply_state *ptr;
3248
3249 if (!req->replies) req->replies = rep;
3250 else
3251 {
3252 ptr = req->replies;
3253 while (ptr->next) ptr = ptr->next;
3254 ptr->next = rep;
3255 }
3256 rep->next = NULL;
3257 }
3258
3259 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3260 // returns the current state of the request (morecoming, error, complete, terminated.)
3261 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3262 mDNSlocal int read_msg(request_state *rs)
3263 {
3264 uint32_t nleft;
3265 int nread;
3266 char buf[4]; // dummy for death notification
3267
3268 if (rs->ts == t_terminated || rs->ts == t_error)
3269 {
3270 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3271 rs->ts = t_error;
3272 return t_error;
3273 }
3274
3275 if (rs->ts == t_complete)
3276 { // this must be death or something is wrong
3277 nread = recv(rs->sd, buf, 4, 0);
3278 if (!nread) { rs->ts = t_terminated; return t_terminated; }
3279 if (nread < 0) goto rerror;
3280 LogMsg("ERROR: read data from a completed request.");
3281 rs->ts = t_error;
3282 return t_error;
3283 }
3284
3285 if (rs->ts != t_morecoming)
3286 {
3287 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
3288 rs->ts = t_error;
3289 return t_error;
3290 }
3291
3292 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
3293 {
3294 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
3295 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
3296 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3297 if (nread < 0) goto rerror;
3298 rs->hdr_bytes += nread;
3299 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3300 {
3301 ConvertHeaderBytes(&rs->hdr);
3302 if (rs->hdr.version != VERSION)
3303 {
3304 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
3305 rs->ts = t_error;
3306 return t_error;
3307 }
3308 }
3309 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
3310 {
3311 LogMsg("ERROR: read_msg - read too many header bytes");
3312 rs->ts = t_error;
3313 return t_error;
3314 }
3315 }
3316
3317 // only read data if header is complete
3318 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3319 {
3320 if (rs->hdr.datalen == 0) // ok in removerecord requests
3321 {
3322 rs->ts = t_complete;
3323 rs->msgbuf = NULL;
3324 return t_complete;
3325 }
3326
3327 if (!rs->msgbuf) // allocate the buffer first time through
3328 {
3329 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
3330 if (!rs->msgbuf)
3331 {
3332 my_perror("ERROR: malloc");
3333 rs->ts = t_error;
3334 return t_error;
3335 }
3336 rs->msgdata = rs->msgbuf;
3337 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
3338 }
3339 nleft = rs->hdr.datalen - rs->data_bytes;
3340 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
3341 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3342 if (nread < 0) goto rerror;
3343 rs->data_bytes += nread;
3344 if (rs->data_bytes > rs->hdr.datalen)
3345 {
3346 LogMsg("ERROR: read_msg - read too many data bytes");
3347 rs->ts = t_error;
3348 return t_error;
3349 }
3350 }
3351
3352 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
3353 rs->ts = t_complete;
3354 else rs->ts = t_morecoming;
3355
3356 return rs->ts;
3357
3358 rerror:
3359 if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
3360 my_perror("ERROR: read_msg");
3361 rs->ts = t_error;
3362 return t_error;
3363 }
3364
3365 mDNSlocal int send_msg(reply_state *rs)
3366 {
3367 ssize_t nwriten;
3368
3369 if (!rs->msgbuf)
3370 {
3371 LogMsg("ERROR: send_msg called with NULL message buffer");
3372 return t_error;
3373 }
3374
3375 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
3376 {
3377 rs->ts = t_complete;
3378 freeL("send_msg", rs->msgbuf);
3379 return t_complete;
3380 }
3381
3382 ConvertHeaderBytes(rs->mhdr);
3383 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
3384 ConvertHeaderBytes(rs->mhdr);
3385 if (nwriten < 0)
3386 {
3387 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
3388 else
3389 {
3390 #if !defined(PLATFORM_NO_EPIPE)
3391 if (dnssd_errno() == EPIPE)
3392 {
3393 debugf("%3d: broken pipe", rs->sd);
3394 rs->ts = t_terminated;
3395 rs->request->ts = t_terminated;
3396 return t_terminated;
3397 }
3398 else
3399 #endif
3400 {
3401 my_perror("ERROR: send\n");
3402 rs->ts = t_error;
3403 return t_error;
3404 }
3405 }
3406 }
3407 rs->nwriten += nwriten;
3408
3409 if (rs->nwriten == rs->len)
3410 {
3411 rs->ts = t_complete;
3412 freeL("send_msg", rs->msgbuf);
3413 }
3414 return rs->ts;
3415 }
3416
3417 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
3418 {
3419 reply_state *reply;
3420 int totallen;
3421
3422 if ((unsigned)datalen < sizeof(reply_hdr))
3423 {
3424 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3425 return NULL;
3426 }
3427
3428 totallen = (int) (datalen + sizeof(ipc_msg_hdr));
3429 reply = mallocL("create_reply", sizeof(reply_state));
3430 if (!reply) FatalError("ERROR: malloc");
3431 bzero(reply, sizeof(reply_state));
3432 reply->ts = t_morecoming;
3433 reply->sd = request->sd;
3434 reply->request = request;
3435 reply->len = totallen;
3436 reply->msgbuf = mallocL("create_reply", totallen);
3437 if (!reply->msgbuf) FatalError("ERROR: malloc");
3438 bzero(reply->msgbuf, totallen);
3439 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
3440 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
3441 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
3442 reply->mhdr->version = VERSION;
3443 reply->mhdr->op = op;
3444 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
3445 return reply;
3446 }
3447
3448 mDNSlocal int deliver_error(request_state *rstate, mStatus err)
3449 {
3450 int nwritten = -1;
3451 undelivered_error_t *undeliv;
3452
3453 err = dnssd_htonl(err);
3454 nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
3455 if (nwritten < (int)sizeof(mStatus))
3456 {
3457 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3458 nwritten = 0;
3459 if (nwritten < 0)
3460 {
3461 my_perror("ERROR: send - unable to deliver error to client");
3462 return(-1);
3463 }
3464 else
3465 {
3466 //client blocked - store result and come backr
3467 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
3468 if (!undeliv) FatalError("ERROR: malloc");
3469 undeliv->err = err;
3470 undeliv->nwritten = nwritten;
3471 undeliv->sd = rstate->sd;
3472 rstate->u_err = undeliv;
3473 return 0;
3474 }
3475 }
3476 return 0;
3477 }
3478
3479 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3480 mDNSlocal transfer_state send_undelivered_error(request_state *rs)
3481 {
3482 int nwritten;
3483
3484 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
3485 if (nwritten < 0)
3486 {
3487 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3488 nwritten = 0;
3489 else
3490 {
3491 my_perror("ERROR: send - unable to deliver error to client\n");
3492 return t_error;
3493 }
3494 }
3495 if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
3496 {
3497 freeL("send_undelivered_error", rs->u_err);
3498 rs->u_err = NULL;
3499 return t_complete;
3500 }
3501 rs->u_err->nwritten += nwritten;
3502 return t_morecoming;
3503 }
3504
3505 // send bogus data along with an error code to the app callback
3506 // returns 0 on success (linking reply into list of not fully delivered),
3507 // -1 on failure (request should be aborted)
3508 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
3509 {
3510 int len;
3511 reply_state *reply;
3512 transfer_state ts;
3513
3514 if (rs->no_reply) return 0;
3515 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
3516 reply = create_reply(op, len, rs);
3517 reply->rhdr->error = dnssd_htonl(err);
3518 ts = send_msg(reply);
3519 if (ts == t_error || ts == t_terminated)
3520 {
3521 freeL("deliver_async_error", reply);
3522 return -1;
3523 }
3524 else if (ts == t_complete) freeL("deliver_async_error", reply);
3525 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
3526 return 0;
3527 }
3528
3529 mDNSlocal void abort_request(request_state *rs)
3530 {
3531 reply_state *rep, *ptr;
3532
3533 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
3534 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
3535 LogOperation("%3d: Removing FD", rs->sd);
3536 udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
3537
3538 // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
3539 // for detecting when the memory for an object is inadvertently freed while the object is still on some list
3540 rs->sd = -2;
3541
3542 // free pending replies
3543 rep = rs->replies;
3544 while(rep)
3545 {
3546 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
3547 ptr = rep;
3548 rep = rep->next;
3549 freeL("abort_request", ptr);
3550 }
3551
3552 if (rs->u_err)
3553 {
3554 freeL("abort_request", rs->u_err);
3555 rs->u_err = NULL;
3556 }
3557 }
3558
3559 mDNSlocal void unlink_request(request_state *rs)
3560 {
3561 request_state *ptr;
3562
3563 if (rs == all_requests)
3564 {
3565 all_requests = all_requests->next;
3566 freeL("unlink_request", rs);
3567 return;
3568 }
3569 for(ptr = all_requests; ptr->next; ptr = ptr->next)
3570 if (ptr->next == rs)
3571 {
3572 ptr->next = rs->next;
3573 freeL("unlink_request", rs);
3574 return;
3575 }
3576 }
3577
3578 //hack to search-replace perror's to LogMsg's
3579 mDNSlocal void my_perror(char *errmsg)
3580 {
3581 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
3582 }
3583
3584 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3585 // without overrunning it.
3586 // returns 0 on success, -1 on error.
3587
3588 mDNSlocal int validate_message(request_state *rstate)
3589 {
3590 uint32_t min_size;
3591
3592 switch(rstate->hdr.op)
3593 {
3594 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
3595 sizeof(uint32_t) + // interface
3596 (3 * sizeof(char)); // name, regtype, domain
3597 break;
3598 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
3599 sizeof(uint32_t) + // interface
3600 sizeof(char) + // fullname
3601 (2 * sizeof(uint16_t)); // type, class
3602 break;
3603 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
3604 sizeof(uint32_t) + // interface
3605 (2 * sizeof(char)); // regtype, domain
3606 break;
3607 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
3608 sizeof(uint32_t) + // interface
3609 (4 * sizeof(char)) + // name, type, domain, host
3610 (2 * sizeof(uint16_t)); // port, textlen
3611 break;
3612 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
3613 sizeof(uint32_t); // interface
3614 break;
3615 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3616 sizeof(uint32_t) + // interface
3617 sizeof(char) + // fullname
3618 (3 * sizeof(uint16_t)) + // type, class, rdlen
3619 sizeof(uint32_t); // ttl
3620 break;
3621 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3622 (2 * sizeof(uint16_t)) + // type, rdlen
3623 sizeof(uint32_t); // ttl
3624 break;
3625 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3626 sizeof(uint16_t) + // rdlen
3627 sizeof(uint32_t); // ttl
3628 break;
3629 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
3630 break;
3631 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
3632 sizeof(uint32_t) + // interface
3633 sizeof(char) + // fullname
3634 (3 * sizeof(uint16_t)); // type, class, rdlen
3635 break;
3636 case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
3637 break;
3638 default:
3639 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
3640 return -1;
3641 }
3642
3643 return (rstate->data_bytes >= min_size ? 0 : -1);
3644
3645 }
3646
3647 mDNSlocal uint32_t dnssd_htonl(uint32_t l)
3648 {
3649 uint32_t ret;
3650 char * data;
3651
3652 data = (char*) &ret;
3653
3654 put_long(l, &data);
3655
3656 return ret;
3657 }
3658
3659 #if defined(_WIN32)
3660
3661 mDNSlocal char * win32_strerror(int inErrorCode)
3662 {
3663 static char buffer[1024];
3664 DWORD n;
3665
3666 memset(buffer, 0, sizeof(buffer));
3667
3668 n = FormatMessageA(
3669 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
3670 NULL,
3671 (DWORD) inErrorCode,
3672 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
3673 buffer,
3674 sizeof( buffer ),
3675 NULL );
3676
3677 if( n > 0 )
3678 {
3679 // Remove any trailing CR's or LF's since some messages have them.
3680
3681 while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
3682 {
3683 buffer[ --n ] = '\0';
3684 }
3685 }
3686
3687 return buffer;
3688 }
3689
3690 #endif