]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/uds_daemon.c
mDNSResponder-107.6.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 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 Change History (most recent first):
18
19 $Log: uds_daemon.c,v $
20 Revision 1.201.2.1 2006/08/29 06:24:36 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
22
23 Revision 1.201 2006/06/29 03:02:47 cheshire
24 <rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
25
26 Revision 1.200 2006/06/28 08:56:26 cheshire
27 Added "_op" to the end of the operation code enum values,
28 to differentiate them from the routines with the same names
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->ReturnCNAME = (flags & kDNSServiceFlagsReturnCNAME) != 0;
1509 q->QuestionCallback = question_result_callback;
1510 q->QuestionContext = rstate;
1511
1512 rstate->termination_context = q;
1513 rstate->terminate = question_termination_callback;
1514
1515 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
1516 result = mDNS_StartQuery(gmDNS, q);
1517 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
1518
1519 if (result) rstate->terminate = NULL;
1520 if (deliver_error(rstate, result) < 0) goto error;
1521 return;
1522
1523 bad_param:
1524 deliver_error(rstate, mStatus_BadParamErr);
1525 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
1526 error:
1527 abort_request(rstate);
1528 unlink_request(rstate);
1529 return;
1530 }
1531
1532 mDNSlocal void handle_resolve_request(request_state *rstate)
1533 {
1534 DNSServiceFlags flags;
1535 uint32_t interfaceIndex;
1536 mDNSInterfaceID InterfaceID;
1537 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1538 char *ptr; // message data pointer
1539 domainname fqdn;
1540 resolve_termination_t *term;
1541 mStatus err;
1542
1543 if (rstate->ts != t_complete)
1544 {
1545 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1546 abort_request(rstate);
1547 unlink_request(rstate);
1548 return;
1549 }
1550
1551 // extract the data from the message
1552 ptr = rstate->msgdata;
1553 if (!ptr)
1554 {
1555 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1556 abort_request(rstate);
1557 unlink_request(rstate);
1558 return;
1559 }
1560 flags = get_flags(&ptr);
1561 interfaceIndex = get_long(&ptr);
1562 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1563 if (interfaceIndex && !InterfaceID)
1564 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
1565 if (get_string(&ptr, name, 256) < 0 ||
1566 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1567 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1568 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
1569
1570 // free memory in rstate since we don't need it anymore
1571 freeL("handle_resolve_request", rstate->msgbuf);
1572 rstate->msgbuf = NULL;
1573
1574 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1575 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
1576
1577 // set up termination info
1578 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
1579 bzero(term, sizeof(*term));
1580 if (!term) FatalError("ERROR: malloc");
1581
1582 // format questions
1583 term->qsrv.InterfaceID = InterfaceID;
1584 term->qsrv.Target = zeroAddr;
1585 memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
1586 term->qsrv.qtype = kDNSType_SRV;
1587 term->qsrv.qclass = kDNSClass_IN;
1588 term->qsrv.LongLived = mDNSfalse;
1589 term->qsrv.ExpectUnique = mDNStrue;
1590 term->qsrv.ForceMCast = mDNSfalse;
1591 term->qsrv.QuestionCallback = resolve_result_callback;
1592 term->qsrv.QuestionContext = rstate;
1593
1594 term->qtxt.InterfaceID = InterfaceID;
1595 term->qtxt.Target = zeroAddr;
1596 memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
1597 term->qtxt.qtype = kDNSType_TXT;
1598 term->qtxt.qclass = kDNSClass_IN;
1599 term->qtxt.LongLived = mDNSfalse;
1600 term->qtxt.ExpectUnique = mDNStrue;
1601 term->qtxt.ForceMCast = mDNSfalse;
1602 term->qtxt.QuestionCallback = resolve_result_callback;
1603 term->qtxt.QuestionContext = rstate;
1604
1605 term->rstate = rstate;
1606 rstate->termination_context = term;
1607 rstate->terminate = resolve_termination_callback;
1608
1609 // ask the questions
1610 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
1611 err = mDNS_StartQuery(gmDNS, &term->qsrv);
1612 if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
1613
1614 if (err)
1615 {
1616 freeL("handle_resolve_request", term);
1617 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
1618 }
1619 if (deliver_error(rstate, err) < 0 || err)
1620 {
1621 abort_request(rstate);
1622 unlink_request(rstate);
1623 }
1624 return;
1625
1626 bad_param:
1627 deliver_error(rstate, mStatus_BadParamErr);
1628 abort_request(rstate);
1629 unlink_request(rstate);
1630 }
1631
1632 mDNSlocal void resolve_termination_callback(void *context)
1633 {
1634 resolve_termination_t *term = context;
1635 request_state *rs;
1636
1637 if (!term)
1638 {
1639 LogMsg("ERROR: resolve_termination_callback: double termination");
1640 return;
1641 }
1642 rs = term->rstate;
1643 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
1644
1645 mDNS_StopQuery(gmDNS, &term->qtxt);
1646 mDNS_StopQuery(gmDNS, &term->qsrv);
1647
1648 freeL("resolve_termination_callback", term);
1649 rs->termination_context = NULL;
1650 }
1651
1652 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1653 {
1654 size_t len = 0;
1655 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1656 char *data;
1657 transfer_state result;
1658 reply_state *rep;
1659 request_state *rs = question->QuestionContext;
1660 resolve_termination_t *res = rs->termination_context;
1661 (void)m; // Unused
1662
1663 LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
1664 rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
1665
1666 // This code used to do this trick of just keeping a copy of the pointer to
1667 // the answer record in the cache, but the unicast query code doesn't currently
1668 // put its answer records in the cache, so for now we can't do this.
1669
1670 if (!AddRecord)
1671 {
1672 // After unicast query code is updated to store its records in the common cache, use this...
1673 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1674 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1675 // intead of this...
1676 if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
1677 res->srv = mDNSfalse;
1678 if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
1679 res->txt = mDNSfalse;
1680 return;
1681 }
1682
1683 // After unicast query code is updated to store its records in the common cache, use this...
1684 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1685 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1686 // intead of this...
1687 if (answer->rrtype == kDNSType_SRV)
1688 {
1689 res->srvdata = answer->rdata->u.srv;
1690 res->srv = mDNStrue;
1691 }
1692 if (answer->rrtype == kDNSType_TXT)
1693 {
1694 if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
1695 res->txtlen = answer->rdlength;
1696 mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
1697 res->txt = mDNStrue;
1698 }
1699
1700 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1701
1702 ConvertDomainNameToCString(answer->name, fullname);
1703 ConvertDomainNameToCString(&res->srvdata.target, target);
1704
1705 // calculate reply length
1706 len += sizeof(DNSServiceFlags);
1707 len += sizeof(uint32_t); // interface index
1708 len += sizeof(DNSServiceErrorType);
1709 len += strlen(fullname) + 1;
1710 len += strlen(target) + 1;
1711 len += 2 * sizeof(uint16_t); // port, txtLen
1712 len += res->txtlen;
1713
1714 // allocate/init reply header
1715 rep = create_reply(resolve_reply_op, len, rs);
1716 rep->rhdr->flags = dnssd_htonl(0);
1717 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1718 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1719
1720 data = rep->sdata;
1721
1722 // write reply data to message
1723 put_string(fullname, &data);
1724 put_string(target, &data);
1725 *data++ = res->srvdata.port.b[0];
1726 *data++ = res->srvdata.port.b[1];
1727 put_short(res->txtlen, &data);
1728 put_rdata(res->txtlen, res->txtdata, &data);
1729
1730 result = send_msg(rep);
1731 if (result == t_error || result == t_terminated)
1732 {
1733 abort_request(rs);
1734 unlink_request(rs);
1735 freeL("resolve_result_callback", rep);
1736 }
1737 else if (result == t_complete) freeL("resolve_result_callback", rep);
1738 else append_reply(rs, rep);
1739 }
1740
1741 // what gets called when a resolve is completed and we need to send the data back to the client
1742 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1743 {
1744 char *data;
1745 char name[MAX_ESCAPED_DOMAIN_NAME];
1746 request_state *req = question->QuestionContext;
1747 reply_state *rep;
1748 size_t len;
1749 (void)m; // Unused
1750
1751 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1752 //mDNS_StopQuery(m, question);
1753
1754 if (answer->rdlength == 0)
1755 {
1756 deliver_async_error(req, query_reply_op, kDNSServiceErr_NoSuchRecord);
1757 return;
1758 }
1759
1760 // calculate reply data length
1761 len = sizeof(DNSServiceFlags);
1762 len += 2 * sizeof(uint32_t); // if index + ttl
1763 len += sizeof(DNSServiceErrorType);
1764 len += 3 * sizeof(uint16_t); // type, class, rdlen
1765 len += answer->rdlength;
1766 ConvertDomainNameToCString(answer->name, name);
1767 len += strlen(name) + 1;
1768
1769 rep = create_reply(query_reply_op, len, req);
1770
1771 rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
1772 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1773 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1774
1775 data = rep->sdata;
1776
1777 put_string(name, &data);
1778 put_short(answer->rrtype, &data);
1779 put_short(answer->rrclass, &data);
1780 put_short(answer->rdlength, &data);
1781 put_rdata(answer->rdlength, answer->rdata->u.data, &data);
1782 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1783
1784 append_reply(req, rep);
1785 return;
1786 }
1787
1788 mDNSlocal void question_termination_callback(void *context)
1789 {
1790 DNSQuestion *q = context;
1791 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
1792 mDNS_StopQuery(gmDNS, q); // no need to error check
1793 freeL("question_termination_callback", q);
1794 }
1795
1796 // If there's a comma followed by another character,
1797 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1798 // Otherwise, it returns a pointer to the final nul at the end of the string
1799 mDNSlocal char *FindFirstSubType(char *p)
1800 {
1801 while (*p)
1802 {
1803 if (p[0] == '\\' && p[1]) p += 2;
1804 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1805 else p++;
1806 }
1807 return(p);
1808 }
1809
1810 // If there's a comma followed by another character,
1811 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1812 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1813 // Otherwise, it returns a pointer to the final nul at the end of the string
1814 mDNSlocal char *FindNextSubType(char *p)
1815 {
1816 while (*p)
1817 {
1818 if (p[0] == '\\' && p[1]) // If escape character
1819 p += 2; // ignore following character
1820 else if (p[0] == ',') // If we found a comma
1821 {
1822 if (p[1]) *p++ = 0;
1823 return(p);
1824 }
1825 else if (p[0] == '.')
1826 return(mDNSNULL);
1827 else p++;
1828 }
1829 return(p);
1830 }
1831
1832 // Returns -1 if illegal subtype found
1833 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1834 {
1835 mDNSs32 NumSubTypes = 0;
1836 char *stp = FindFirstSubType(regtype);
1837 while (stp && *stp) // If we found a comma...
1838 {
1839 if (*stp == ',') return(-1);
1840 NumSubTypes++;
1841 stp = FindNextSubType(stp);
1842 }
1843 if (!stp) return(-1);
1844 return(NumSubTypes);
1845 }
1846
1847 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1848 {
1849 AuthRecord *st = mDNSNULL;
1850 if (NumSubTypes)
1851 {
1852 mDNSs32 i;
1853 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1854 if (!st) return(mDNSNULL);
1855 for (i = 0; i < NumSubTypes; i++)
1856 {
1857 mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1858 while (*p) p++;
1859 p++;
1860 if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
1861 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1862 }
1863 }
1864 return(st);
1865 }
1866
1867 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1868 mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
1869 {
1870 (void)m; // unused
1871 if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
1872 }
1873 #endif
1874
1875 mDNSlocal void handle_setdomain_request(request_state *request)
1876 {
1877 mStatus err = mStatus_NoError;
1878 char *ptr;
1879 char domainstr[MAX_ESCAPED_DOMAIN_NAME];
1880 domainname domain;
1881 DNSServiceFlags flags;
1882 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1883 struct xucred xuc;
1884 socklen_t xuclen;
1885 #endif
1886
1887 if (request->ts != t_complete)
1888 {
1889 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1890 abort_request(request);
1891 unlink_request(request);
1892 return;
1893 }
1894
1895 // extract flags/domain from message
1896 ptr = request->msgdata;
1897 flags = get_flags(&ptr);
1898 if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1899 !MakeDomainNameFromDNSNameString(&domain, domainstr))
1900 { err = mStatus_BadParamErr; goto end; }
1901
1902 freeL("handle_setdomain_request", request->msgbuf);
1903 request->msgbuf = NULL;
1904
1905 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
1906
1907 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1908 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1909 // the existence of this socket option
1910 xuclen = sizeof(xuc);
1911 if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
1912 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
1913 if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
1914 LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
1915
1916 if (flags & kDNSServiceFlagsAdd)
1917 {
1918 // register a local-only PRT record
1919 default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
1920 if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
1921 mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
1922 MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
1923 AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
1924 AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
1925 newelem->uid = xuc.cr_uid;
1926 err = mDNS_Register(gmDNS, &newelem->ptr_rec);
1927 if (err) free(newelem);
1928 else
1929 {
1930 // link into list
1931 newelem->next = default_browse_list;
1932 default_browse_list = newelem;
1933 }
1934
1935 }
1936 else
1937 {
1938 // remove - find in list, deregister
1939 default_browse_list_t *ptr = default_browse_list, *prev = NULL;
1940 while (ptr)
1941 {
1942 if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
1943 {
1944 if (prev) prev->next = ptr->next;
1945 else default_browse_list = ptr->next;
1946 err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
1947 break;
1948 }
1949 prev = ptr;
1950 ptr = ptr->next;
1951 }
1952 if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
1953 }
1954 #else
1955 err = mStatus_NoError;
1956 #endif // _HAVE_SETDOMAIN_SUPPORT_
1957
1958 end:
1959 deliver_error(request, err);
1960 abort_request(request);
1961 unlink_request(request);
1962 }
1963
1964 // Generates a response message giving name, type, domain, plus interface index,
1965 // suitable for a browse result or service registration result.
1966 // On successful completion rep is set to point to a malloc'd reply_state struct
1967 mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1968 {
1969 domainlabel name;
1970 domainname type, dom;
1971 *rep = NULL;
1972 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1973 return kDNSServiceErr_Invalid;
1974 else
1975 {
1976 char namestr[MAX_DOMAIN_LABEL+1];
1977 char typestr[MAX_ESCAPED_DOMAIN_NAME];
1978 char domstr [MAX_ESCAPED_DOMAIN_NAME];
1979 int len;
1980 char *data;
1981
1982 ConvertDomainLabelToCString_unescaped(&name, namestr);
1983 ConvertDomainNameToCString(&type, typestr);
1984 ConvertDomainNameToCString(&dom, domstr);
1985
1986 // Calculate reply data length
1987 len = sizeof(DNSServiceFlags);
1988 len += sizeof(uint32_t); // if index
1989 len += sizeof(DNSServiceErrorType);
1990 len += (int) (strlen(namestr) + 1);
1991 len += (int) (strlen(typestr) + 1);
1992 len += (int) (strlen(domstr) + 1);
1993
1994 // Build reply header
1995 *rep = create_reply(query_reply_op, len, request);
1996 (*rep)->rhdr->flags = dnssd_htonl(0);
1997 (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
1998 (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1999
2000 // Build reply body
2001 data = (*rep)->sdata;
2002 put_string(namestr, &data);
2003 put_string(typestr, &data);
2004 put_string(domstr, &data);
2005
2006 return mStatus_NoError;
2007 }
2008 }
2009
2010 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2011 {
2012 request_state *req = question->QuestionContext;
2013 reply_state *rep;
2014 (void)m; // Unused
2015
2016 if (answer->rrtype != kDNSType_PTR)
2017 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
2018
2019 if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
2020 {
2021 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2022 req->sd, answer->name->c, answer->rdata->u.name.c);
2023 return;
2024 }
2025
2026 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
2027 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2028
2029 if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
2030 append_reply(req, rep);
2031 }
2032
2033 mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
2034 {
2035 browser_t *b, *p;
2036 mStatus err;
2037
2038 for (p = info->browsers; p; p = p->next)
2039 {
2040 if (SameDomainName(&p->domain, d))
2041 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
2042 }
2043
2044 b = mallocL("browser_t", sizeof(*b));
2045 if (!b) return mStatus_NoMemoryErr;
2046 AssignDomainName(&b->domain, d);
2047 err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
2048 if (err)
2049 {
2050 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
2051 freeL("browser_t", b);
2052 }
2053 else
2054 {
2055 b->next = info->browsers;
2056 info->browsers = b;
2057 }
2058 return err;
2059 }
2060
2061 mDNSlocal void handle_browse_request(request_state *request)
2062 {
2063 DNSServiceFlags flags;
2064 uint32_t interfaceIndex;
2065 mDNSInterfaceID InterfaceID;
2066 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
2067 domainname typedn, d, temp;
2068 mDNSs32 NumSubTypes;
2069 char *ptr;
2070 mStatus err = mStatus_NoError;
2071 DNameListElem *search_domain_list, *sdom;
2072 browser_info_t *info = NULL;
2073
2074 if (request->ts != t_complete)
2075 {
2076 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
2077 abort_request(request);
2078 unlink_request(request);
2079 return;
2080 }
2081
2082 // extract data from message
2083 ptr = request->msgdata;
2084 flags = get_flags(&ptr);
2085 interfaceIndex = get_long(&ptr);
2086 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2087 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
2088 { err = mStatus_BadParamErr; goto error; }
2089 freeL("handle_browse_request", request->msgbuf);
2090 request->msgbuf = NULL;
2091
2092 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
2093 if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
2094
2095 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
2096 if ( !domain || ( domain[0] == '\0' ) )
2097 {
2098 dDNS_RegisterSearchDomains( gmDNS );
2099 }
2100 #endif
2101
2102 typedn.c[0] = 0;
2103 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
2104 if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
2105 if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
2106 { err = mStatus_BadParamErr; goto error; }
2107
2108 if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
2109
2110 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
2111 if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
2112
2113 // allocate and set up browser info
2114 info = mallocL("browser_info_t", sizeof(*info));
2115 if (!info) { err = mStatus_NoMemoryErr; goto error; }
2116
2117 request->browser_info = info;
2118 info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
2119 info->interface_id = InterfaceID;
2120 AssignDomainName(&info->regtype, &typedn);
2121 info->rstate = request;
2122 info->default_domain = !domain[0];
2123 info->browsers = NULL;
2124
2125 // setup termination context
2126 request->termination_context = info;
2127 request->terminate = browse_termination_callback;
2128
2129 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
2130 if (domain[0])
2131 {
2132 if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
2133 err = add_domain_to_browser(info, &d);
2134 }
2135
2136 else
2137 {
2138 search_domain_list = mDNSPlatformGetSearchDomainList();
2139 for (sdom = search_domain_list; sdom; sdom = sdom->next)
2140 {
2141 err = add_domain_to_browser(info, &sdom->name);
2142 if (err)
2143 {
2144 if (SameDomainName(&sdom->name, &localdomain)) break;
2145 else err = mStatus_NoError; // suppress errors for non-local "default" domains
2146 }
2147
2148 }
2149 mDNS_FreeDNameList(search_domain_list);
2150 }
2151
2152 deliver_error(request, err);
2153 return;
2154
2155 error:
2156 if (info) freeL("browser_info_t", info);
2157 if (request->termination_context) request->termination_context = NULL;
2158 deliver_error(request, err);
2159 abort_request(request);
2160 unlink_request(request);
2161 }
2162
2163 mDNSlocal void browse_termination_callback(void *context)
2164 {
2165 browser_info_t *info = context;
2166 browser_t *ptr;
2167
2168 if (!info) return;
2169
2170 while(info->browsers)
2171 {
2172 ptr = info->browsers;
2173 info->browsers = ptr->next;
2174 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
2175 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
2176 freeL("browse_termination_callback", ptr);
2177 }
2178
2179 info->rstate->termination_context = NULL;
2180 freeL("browser_info", info);
2181 }
2182
2183 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
2184 {
2185 request_state *r;
2186
2187 for (r = all_requests; r; r = r->next)
2188 {
2189 browser_info_t *info = r->browser_info;
2190
2191 if (!info || !info->default_domain) continue;
2192 if (add) add_domain_to_browser(info, d);
2193 else
2194 {
2195 browser_t **ptr = &info->browsers;
2196 while (*ptr)
2197 {
2198 if (SameDomainName(&(*ptr)->domain, d))
2199 {
2200 browser_t *remove = *ptr;
2201 *ptr = (*ptr)->next;
2202 if (remove->q.LongLived)
2203 {
2204 // Give goodbyes for known answers.
2205 // Note that this a special case where we know that the QuestionCallback function is our own
2206 // code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
2207 // don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
2208 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
2209 while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
2210 }
2211 mDNS_StopBrowse(gmDNS, &remove->q);
2212 freeL("browser_t", remove);
2213 return;
2214 }
2215 ptr = &(*ptr)->next;
2216 }
2217 LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
2218 }
2219 }
2220 }
2221
2222 // Count how many other service records we have locally with the same name, but different rdata.
2223 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2224 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
2225 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
2226 {
2227 int count = 0;
2228 ResourceRecord *r = &srs->RR_SRV.resrec;
2229 AuthRecord *rr;
2230 ServiceRecordSet *s;
2231
2232 for (rr = m->ResourceRecords; rr; rr=rr->next)
2233 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2234 count++;
2235
2236 for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
2237 if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2238 count++;
2239
2240 for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
2241 if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
2242 count++;
2243
2244 verbosedebugf("%d peer registrations for %##s", count, r->name->c);
2245 return(count);
2246 }
2247
2248 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
2249 {
2250 int count = 0;
2251 AuthRecord *rr;
2252 for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
2253 if (rr->resrec.rrtype == kDNSType_SRV &&
2254 rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
2255 SameDomainName(rr->resrec.name, srv))
2256 count++;
2257 return(count);
2258 }
2259
2260 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
2261 {
2262 service_info *info = request->service_registration;
2263 service_instance *ptr, *instance;
2264 int instance_size;
2265 mStatus result;
2266
2267 for (ptr = info->instances; ptr; ptr = ptr->next)
2268 {
2269 if (SameDomainName(&ptr->domain, domain))
2270 { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
2271 }
2272
2273 instance_size = sizeof(*instance);
2274 if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
2275 instance = mallocL("service_instance", instance_size);
2276 if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
2277
2278 instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
2279 if (info->num_subtypes && !instance->subtypes)
2280 { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
2281 instance->request = request;
2282 instance->sd = request->sd;
2283 instance->autoname = info->autoname;
2284 instance->autorename = info->autorename;
2285 instance->allowremotequery = info->allowremotequery;
2286 instance->rename_on_memfree = 0;
2287 instance->name = info->name;
2288 AssignDomainName(&instance->domain, domain);
2289 instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
2290 result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
2291 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
2292
2293 if (result) free_service_instance(instance);
2294 else
2295 {
2296 instance->next = info->instances;
2297 info->instances = instance;
2298 }
2299 return result;
2300 }
2301
2302 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
2303 {
2304 request_state *rstate;
2305 service_info *info;
2306
2307 LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
2308 for (rstate = all_requests; rstate; rstate = rstate->next)
2309 {
2310 if (rstate->terminate != regservice_termination_callback) continue;
2311 info = rstate->service_registration;
2312 if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2313 if (!info->default_domain) continue;
2314
2315 // valid default registration
2316 if (add) register_service_instance(rstate, d);
2317 else
2318 {
2319 // find the instance to remove
2320 service_instance *si = rstate->service_registration->instances, *prev = NULL;
2321 while (si)
2322 {
2323 if (SameDomainName(&si->domain, d))
2324 {
2325 mStatus err;
2326 if (prev) prev->next = si->next;
2327 else info->instances = si->next;
2328 err = mDNS_DeregisterService(gmDNS, &si->srs);
2329 if (err)
2330 {
2331 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
2332 free_service_instance(si);
2333 }
2334 break;
2335 }
2336 prev = si;
2337 si = si->next;
2338 }
2339 if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
2340 }
2341 }
2342 }
2343
2344 // service registration
2345 mDNSlocal void handle_regservice_request(request_state *request)
2346 {
2347 DNSServiceFlags flags;
2348 uint32_t ifi;
2349 char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2350 char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2351 char *ptr;
2352 domainname d, srv;
2353 mStatus result;
2354 service_info *service = NULL;
2355
2356 if (request->ts != t_complete)
2357 {
2358 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2359 abort_request(request);
2360 unlink_request(request);
2361 return;
2362 }
2363
2364 service = mallocL("service_info", sizeof(*service));
2365 if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2366
2367 service->instances = NULL;
2368 service->request = request;
2369 service->txtlen = 0;
2370 service->txtdata = NULL;
2371 request->service_registration = service;
2372 request->termination_context = request->service_registration;
2373 request->terminate = regservice_termination_callback;
2374
2375 // extract data from message
2376 ptr = request->msgdata;
2377 flags = get_flags(&ptr);
2378 ifi = get_long(&ptr);
2379 service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2380 if (ifi && !service->InterfaceID)
2381 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
2382 if (get_string(&ptr, name, sizeof(name)) < 0 ||
2383 get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2384 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2385 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
2386 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
2387
2388 service->port.b[0] = *ptr++;
2389 service->port.b[1] = *ptr++;
2390
2391 service->txtlen = get_short(&ptr);
2392 if (service->txtlen)
2393 {
2394 service->txtdata = mallocL("txtdata", service->txtlen);
2395 if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2396 memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
2397 }
2398 else service->txtdata = NULL;
2399
2400 // Check for sub-types after the service type
2401 service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
2402 if (service->num_subtypes < 0)
2403 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
2404
2405 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2406 if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
2407 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
2408
2409 if (!name[0])
2410 {
2411 service->name = (gmDNS)->nicelabel;
2412 service->autoname = mDNStrue;
2413 }
2414 else
2415 {
2416 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2417 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2418 {
2419 int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2420 name[newlen] = 0;
2421 }
2422 if (!MakeDomainLabelFromLiteralString(&service->name, name))
2423 { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2424 service->autoname = mDNSfalse;
2425 }
2426
2427 if (*domain)
2428 {
2429 service->default_domain = mDNSfalse;
2430 if (!MakeDomainNameFromDNSNameString(&d, domain))
2431 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2432 }
2433 else
2434 {
2435 service->default_domain = mDNStrue;
2436 MakeDomainNameFromDNSNameString(&d, "local.");
2437 }
2438
2439 if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
2440 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
2441
2442 if (!MakeDomainNameFromDNSNameString(&service->host, host))
2443 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2444 service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
2445 service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2446
2447 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2448 // a port number of zero. When two instances of the protected client are allowed to run on one
2449 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2450 if (service->port.NotAnInteger)
2451 {
2452 int count = CountExistingRegistrations(&srv, service->port);
2453 if (count)
2454 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2455 count+1, srv.c, mDNSVal16(service->port));
2456 }
2457
2458 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2459 request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
2460 result = register_service_instance(request, &d);
2461
2462 if (!result && !*domain)
2463 {
2464 DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
2465 for (ptr = def_domains; ptr; ptr = ptr->next)
2466 register_service_instance(request, &ptr->name);
2467 // note that we don't report errors for non-local, non-explicit domains
2468 mDNS_FreeDNameList(def_domains);
2469 }
2470
2471 finish:
2472 deliver_error(request, result);
2473 if (result != mStatus_NoError)
2474 {
2475 abort_request(request);
2476 unlink_request(request);
2477 }
2478 else
2479 reset_connected_rstate(request); // prepare to receive add/remove messages
2480
2481 return;
2482
2483 bad_param:
2484 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2485 deliver_error(request, mStatus_BadParamErr);
2486 abort_request(request);
2487 unlink_request(request);
2488 }
2489
2490 // service registration callback performs three duties - frees memory for deregistered services,
2491 // handles name conflicts, and delivers completed registration information to the client (via
2492 // process_service_registraion())
2493
2494 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
2495 {
2496 mStatus err;
2497 mDNSBool SuppressError = mDNSfalse;
2498 service_instance *instance = srs->ServiceContext;
2499 (void)m; // Unused
2500 if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
2501 if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
2502
2503 if (instance->request && instance->request->service_registration)
2504 {
2505 service_info *info = instance->request->service_registration;
2506 if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
2507 // don't send errors up to client for wide-area, empty-string registrations
2508 }
2509
2510 if (result == mStatus_NoError)
2511 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2512 else if (result == mStatus_MemFree)
2513 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2514 else if (result == mStatus_NameConflict)
2515 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2516 else
2517 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);
2518
2519 if (result == mStatus_NoError)
2520 {
2521 request_state *req = instance->request;
2522 if (instance->allowremotequery)
2523 {
2524 ExtraResourceRecord *e;
2525 srs->RR_ADV.AllowRemoteQuery = mDNStrue;
2526 srs->RR_PTR.AllowRemoteQuery = mDNStrue;
2527 srs->RR_SRV.AllowRemoteQuery = mDNStrue;
2528 srs->RR_TXT.AllowRemoteQuery = mDNStrue;
2529 for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
2530 }
2531
2532 if (!req) LogMsg("ERROR: regservice_callback - null request object");
2533 else
2534 {
2535 reply_state *rep;
2536 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
2537 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
2538 else
2539 {
2540 transfer_state send_result = send_msg(rep);
2541 if (send_result == t_error || send_result == t_terminated)
2542 { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
2543 else if (send_result == t_complete) freeL("regservice_callback", rep);
2544 else append_reply(req, rep);
2545 }
2546 }
2547 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2548 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
2549 return;
2550 }
2551 else if (result == mStatus_MemFree)
2552 {
2553 if (instance->rename_on_memfree)
2554 {
2555 instance->rename_on_memfree = 0;
2556 instance->name = gmDNS->nicelabel;
2557 err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
2558 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
2559 // error should never happen - safest to log and continue
2560 }
2561 else
2562 {
2563 free_service_instance(instance);
2564 return;
2565 }
2566 }
2567 else if (result == mStatus_NameConflict)
2568 {
2569 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2570 {
2571 // On conflict for an autoname service, rename and reregister *all* autoname services
2572 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
2573 m->MainCallback(m, mStatus_ConfigChanged);
2574 }
2575 else if (instance->autoname || instance->autorename)
2576 {
2577 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
2578 return;
2579 }
2580 else
2581 {
2582 request_state *rs = instance->request;
2583 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2584 free_service_instance(instance);
2585 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2586 {
2587 abort_request(rs);
2588 unlink_request(rs);
2589 }
2590 return;
2591 }
2592 }
2593 else
2594 {
2595 request_state *rs = instance->request;
2596 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2597 if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
2598 free_service_instance(instance);
2599 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2600 {
2601 abort_request(rs);
2602 unlink_request(rs);
2603 }
2604 return;
2605 }
2606 }
2607
2608 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
2609 {
2610 ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
2611 (void)m; //unused
2612
2613 if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
2614
2615 debugf("%##s: MemFree", rr->resrec.name->c);
2616 if (rr->resrec.rdata != &rr->rdatastorage)
2617 freeL("Extra RData", rr->resrec.rdata);
2618 freeL("ExtraResourceRecord", extra);
2619 }
2620
2621 mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
2622 {
2623 ServiceRecordSet *srs = &instance->srs;
2624 ExtraResourceRecord *extra;
2625 mStatus result;
2626 int size;
2627
2628 if (rdlen > sizeof(RDataBody)) size = rdlen;
2629 else size = sizeof(RDataBody);
2630
2631 extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
2632 if (!extra)
2633 {
2634 my_perror("ERROR: malloc");
2635 return mStatus_NoMemoryErr;
2636 }
2637
2638 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
2639 extra->r.resrec.rrtype = rrtype;
2640 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
2641 extra->r.resrec.rdlength = rdlen;
2642 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
2643
2644 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
2645 if (result) { freeL("ExtraResourceRecord", extra); return result; }
2646
2647 extra->ClientID = rstate->hdr.reg_index;
2648 return result;
2649 }
2650
2651 mDNSlocal mStatus handle_add_request(request_state *rstate)
2652 {
2653 uint32_t ttl;
2654 uint16_t rrtype, rdlen;
2655 char *ptr, *rdata;
2656 mStatus result = mStatus_UnknownErr;
2657 DNSServiceFlags flags;
2658 service_info *srvinfo = rstate->service_registration;
2659 service_instance *i;
2660
2661 if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2662
2663 ptr = rstate->msgdata;
2664 flags = get_flags(&ptr);
2665 rrtype = get_short(&ptr);
2666 rdlen = get_short(&ptr);
2667 rdata = get_rdata(&ptr, rdlen);
2668 ttl = get_long(&ptr);
2669
2670 if (!ttl) ttl = DefaultTTLforRRType(rrtype);
2671
2672 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
2673 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
2674
2675 for (i = srvinfo->instances; i; i = i->next)
2676 {
2677 result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
2678 if (result && i->default_local) break;
2679 else result = mStatus_NoError; // suppress non-local default errors
2680 }
2681
2682 return(result);
2683 }
2684
2685 mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
2686 {
2687 int rdsize;
2688 RData *newrd;
2689 mStatus result;
2690
2691 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
2692 else rdsize = sizeof(RDataBody);
2693 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
2694 if (!newrd) FatalError("ERROR: malloc");
2695 newrd->MaxRDLength = (mDNSu16) rdsize;
2696 memcpy(&newrd->u, rdata, rdlen);
2697
2698 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2699 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2700 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2701 if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
2702
2703 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
2704 if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
2705 return result;
2706 }
2707
2708 mDNSlocal mStatus handle_update_request(request_state *rstate)
2709 {
2710 uint16_t rdlen;
2711 char *ptr, *rdata;
2712 uint32_t ttl;
2713 mStatus result = mStatus_BadReferenceErr;
2714 service_info *srvinfo = rstate->service_registration;
2715 service_instance *i;
2716 AuthRecord *rr = NULL;
2717
2718 // get the message data
2719 ptr = rstate->msgdata;
2720 get_flags(&ptr); // flags unused
2721 rdlen = get_short(&ptr);
2722 rdata = get_rdata(&ptr, rdlen);
2723 ttl = get_long(&ptr);
2724
2725 if (rstate->reg_recs)
2726 {
2727 // update an individually registered record
2728 registered_record_entry *reptr;
2729 for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
2730 {
2731 if (reptr->key == rstate->hdr.reg_index)
2732 {
2733 result = update_record(reptr->rr, rdlen, rdata, ttl);
2734 goto end;
2735 }
2736 }
2737 result = mStatus_BadReferenceErr;
2738 goto end;
2739 }
2740
2741 // update a record from a service record set
2742 if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
2743 for (i = srvinfo->instances; i; i = i->next)
2744 {
2745 if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
2746 else
2747 {
2748 ExtraResourceRecord *e;
2749 for (e = i->srs.Extras; e; e = e->next)
2750 if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
2751 }
2752
2753 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
2754 result = update_record(rr, rdlen, rdata, ttl);
2755 if (result && i->default_local) goto end;
2756 else result = mStatus_NoError; // suppress non-local default errors
2757 }
2758
2759 end:
2760 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
2761 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
2762 rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
2763
2764 return(result);
2765 }
2766
2767 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
2768 {
2769 (void)m; // Unused
2770 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
2771 }
2772
2773 mDNSlocal void free_service_instance(service_instance *srv)
2774 {
2775 request_state *rstate = srv->request;
2776 ExtraResourceRecord *e = srv->srs.Extras, *tmp;
2777
2778 // clear pointers from parent struct
2779 if (rstate)
2780 {
2781 service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
2782 while (ptr)
2783 {
2784 if (ptr == srv)
2785 {
2786 if (prev) prev->next = ptr->next;
2787 else rstate->service_registration->instances = ptr->next;
2788 break;
2789 }
2790 prev = ptr;
2791 ptr = ptr->next;
2792 }
2793 }
2794
2795 while(e)
2796 {
2797 e->r.RecordContext = e;
2798 tmp = e;
2799 e = e->next;
2800 FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
2801 }
2802
2803 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
2804 freeL("regservice_callback", srv);
2805 }
2806
2807 mDNSlocal void regservice_termination_callback(void *context)
2808 {
2809 service_info *info = context;
2810 service_instance *i, *p;
2811 if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
2812 if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2813 i = info->instances;
2814 while (i)
2815 {
2816 p = i;
2817 i = i->next;
2818 p->request = NULL; // clear back pointer
2819 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2820 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));
2821 if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
2822 }
2823 info->request->service_registration = NULL; // clear pointer from request back to info
2824 if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
2825 freeL("service_info", info);
2826 }
2827
2828 mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
2829 {
2830 AuthRecord *rr;
2831 registered_record_entry *re;
2832 mStatus result;
2833
2834 if (rstate->ts != t_complete)
2835 {
2836 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2837 abort_request(rstate);
2838 unlink_request(rstate);
2839 return(-1);
2840 }
2841
2842 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
2843 if (!rr) return(mStatus_BadParamErr);
2844
2845 // allocate registration entry, link into list
2846 re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
2847 if (!re) FatalError("ERROR: malloc");
2848 re->key = rstate->hdr.reg_index;
2849 re->rr = rr;
2850 re->rstate = rstate;
2851 re->client_context = rstate->hdr.client_context;
2852 rr->RecordContext = re;
2853 rr->RecordCallback = regrecord_callback;
2854 re->next = rstate->reg_recs;
2855 rstate->reg_recs = re;
2856
2857 if (!rstate->terminate)
2858 {
2859 rstate->terminate = connected_registration_termination;
2860 rstate->termination_context = rstate;
2861 }
2862
2863 if (rr->resrec.rroriginalttl == 0)
2864 rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
2865
2866 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
2867 result = mDNS_Register(gmDNS, rr);
2868 return(result);
2869 }
2870
2871 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
2872 {
2873 registered_record_entry *re = rr->RecordContext;
2874 request_state *rstate = re ? re->rstate : NULL;
2875 int len;
2876 reply_state *reply;
2877 transfer_state ts;
2878 (void)m; // Unused
2879
2880 if (!re)
2881 {
2882 // parent struct alreadt freed by termination callback
2883 if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2884 else
2885 {
2886 if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
2887 freeL("regrecord_callback", rr);
2888 }
2889 return;
2890 }
2891
2892 // format result, add to the list for the request, including the client context in the header
2893 len = sizeof(DNSServiceFlags);
2894 len += sizeof(uint32_t); //interfaceIndex
2895 len += sizeof(DNSServiceErrorType);
2896
2897 reply = create_reply(reg_record_reply_op, len, rstate);
2898 reply->mhdr->client_context = re->client_context;
2899 reply->rhdr->flags = dnssd_htonl(0);
2900 reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
2901 reply->rhdr->error = dnssd_htonl(result);
2902
2903 if (result)
2904 {
2905 // unlink from list, free memory
2906 registered_record_entry **ptr = &re->rstate->reg_recs;
2907 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
2908 if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
2909 *ptr = (*ptr)->next;
2910 freeL("regrecord_callback", re->rr);
2911 re->rr = rr = NULL;
2912 freeL("regrecord_callback", re);
2913 re = NULL;
2914 }
2915
2916 ts = send_msg(reply);
2917
2918 if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
2919 else if (ts == t_complete) freeL("regrecord_callback", reply);
2920 else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
2921 }
2922
2923 mDNSlocal void connected_registration_termination(void *context)
2924 {
2925 int shared;
2926 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
2927 while(ptr)
2928 {
2929 fptr = ptr;
2930 ptr = ptr->next;
2931 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
2932 fptr->rr->RecordContext = NULL;
2933 mDNS_Deregister(gmDNS, fptr->rr);
2934 freeL("connected_registration_termination", fptr);
2935 }
2936 }
2937
2938 mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
2939 {
2940 mStatus err = mStatus_BadReferenceErr;
2941 char *ptr;
2942 service_info *srvinfo = rstate->service_registration;
2943
2944 ptr = rstate->msgdata;
2945 get_flags(&ptr); // flags unused
2946
2947 if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
2948 else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
2949 else
2950 {
2951 service_instance *i;
2952 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
2953 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
2954 for (i = srvinfo->instances; i; i = i->next)
2955 {
2956 err = remove_extra(rstate, i);
2957 if (err && i->default_local) break;
2958 else err = mStatus_NoError; // suppress non-local default errors
2959 }
2960 }
2961
2962 return(err);
2963 }
2964
2965 // remove a resource record registered via DNSServiceRegisterRecord()
2966 mDNSlocal mStatus remove_record(request_state *rstate)
2967 {
2968 int shared;
2969 mStatus err = mStatus_UnknownErr;
2970 registered_record_entry *e, **ptr = &rstate->reg_recs;
2971
2972 while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
2973 if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
2974 e = *ptr;
2975 *ptr = e->next; // unlink
2976
2977 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
2978 shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
2979 e->rr->RecordContext = NULL;
2980 err = mDNS_Deregister(gmDNS, e->rr);
2981 if (err)
2982 {
2983 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
2984 freeL("remove_record", e->rr);
2985 freeL("remove_record", e);
2986 }
2987 return err;
2988 }
2989
2990 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
2991 {
2992 mStatus err = mStatus_BadReferenceErr;
2993 ExtraResourceRecord *ptr;
2994
2995 for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
2996 {
2997 if (ptr->ClientID == rstate->hdr.reg_index) // found match
2998 return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
2999 }
3000 return err;
3001 }
3002
3003 // domain enumeration
3004 mDNSlocal void handle_enum_request(request_state *rstate)
3005 {
3006 DNSServiceFlags flags;
3007 uint32_t ifi;
3008 mDNSInterfaceID InterfaceID;
3009 char *ptr = rstate->msgdata;
3010 domain_enum_t *def, *all;
3011 enum_termination_t *term;
3012 mStatus err;
3013 int result;
3014
3015 if (rstate->ts != t_complete)
3016 {
3017 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
3018 abort_request(rstate);
3019 unlink_request(rstate);
3020 return;
3021 }
3022
3023 flags = get_flags(&ptr);
3024 ifi = get_long(&ptr);
3025 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
3026 if (ifi && !InterfaceID)
3027 {
3028 deliver_error(rstate, mStatus_BadParamErr);
3029 abort_request(rstate);
3030 unlink_request(rstate);
3031 return;
3032 }
3033
3034 // allocate context structures
3035 def = mallocL("handle_enum_request", sizeof(domain_enum_t));
3036 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
3037 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
3038 if (!def || !all || !term) FatalError("ERROR: malloc");
3039
3040 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
3041 dDNS_RegisterSearchDomains( gmDNS );
3042 #endif
3043
3044 // enumeration requires multiple questions, so we must link all the context pointers so that
3045 // necessary context can be reached from the callbacks
3046 def->rstate = rstate;
3047 all->rstate = rstate;
3048 term->def = def;
3049 term->all = all;
3050 term->rstate = rstate;
3051 rstate->termination_context = term;
3052 rstate->terminate = enum_termination_callback;
3053 def->question.QuestionContext = def;
3054 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3055 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
3056 all->question.QuestionContext = all;
3057 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3058 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
3059
3060 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
3061 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
3062
3063 // make the calls
3064 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
3065 (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
3066 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
3067 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
3068 if (err == mStatus_NoError)
3069 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
3070 result = deliver_error(rstate, err); // send error *before* returning local domain
3071
3072 if (result < 0 || err)
3073 {
3074 abort_request(rstate);
3075 unlink_request(rstate);
3076 return;
3077 }
3078 }
3079
3080 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
3081 {
3082 char domain[MAX_ESCAPED_DOMAIN_NAME];
3083 domain_enum_t *de = question->QuestionContext;
3084 DNSServiceFlags flags = 0;
3085 reply_state *reply;
3086 (void)m; // Unused
3087
3088 if (answer->rrtype != kDNSType_PTR) return;
3089 if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
3090
3091 if (AddRecord)
3092 {
3093 flags |= kDNSServiceFlagsAdd;
3094 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
3095 flags |= kDNSServiceFlagsDefault;
3096 }
3097 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
3098 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3099 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3100 // network, so we just pass kDNSServiceInterfaceIndexAny
3101 reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
3102 if (!reply)
3103 {
3104 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
3105 return;
3106 }
3107 reply->next = NULL;
3108 append_reply(de->rstate, reply);
3109 return;
3110 }
3111
3112 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
3113 {
3114 size_t len;
3115 reply_state *reply;
3116 char *data;
3117
3118 len = sizeof(DNSServiceFlags);
3119 len += sizeof(uint32_t);
3120 len += sizeof(DNSServiceErrorType);
3121 len += strlen(domain) + 1;
3122
3123 reply = create_reply(enumeration_reply_op, len, rstate);
3124 reply->rhdr->flags = dnssd_htonl(flags);
3125 reply->rhdr->ifi = dnssd_htonl(ifi);
3126 reply->rhdr->error = dnssd_htonl(err);
3127 data = reply->sdata;
3128 put_string(domain, &data);
3129 return reply;
3130 }
3131
3132 mDNSlocal void enum_termination_callback(void *context)
3133 {
3134 enum_termination_t *t = context;
3135 mDNS *coredata = gmDNS;
3136
3137 mDNS_StopGetDomains(coredata, &t->all->question);
3138 mDNS_StopGetDomains(coredata, &t->def->question);
3139 freeL("enum_termination_callback", t->all);
3140 freeL("enum_termination_callback", t->def);
3141 t->rstate->termination_context = NULL;
3142 freeL("enum_termination_callback", t);
3143 }
3144
3145 mDNSlocal void handle_reconfirm_request(request_state *rstate)
3146 {
3147 AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
3148 if (rr)
3149 {
3150 mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
3151 LogOperation(
3152 (status == mStatus_NoError) ?
3153 "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
3154 "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
3155 rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
3156 mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
3157 status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
3158 }
3159 abort_request(rstate);
3160 unlink_request(rstate);
3161 freeL("handle_reconfirm_request", rr);
3162 }
3163
3164 // setup rstate to accept new reg/dereg requests
3165 mDNSlocal void reset_connected_rstate(request_state *rstate)
3166 {
3167 rstate->ts = t_morecoming;
3168 rstate->hdr_bytes = 0;
3169 rstate->data_bytes = 0;
3170 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
3171 rstate->msgbuf = NULL;
3172 rstate->bufsize = 0;
3173 }
3174
3175 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3176 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3177 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
3178 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
3179 {
3180 char *rdata, name[256];
3181 AuthRecord *rr;
3182 DNSServiceFlags flags;
3183 uint32_t interfaceIndex;
3184 uint16_t type, class, rdlen;
3185 int storage_size;
3186
3187 flags = get_flags(&msgbuf);
3188 if (validate_flags &&
3189 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
3190 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
3191 {
3192 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3193 return NULL;
3194 }
3195
3196 interfaceIndex = get_long(&msgbuf);
3197 if (get_string(&msgbuf, name, 256) < 0)
3198 {
3199 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3200 return NULL;
3201 }
3202 type = get_short(&msgbuf);
3203 class = get_short(&msgbuf);
3204 rdlen = get_short(&msgbuf);
3205
3206 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
3207 else storage_size = sizeof(RDataBody);
3208
3209 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
3210 if (!rr) FatalError("ERROR: malloc");
3211 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
3212
3213 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
3214 type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
3215
3216 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
3217 {
3218 LogMsg("ERROR: bad name: %s", name);
3219 freeL("read_rr_from_ipc_msg", rr);
3220 return NULL;
3221 }
3222
3223 if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
3224 rr->resrec.rrclass = class;
3225 rr->resrec.rdlength = rdlen;
3226 rr->resrec.rdata->MaxRDLength = rdlen;
3227 rdata = get_rdata(&msgbuf, rdlen);
3228 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
3229 if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
3230 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3231 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
3232 return rr;
3233 }
3234
3235 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
3236 {
3237 domainlabel n;
3238 domainname d, t;
3239
3240 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
3241 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
3242 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
3243 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
3244 return 0;
3245 }
3246
3247 // append a reply to the list in a request object
3248 mDNSlocal void append_reply(request_state *req, reply_state *rep)
3249 {
3250 reply_state *ptr;
3251
3252 if (!req->replies) req->replies = rep;
3253 else
3254 {
3255 ptr = req->replies;
3256 while (ptr->next) ptr = ptr->next;
3257 ptr->next = rep;
3258 }
3259 rep->next = NULL;
3260 }
3261
3262 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3263 // returns the current state of the request (morecoming, error, complete, terminated.)
3264 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
3265 mDNSlocal int read_msg(request_state *rs)
3266 {
3267 uint32_t nleft;
3268 int nread;
3269 char buf[4]; // dummy for death notification
3270
3271 if (rs->ts == t_terminated || rs->ts == t_error)
3272 {
3273 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3274 rs->ts = t_error;
3275 return t_error;
3276 }
3277
3278 if (rs->ts == t_complete)
3279 { // this must be death or something is wrong
3280 nread = recv(rs->sd, buf, 4, 0);
3281 if (!nread) { rs->ts = t_terminated; return t_terminated; }
3282 if (nread < 0) goto rerror;
3283 LogMsg("ERROR: read data from a completed request.");
3284 rs->ts = t_error;
3285 return t_error;
3286 }
3287
3288 if (rs->ts != t_morecoming)
3289 {
3290 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
3291 rs->ts = t_error;
3292 return t_error;
3293 }
3294
3295 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
3296 {
3297 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
3298 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
3299 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3300 if (nread < 0) goto rerror;
3301 rs->hdr_bytes += nread;
3302 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3303 {
3304 ConvertHeaderBytes(&rs->hdr);
3305 if (rs->hdr.version != VERSION)
3306 {
3307 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
3308 rs->ts = t_error;
3309 return t_error;
3310 }
3311 }
3312 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
3313 {
3314 LogMsg("ERROR: read_msg - read too many header bytes");
3315 rs->ts = t_error;
3316 return t_error;
3317 }
3318 }
3319
3320 // only read data if header is complete
3321 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3322 {
3323 if (rs->hdr.datalen == 0) // ok in removerecord requests
3324 {
3325 rs->ts = t_complete;
3326 rs->msgbuf = NULL;
3327 return t_complete;
3328 }
3329
3330 if (!rs->msgbuf) // allocate the buffer first time through
3331 {
3332 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
3333 if (!rs->msgbuf)
3334 {
3335 my_perror("ERROR: malloc");
3336 rs->ts = t_error;
3337 return t_error;
3338 }
3339 rs->msgdata = rs->msgbuf;
3340 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
3341 }
3342 nleft = rs->hdr.datalen - rs->data_bytes;
3343 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
3344 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3345 if (nread < 0) goto rerror;
3346 rs->data_bytes += nread;
3347 if (rs->data_bytes > rs->hdr.datalen)
3348 {
3349 LogMsg("ERROR: read_msg - read too many data bytes");
3350 rs->ts = t_error;
3351 return t_error;
3352 }
3353 }
3354
3355 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
3356 rs->ts = t_complete;
3357 else rs->ts = t_morecoming;
3358
3359 return rs->ts;
3360
3361 rerror:
3362 if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
3363 my_perror("ERROR: read_msg");
3364 rs->ts = t_error;
3365 return t_error;
3366 }
3367
3368 mDNSlocal int send_msg(reply_state *rs)
3369 {
3370 ssize_t nwriten;
3371
3372 if (!rs->msgbuf)
3373 {
3374 LogMsg("ERROR: send_msg called with NULL message buffer");
3375 return t_error;
3376 }
3377
3378 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
3379 {
3380 rs->ts = t_complete;
3381 freeL("send_msg", rs->msgbuf);
3382 return t_complete;
3383 }
3384
3385 ConvertHeaderBytes(rs->mhdr);
3386 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
3387 ConvertHeaderBytes(rs->mhdr);
3388 if (nwriten < 0)
3389 {
3390 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
3391 else
3392 {
3393 #if !defined(PLATFORM_NO_EPIPE)
3394 if (dnssd_errno() == EPIPE)
3395 {
3396 debugf("%3d: broken pipe", rs->sd);
3397 rs->ts = t_terminated;
3398 rs->request->ts = t_terminated;
3399 return t_terminated;
3400 }
3401 else
3402 #endif
3403 {
3404 my_perror("ERROR: send\n");
3405 rs->ts = t_error;
3406 return t_error;
3407 }
3408 }
3409 }
3410 rs->nwriten += nwriten;
3411
3412 if (rs->nwriten == rs->len)
3413 {
3414 rs->ts = t_complete;
3415 freeL("send_msg", rs->msgbuf);
3416 }
3417 return rs->ts;
3418 }
3419
3420 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
3421 {
3422 reply_state *reply;
3423 int totallen;
3424
3425 if ((unsigned)datalen < sizeof(reply_hdr))
3426 {
3427 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3428 return NULL;
3429 }
3430
3431 totallen = (int) (datalen + sizeof(ipc_msg_hdr));
3432 reply = mallocL("create_reply", sizeof(reply_state));
3433 if (!reply) FatalError("ERROR: malloc");
3434 bzero(reply, sizeof(reply_state));
3435 reply->ts = t_morecoming;
3436 reply->sd = request->sd;
3437 reply->request = request;
3438 reply->len = totallen;
3439 reply->msgbuf = mallocL("create_reply", totallen);
3440 if (!reply->msgbuf) FatalError("ERROR: malloc");
3441 bzero(reply->msgbuf, totallen);
3442 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
3443 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
3444 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
3445 reply->mhdr->version = VERSION;
3446 reply->mhdr->op = op;
3447 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
3448 return reply;
3449 }
3450
3451 mDNSlocal int deliver_error(request_state *rstate, mStatus err)
3452 {
3453 int nwritten = -1;
3454 undelivered_error_t *undeliv;
3455
3456 err = dnssd_htonl(err);
3457 nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
3458 if (nwritten < (int)sizeof(mStatus))
3459 {
3460 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3461 nwritten = 0;
3462 if (nwritten < 0)
3463 {
3464 my_perror("ERROR: send - unable to deliver error to client");
3465 return(-1);
3466 }
3467 else
3468 {
3469 //client blocked - store result and come backr
3470 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
3471 if (!undeliv) FatalError("ERROR: malloc");
3472 undeliv->err = err;
3473 undeliv->nwritten = nwritten;
3474 undeliv->sd = rstate->sd;
3475 rstate->u_err = undeliv;
3476 return 0;
3477 }
3478 }
3479 return 0;
3480 }
3481
3482 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
3483 mDNSlocal transfer_state send_undelivered_error(request_state *rs)
3484 {
3485 int nwritten;
3486
3487 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
3488 if (nwritten < 0)
3489 {
3490 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3491 nwritten = 0;
3492 else
3493 {
3494 my_perror("ERROR: send - unable to deliver error to client\n");
3495 return t_error;
3496 }
3497 }
3498 if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
3499 {
3500 freeL("send_undelivered_error", rs->u_err);
3501 rs->u_err = NULL;
3502 return t_complete;
3503 }
3504 rs->u_err->nwritten += nwritten;
3505 return t_morecoming;
3506 }
3507
3508 // send bogus data along with an error code to the app callback
3509 // returns 0 on success (linking reply into list of not fully delivered),
3510 // -1 on failure (request should be aborted)
3511 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
3512 {
3513 int len;
3514 reply_state *reply;
3515 transfer_state ts;
3516
3517 if (rs->no_reply) return 0;
3518 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
3519 reply = create_reply(op, len, rs);
3520 reply->rhdr->error = dnssd_htonl(err);
3521 ts = send_msg(reply);
3522 if (ts == t_error || ts == t_terminated)
3523 {
3524 freeL("deliver_async_error", reply);
3525 return -1;
3526 }
3527 else if (ts == t_complete) freeL("deliver_async_error", reply);
3528 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
3529 return 0;
3530 }
3531
3532 mDNSlocal void abort_request(request_state *rs)
3533 {
3534 reply_state *rep, *ptr;
3535
3536 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
3537 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
3538 LogOperation("%3d: Removing FD", rs->sd);
3539 udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
3540
3541 // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
3542 // for detecting when the memory for an object is inadvertently freed while the object is still on some list
3543 rs->sd = -2;
3544
3545 // free pending replies
3546 rep = rs->replies;
3547 while(rep)
3548 {
3549 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
3550 ptr = rep;
3551 rep = rep->next;
3552 freeL("abort_request", ptr);
3553 }
3554
3555 if (rs->u_err)
3556 {
3557 freeL("abort_request", rs->u_err);
3558 rs->u_err = NULL;
3559 }
3560 }
3561
3562 mDNSlocal void unlink_request(request_state *rs)
3563 {
3564 request_state *ptr;
3565
3566 if (rs == all_requests)
3567 {
3568 all_requests = all_requests->next;
3569 freeL("unlink_request", rs);
3570 return;
3571 }
3572 for(ptr = all_requests; ptr->next; ptr = ptr->next)
3573 if (ptr->next == rs)
3574 {
3575 ptr->next = rs->next;
3576 freeL("unlink_request", rs);
3577 return;
3578 }
3579 }
3580
3581 //hack to search-replace perror's to LogMsg's
3582 mDNSlocal void my_perror(char *errmsg)
3583 {
3584 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
3585 }
3586
3587 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3588 // without overrunning it.
3589 // returns 0 on success, -1 on error.
3590
3591 mDNSlocal int validate_message(request_state *rstate)
3592 {
3593 uint32_t min_size;
3594
3595 switch(rstate->hdr.op)
3596 {
3597 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
3598 sizeof(uint32_t) + // interface
3599 (3 * sizeof(char)); // name, regtype, domain
3600 break;
3601 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
3602 sizeof(uint32_t) + // interface
3603 sizeof(char) + // fullname
3604 (2 * sizeof(uint16_t)); // type, class
3605 break;
3606 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
3607 sizeof(uint32_t) + // interface
3608 (2 * sizeof(char)); // regtype, domain
3609 break;
3610 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
3611 sizeof(uint32_t) + // interface
3612 (4 * sizeof(char)) + // name, type, domain, host
3613 (2 * sizeof(uint16_t)); // port, textlen
3614 break;
3615 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
3616 sizeof(uint32_t); // interface
3617 break;
3618 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3619 sizeof(uint32_t) + // interface
3620 sizeof(char) + // fullname
3621 (3 * sizeof(uint16_t)) + // type, class, rdlen
3622 sizeof(uint32_t); // ttl
3623 break;
3624 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3625 (2 * sizeof(uint16_t)) + // type, rdlen
3626 sizeof(uint32_t); // ttl
3627 break;
3628 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3629 sizeof(uint16_t) + // rdlen
3630 sizeof(uint32_t); // ttl
3631 break;
3632 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
3633 break;
3634 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
3635 sizeof(uint32_t) + // interface
3636 sizeof(char) + // fullname
3637 (3 * sizeof(uint16_t)); // type, class, rdlen
3638 break;
3639 case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
3640 break;
3641 default:
3642 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
3643 return -1;
3644 }
3645
3646 return (rstate->data_bytes >= min_size ? 0 : -1);
3647
3648 }
3649
3650 mDNSlocal uint32_t dnssd_htonl(uint32_t l)
3651 {
3652 uint32_t ret;
3653 char * data;
3654
3655 data = (char*) &ret;
3656
3657 put_long(l, &data);
3658
3659 return ret;
3660 }
3661
3662 #if defined(_WIN32)
3663
3664 mDNSlocal char * win32_strerror(int inErrorCode)
3665 {
3666 static char buffer[1024];
3667 DWORD n;
3668
3669 memset(buffer, 0, sizeof(buffer));
3670
3671 n = FormatMessageA(
3672 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
3673 NULL,
3674 (DWORD) inErrorCode,
3675 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
3676 buffer,
3677 sizeof( buffer ),
3678 NULL );
3679
3680 if( n > 0 )
3681 {
3682 // Remove any trailing CR's or LF's since some messages have them.
3683
3684 while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
3685 {
3686 buffer[ --n ] = '\0';
3687 }
3688 }
3689
3690 return buffer;
3691 }
3692
3693 #endif