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 "®type[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 #pragma ident "%Z%%M% %I% %E% SMI"
649
650 #if defined(_WIN32)
651 #include <process.h>
652 #define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
653 #define dnssd_strerror(X) win32_strerror(X)
654 #define usleep(X) Sleep(((X)+999)/1000)
655 static char * win32_strerror(int inErrorCode);
656 #else
657 #include <fcntl.h>
658 #include <errno.h>
659 #include <sys/ioctl.h>
660 #include <sys/types.h>
661 #include <sys/time.h>
662 #include <sys/resource.h>
663 #define dnssd_strerror(X) strerror(X)
664 #endif
665
666 #include <stdlib.h>
667 #include <stdio.h>
668 #include "mDNSEmbeddedAPI.h"
669 #include "DNSCommon.h"
670 #include "uds_daemon.h"
671 #include "dns_sd.h"
672 #include "dnssd_ipc.h"
673
674 // Apple specific configuration functionality, not required for other platforms
675 #ifdef __MACOSX__
676 #include <sys/ucred.h>
677 #ifndef LOCAL_PEERCRED
678 #define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
679 #endif // LOCAL_PEERCRED
680 #endif //__MACOSX__
681
682 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
683 extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
684 #endif
685
686 // Types and Data Structures
687 // ----------------------------------------------------------------------
688
689 typedef enum
690 {
691 t_uninitialized,
692 t_morecoming,
693 t_complete,
694 t_error,
695 t_terminated
696 } transfer_state;
697
698 typedef void (*req_termination_fn)(void *);
699
700 typedef struct registered_record_entry
701 {
702 uint32_t key;
703 AuthRecord *rr;
704 struct registered_record_entry *next;
705 client_context_t client_context;
706 struct request_state *rstate;
707 } registered_record_entry;
708
709 // A single registered service: ServiceRecordSet + bookkeeping
710 // Note that we duplicate some fields from parent service_info object
711 // to facilitate cleanup, when instances and parent may be deallocated at different times.
712 typedef struct service_instance
713 {
714 struct service_instance *next;
715 mDNSBool autoname; // Set if this name is tied to the Computer Name
716 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
717 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
718 mDNSBool rename_on_memfree; // Set on config change when we deregister original name
719 domainlabel name;
720 domainname domain;
721 mDNSBool default_local; // is this the "local." from an empty-string registration?
722 struct request_state *request;
723 dnssd_sock_t sd;
724 AuthRecord *subtypes;
725 ServiceRecordSet srs; // note - must be last field in struct
726 } service_instance;
727
728 // A client-created service. May reference several service_info objects if default
729 // settings cause registration in multiple domains.
730 typedef struct
731 {
732 uint16_t txtlen;
733 void *txtdata;
734 mDNSIPPort port;
735 domainlabel name;
736 char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
737 domainname type;
738 mDNSBool default_domain;
739 domainname host;
740 mDNSBool autoname; // Set if this name is tied to the Computer Name
741 mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
742 mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
743 int num_subtypes;
744 mDNSInterfaceID InterfaceID;
745 service_instance *instances;
746 struct request_state *request;
747 } service_info;
748
749 // for multi-domain default browsing
750 typedef struct browser_t
751 {
752 DNSQuestion q;
753 domainname domain;
754 struct browser_t *next;
755 } browser_t;
756
757 // parent struct for browser instances: list pointer plus metadata
758 typedef struct
759 {
760 mDNSBool default_domain;
761 mDNSBool ForceMCast;
762 domainname regtype;
763 mDNSInterfaceID interface_id;
764 struct request_state *rstate;
765 browser_t *browsers;
766 } browser_info_t;
767
768 typedef struct
769 {
770 mStatus err; // Note: This field is in NETWORK byte order
771 int nwritten;
772 dnssd_sock_t sd;
773 } undelivered_error_t;
774
775 typedef struct request_state
776 {
777 // connection structures
778 dnssd_sock_t sd;
779
780 // state of read (in case message is read over several recv() calls)
781 transfer_state ts;
782 uint32_t hdr_bytes; // bytes of header already read
783 ipc_msg_hdr hdr;
784 uint32_t data_bytes; // bytes of message data already read
785 char *msgbuf; // pointer to data storage to pass to free()
786 char *msgdata; // pointer to data to be read from (may be modified)
787 int bufsize; // size of data storage
788
789 // reply, termination, error, and client context info
790 int no_reply; // don't send asynchronous replies to client
791 int time_blocked; // record time of a blocked client
792 void *client_context; // don't touch this - pointer only valid in client's addr space
793 struct reply_state *replies; // corresponding (active) reply list
794 undelivered_error_t *u_err;
795 void *termination_context;
796 req_termination_fn terminate;
797
798 //!!!KRS toss these pointers in a union
799 // registration context associated with this request (null if not applicable)
800 registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
801 service_info *service_registration;
802 browser_info_t *browser_info;
803 struct request_state *next;
804 } request_state;
805
806 // struct physically sits between ipc message header and call-specific fields in the message buffer
807 typedef struct
808 {
809 DNSServiceFlags flags; // Note: This field is in NETWORK byte order
810 uint32_t ifi; // Note: This field is in NETWORK byte order
811 DNSServiceErrorType error; // Note: This field is in NETWORK byte order
812 } reply_hdr;
813
814 typedef struct reply_state
815 {
816 // state of the transmission
817 dnssd_sock_t sd;
818 transfer_state ts;
819 uint32_t nwriten;
820 uint32_t len;
821 // context of the reply
822 struct request_state *request; // the request that this answers
823 struct reply_state *next; // if there are multiple unsent replies
824 // pointer into message buffer - allows fields to be changed after message is formatted
825 ipc_msg_hdr *mhdr;
826 reply_hdr *rhdr;
827 char *sdata; // pointer to start of call-specific data
828 // pointer to malloc'd buffer
829 char *msgbuf;
830 } reply_state;
831
832 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
833 // structures to handle callbacks
834 typedef struct
835 {
836 DNSQuestion question;
837 mDNS_DomainType type;
838 request_state *rstate;
839 } domain_enum_t;
840
841 typedef struct
842 {
843 domain_enum_t *all;
844 domain_enum_t *def;
845 request_state *rstate;
846 } enum_termination_t;
847
848 typedef struct
849 {
850 request_state *rstate;
851 DNSQuestion qtxt;
852 DNSQuestion qsrv;
853 // const ResourceRecord *txt;
854 // const ResourceRecord *srv;
855 mDNSBool srv;
856 mDNSBool txt;
857 rdataSRV srvdata;
858 mDNSu16 txtlen;
859 mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
860 } resolve_termination_t;
861
862 #ifdef _HAVE_SETDOMAIN_SUPPORT_
863 typedef struct default_browse_list_t
864 {
865 struct default_browse_list_t *next;
866 uid_t uid;
867 AuthRecord ptr_rec;
868 } default_browse_list_t;
869
870 static default_browse_list_t *default_browse_list = NULL;
871 #endif // _HAVE_SETDOMAIN_SUPPORT_
872
873 // globals
874 mDNSexport mDNS mDNSStorage;
875 #define gmDNS (&mDNSStorage)
876
877 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
878 static request_state * all_requests = NULL;
879
880 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
881 // terminating connection
882 #define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
883 // n get_string() calls w/o buffer overrun
884 // private function prototypes
885 mDNSlocal void connect_callback(void *info);
886 mDNSlocal int read_msg(request_state *rs);
887 mDNSlocal int send_msg(reply_state *rs);
888 mDNSlocal void abort_request(request_state *rs);
889 mDNSlocal void request_callback(void *info);
890 mDNSlocal void handle_resolve_request(request_state *rstate);
891 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
892 mDNSlocal void question_termination_callback(void *context);
893 mDNSlocal void handle_browse_request(request_state *request);
894 mDNSlocal void browse_termination_callback(void *context);
895 mDNSlocal void handle_regservice_request(request_state *request);
896 mDNSlocal void regservice_termination_callback(void *context);
897 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
898 mDNSlocal mStatus handle_add_request(request_state *rstate);
899 mDNSlocal mStatus handle_update_request(request_state *rstate);
900 mDNSlocal void append_reply(request_state *req, reply_state *rep);
901 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
902 mDNSlocal void enum_termination_callback(void *context);
903 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
904 mDNSlocal void handle_query_request(request_state *rstate);
905 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
906 mDNSlocal void handle_enum_request(request_state *rstate);
907 mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
908 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
909 mDNSlocal void connected_registration_termination(void *context);
910 mDNSlocal void handle_reconfirm_request(request_state *rstate);
911 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
912 mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
913 mDNSlocal void reset_connected_rstate(request_state *rstate);
914 mDNSlocal int deliver_error(request_state *rstate, mStatus err);
915 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
916 mDNSlocal transfer_state send_undelivered_error(request_state *rs);
917 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
918 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
919 mDNSlocal void my_perror(char *errmsg);
920 mDNSlocal void unlink_request(request_state *rs);
921 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
922 mDNSlocal void resolve_termination_callback(void *context);
923 mDNSlocal int validate_message(request_state *rstate);
924 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
925 mDNSlocal mStatus remove_record(request_state *rstate);
926 mDNSlocal void free_service_instance(service_instance *srv);
927 mDNSlocal uint32_t dnssd_htonl(uint32_t l);
928 mDNSlocal void handle_setdomain_request(request_state *rstate);
929
930 // initialization, setup/teardown functions
931
932 // If a platform specifies its own PID file name, we use that
933 #ifndef PID_FILE
934 #define PID_FILE "/var/run/mDNSResponder.pid"
935 #endif
936
LogClientInfo(request_state * req)937 mDNSlocal void LogClientInfo(request_state *req)
938 {
939 void *t = req->termination_context;
940 if (t)
941 {
942 if (req->terminate == regservice_termination_callback)
943 {
944 service_instance *ptr;
945 for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
946 LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
947 }
948 else if (req->terminate == browse_termination_callback)
949 {
950 browser_t *blist;
951 for (blist = req->browser_info->browsers; blist; blist = blist->next)
952 LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
953 }
954 else if (req->terminate == resolve_termination_callback)
955 LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
956 else if (req->terminate == question_termination_callback)
957 LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req->sd, ((DNSQuestion *) t)->qname.c);
958 else if (req->terminate == enum_termination_callback)
959 LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
960 }
961 }
962
FatalError(char * errmsg)963 mDNSlocal void FatalError(char *errmsg)
964 {
965 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
966 *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
967 abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
968 }
969
udsserver_init(void)970 int udsserver_init(void)
971 {
972 dnssd_sockaddr_t laddr;
973 int ret;
974 #if defined(_WIN32)
975 u_long opt = 1;
976 #endif
977
978 // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
979 if (PID_FILE[0])
980 {
981 FILE *fp = fopen(PID_FILE, "w");
982 if (fp != NULL)
983 {
984 fprintf(fp, "%d\n", getpid());
985 fclose(fp);
986 }
987 }
988
989 if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
990 {
991 my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
992 goto error;
993 }
994
995 bzero(&laddr, sizeof(laddr));
996
997 #if defined(USE_TCP_LOOPBACK)
998 {
999 laddr.sin_family = AF_INET;
1000 laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
1001 laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1002 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1003 if (ret < 0)
1004 {
1005 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1006 goto error;
1007 }
1008 }
1009 #else
1010 {
1011 mode_t mask = umask(0);
1012 unlink(MDNS_UDS_SERVERPATH); //OK if this fails
1013 laddr.sun_family = AF_LOCAL;
1014 #ifndef NOT_HAVE_SA_LEN
1015 // According to Stevens (section 3.2), there is no portable way to
1016 // determine whether sa_len is defined on a particular platform.
1017 laddr.sun_len = sizeof(struct sockaddr_un);
1018 #endif
1019 strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
1020 ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
1021 umask(mask);
1022 if (ret < 0)
1023 {
1024 my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
1025 goto error;
1026 }
1027 }
1028 #endif
1029
1030 #if defined(_WIN32)
1031 //
1032 // SEH: do we even need to do this on windows? this socket
1033 // will be given to WSAEventSelect which will automatically
1034 // set it to non-blocking
1035 //
1036 if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
1037 #else
1038 if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
1039 #endif
1040 {
1041 my_perror("ERROR: could not set listen socket to non-blocking mode");
1042 goto error;
1043 }
1044
1045 if (listen(listenfd, LISTENQ) != 0)
1046 {
1047 my_perror("ERROR: could not listen on listen socket");
1048 goto error;
1049 }
1050
1051 if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
1052 {
1053 my_perror("ERROR: could not add listen socket to event loop");
1054 goto error;
1055 }
1056
1057 #if !defined(PLATFORM_NO_RLIMIT)
1058 {
1059 // Set maximum number of open file descriptors
1060 #define MIN_OPENFILES 10240
1061 struct rlimit maxfds, newfds;
1062
1063 // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
1064 // you have to get and set rlimits once before getrlimit will return sensible values
1065 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1066 if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1067
1068 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1069 newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
1070 newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
1071 if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
1072 if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
1073
1074 if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
1075 debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
1076 debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
1077 }
1078 #endif
1079
1080 return 0;
1081
1082 error:
1083
1084 my_perror("ERROR: udsserver_init");
1085 return -1;
1086 }
1087
udsserver_exit(void)1088 int udsserver_exit(void)
1089 {
1090 dnssd_close(listenfd);
1091
1092 #if !defined(USE_TCP_LOOPBACK)
1093 // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
1094 // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
1095 // It would be nice if we could find a solution to this problem
1096 if (unlink(MDNS_UDS_SERVERPATH))
1097 debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
1098 #endif
1099
1100 if (PID_FILE[0]) unlink(PID_FILE);
1101
1102 return 0;
1103 }
1104
udsserver_idle(mDNSs32 nextevent)1105 mDNSs32 udsserver_idle(mDNSs32 nextevent)
1106 {
1107 request_state *req = all_requests, *tmp, *prev = NULL;
1108 reply_state *fptr;
1109 transfer_state result;
1110 mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
1111
1112 while(req)
1113 {
1114 result = t_uninitialized;
1115 if (req->u_err)
1116 result = send_undelivered_error(req);
1117 if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
1118 (req->ts == t_complete || req->ts == t_morecoming))
1119 {
1120 while(req->replies)
1121 {
1122 if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
1123 result = send_msg(req->replies);
1124 if (result == t_complete)
1125 {
1126 fptr = req->replies;
1127 req->replies = req->replies->next;
1128 freeL("udsserver_idle", fptr);
1129 req->time_blocked = 0; // reset failure counter after successful send
1130 }
1131 else if (result == t_terminated || result == t_error)
1132 {
1133 abort_request(req);
1134 break;
1135 }
1136 else if (result == t_morecoming) break; // client's queues are full, move to next
1137 }
1138 }
1139 if (result == t_morecoming)
1140 {
1141 if (!req->time_blocked) req->time_blocked = now;
1142 debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
1143 if (now - req->time_blocked >= MAX_TIME_BLOCKED)
1144 {
1145 LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
1146 LogClientInfo(req);
1147 abort_request(req);
1148 result = t_terminated;
1149 }
1150 else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
1151 }
1152 if (result == t_terminated || result == t_error)
1153 //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
1154 {
1155 tmp = req;
1156 if (prev) prev->next = req->next;
1157 if (req == all_requests) all_requests = all_requests->next;
1158 req = req->next;
1159 freeL("udsserver_idle", tmp);
1160 }
1161 else
1162 {
1163 prev = req;
1164 req = req->next;
1165 }
1166 }
1167 return nextevent;
1168 }
1169
udsserver_info(mDNS * const m)1170 mDNSexport void udsserver_info(mDNS *const m)
1171 {
1172 mDNSs32 now = mDNS_TimeNow(m);
1173 mDNSu32 CacheUsed = 0, CacheActive = 0;
1174 mDNSu32 slot;
1175 CacheGroup *cg;
1176 CacheRecord *rr;
1177 request_state *req;
1178
1179 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1180
1181 LogMsgNoIdent("Slt Q TTL U Type if len rdata");
1182 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
1183 for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1184 {
1185 CacheUsed++; // Count one cache entity for the CacheGroup object
1186 for (rr = cg->members; rr; rr=rr->next)
1187 {
1188 mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
1189 CacheUsed++;
1190 if (rr->CRActiveQuestion) CacheActive++;
1191 LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
1192 slot,
1193 rr->CRActiveQuestion ? "*" : " ",
1194 remain,
1195 (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
1196 DNSTypeName(rr->resrec.rrtype),
1197 ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
1198 CRDisplayString(m, rr));
1199 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1200 }
1201 }
1202
1203 if (m->rrcache_totalused != CacheUsed)
1204 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
1205 if (m->rrcache_active != CacheActive)
1206 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
1207 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
1208
1209 for (req = all_requests; req; req=req->next)
1210 LogClientInfo(req);
1211
1212 now = mDNS_TimeNow(m);
1213 LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
1214 }
1215
1216 #if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
uds_validatelists(void)1217 mDNSexport void uds_validatelists(void)
1218 {
1219 request_state *req;
1220 for (req = all_requests; req; req=req->next)
1221 if (req->sd < 0 && req->sd != -2)
1222 LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
1223 }
1224 #endif
1225
rename_service(service_instance * srv)1226 mDNSlocal void rename_service(service_instance *srv)
1227 {
1228 if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
1229 {
1230 srv->rename_on_memfree = 1;
1231 if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
1232 regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
1233 }
1234 }
1235
udsserver_handle_configchange(void)1236 mDNSexport void udsserver_handle_configchange(void)
1237 {
1238 request_state *req;
1239
1240 for (req = all_requests; req; req = req->next)
1241 {
1242 if (req->service_registration)
1243 {
1244 service_instance *ptr;
1245 for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
1246 rename_service(ptr);
1247 }
1248 }
1249 }
1250
connect_callback(void * info)1251 mDNSlocal void connect_callback(void *info)
1252 {
1253 dnssd_sock_t sd;
1254 dnssd_socklen_t len;
1255 unsigned long optval;
1256 dnssd_sockaddr_t cliaddr;
1257 request_state *rstate;
1258 (void)info; // Unused
1259
1260 len = (dnssd_socklen_t) sizeof(cliaddr);
1261
1262 sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
1263
1264 if (sd == dnssd_InvalidSocket)
1265 {
1266 if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
1267 my_perror("ERROR: accept");
1268 return;
1269 }
1270 optval = 1;
1271
1272 #ifdef SO_NOSIGPIPE
1273 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
1274 if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
1275 {
1276 my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
1277 dnssd_close(sd);
1278 return;
1279 }
1280 #endif
1281
1282 #if defined(_WIN32)
1283 if (ioctlsocket(sd, FIONBIO, &optval) != 0)
1284 #else
1285 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
1286 #endif
1287 {
1288 my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
1289 dnssd_close(sd);
1290 return;
1291 }
1292
1293 // allocate a request_state struct that will live with the socket
1294 rstate = mallocL("connect_callback", sizeof(request_state));
1295 if (!rstate) FatalError("ERROR: malloc");
1296 bzero(rstate, sizeof(request_state));
1297 rstate->ts = t_morecoming;
1298 rstate->sd = sd;
1299
1300 LogOperation("%3d: Adding FD", rstate->sd);
1301 if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
1302 return;
1303 rstate->next = all_requests;
1304 all_requests = rstate;
1305 }
1306
1307 // handler
request_callback(void * info)1308 mDNSlocal void request_callback(void *info)
1309 {
1310 request_state *rstate = info;
1311 transfer_state result;
1312 dnssd_sockaddr_t cliaddr;
1313 int dedicated_error_socket;
1314 #if defined(_WIN32)
1315 u_long opt = 1;
1316 #endif
1317
1318 result = read_msg(rstate);
1319 if (result == t_morecoming)
1320 {
1321 return;
1322 }
1323 if (result == t_terminated)
1324 {
1325 abort_request(rstate);
1326 unlink_request(rstate);
1327 return;
1328 }
1329 if (result == t_error)
1330 {
1331 abort_request(rstate);
1332 unlink_request(rstate);
1333 return;
1334 }
1335
1336 if (rstate->hdr.version != VERSION)
1337 {
1338 LogMsg("ERROR: client incompatible with daemon (client version = %d, "
1339 "daemon version = %d)\n", rstate->hdr.version, VERSION);
1340 abort_request(rstate);
1341 unlink_request(rstate);
1342 return;
1343 }
1344
1345 if (validate_message(rstate) < 0)
1346 {
1347 // note that we cannot deliver an error message if validation fails, since the path to the error socket
1348 // may be contained in the (invalid) message body for some message types
1349 abort_request(rstate);
1350 unlink_request(rstate);
1351 LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
1352 return;
1353 }
1354
1355 // check if client wants silent operation
1356 if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
1357
1358 dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
1359 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
1360
1361 if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
1362 LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
1363
1364 // check if primary socket is to be used for synchronous errors, else open new socket
1365 if (dedicated_error_socket)
1366 {
1367 mStatus err = 0;
1368 int nwritten;
1369 dnssd_sock_t errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
1370 if (errfd == dnssd_InvalidSocket)
1371 {
1372 my_perror("ERROR: socket");
1373 abort_request(rstate);
1374 unlink_request(rstate);
1375 return;
1376 }
1377
1378 //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
1379
1380 #if defined(USE_TCP_LOOPBACK)
1381 {
1382 mDNSOpaque16 port;
1383 port.b[0] = rstate->msgdata[0];
1384 port.b[1] = rstate->msgdata[1];
1385 rstate->msgdata += 2;
1386 cliaddr.sin_family = AF_INET;
1387 cliaddr.sin_port = port.NotAnInteger;
1388 cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
1389 }
1390 #else
1391 {
1392 char ctrl_path[MAX_CTLPATH];
1393 get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
1394 bzero(&cliaddr, sizeof(cliaddr));
1395 cliaddr.sun_family = AF_LOCAL;
1396 strcpy(cliaddr.sun_path, ctrl_path);
1397 }
1398 #endif
1399 //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
1400 if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
1401 {
1402 //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
1403 my_perror("ERROR: connect");
1404 abort_request(rstate);
1405 unlink_request(rstate);
1406 return;
1407 }
1408 #if defined(_WIN32)
1409 if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
1410 #else
1411 if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
1412 #endif
1413 {
1414 my_perror("ERROR: could not set control socket to non-blocking mode");
1415 abort_request(rstate);
1416 unlink_request(rstate);
1417 return;
1418 }
1419
1420 switch(rstate->hdr.op)
1421 {
1422 case reg_record_request: err = handle_regrecord_request (rstate); break;
1423 case add_record_request: err = handle_add_request (rstate); break;
1424 case update_record_request: err = handle_update_request (rstate); break;
1425 case remove_record_request: err = handle_removerecord_request(rstate); break;
1426 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1427 }
1428
1429 //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
1430 err = dnssd_htonl(err);
1431 nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
1432 // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
1433 // If not, we don't attempt to handle this failure, but we do log it.
1434 if (nwritten < (int)sizeof(err))
1435 LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
1436 nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
1437 //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
1438 dnssd_close(errfd);
1439 //LogOperation("request_callback: Closed errfd %d", errfd);
1440 reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
1441 }
1442 else
1443 {
1444 switch(rstate->hdr.op)
1445 {
1446 case resolve_request: handle_resolve_request (rstate); break;
1447 case query_request: handle_query_request (rstate); break;
1448 case browse_request: handle_browse_request (rstate); break;
1449 case reg_service_request: handle_regservice_request(rstate); break;
1450 case enumeration_request: handle_enum_request (rstate); break;
1451 case reconfirm_record_request: handle_reconfirm_request (rstate); break;
1452 case setdomain_request: handle_setdomain_request (rstate); break;
1453 default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
1454 }
1455 }
1456 }
1457
1458 // mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
1459 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
1460 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
1461 // the mDNSCore operation if the client dies or closes its socket.
1462
1463 // query and resolve calls have separate request handlers that parse the arguments from the client and
1464 // massage the name parameters appropriately, but the rest of the operations (making the query call,
1465 // delivering the result to the client, and termination) are identical.
1466
handle_query_request(request_state * rstate)1467 mDNSlocal void handle_query_request(request_state *rstate)
1468 {
1469 DNSServiceFlags flags;
1470 uint32_t ifi;
1471 char name[256];
1472 uint16_t rrtype, rrclass;
1473 char *ptr;
1474 mStatus result;
1475 mDNSInterfaceID InterfaceID;
1476 DNSQuestion *q;
1477
1478 if (rstate->ts != t_complete)
1479 {
1480 LogMsg("ERROR: handle_query_request - transfer state != t_complete");
1481 goto error;
1482 }
1483 ptr = rstate->msgdata;
1484 if (!ptr)
1485 {
1486 LogMsg("ERROR: handle_query_request - NULL msgdata");
1487 goto error;
1488 }
1489
1490 flags = get_flags(&ptr);
1491 ifi = get_long(&ptr);
1492 if (get_string(&ptr, name, 256) < 0) goto bad_param;
1493 rrtype = get_short(&ptr);
1494 rrclass = get_short(&ptr);
1495 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
1496 if (ifi && !InterfaceID) goto bad_param;
1497
1498 q = mallocL("DNSQuestion", sizeof(DNSQuestion));
1499 if (!q) FatalError("ERROR: handle_query - malloc");
1500 bzero(q, sizeof(DNSQuestion));
1501
1502 q->InterfaceID = InterfaceID;
1503 q->Target = zeroAddr;
1504 if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
1505 q->qtype = rrtype;
1506 q->qclass = rrclass;
1507 q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
1508 q->ExpectUnique = mDNSfalse;
1509 q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
1510 q->ReturnCNAME = (flags & kDNSServiceFlagsReturnCNAME) != 0;
1511 q->QuestionCallback = question_result_callback;
1512 q->QuestionContext = rstate;
1513
1514 rstate->termination_context = q;
1515 rstate->terminate = question_termination_callback;
1516
1517 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
1518 result = mDNS_StartQuery(gmDNS, q);
1519 if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
1520
1521 if (result) rstate->terminate = NULL;
1522 if (deliver_error(rstate, result) < 0) goto error;
1523 return;
1524
1525 bad_param:
1526 deliver_error(rstate, mStatus_BadParamErr);
1527 rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
1528 error:
1529 abort_request(rstate);
1530 unlink_request(rstate);
1531 return;
1532 }
1533
handle_resolve_request(request_state * rstate)1534 mDNSlocal void handle_resolve_request(request_state *rstate)
1535 {
1536 DNSServiceFlags flags;
1537 uint32_t interfaceIndex;
1538 mDNSInterfaceID InterfaceID;
1539 char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
1540 char *ptr; // message data pointer
1541 domainname fqdn;
1542 resolve_termination_t *term;
1543 mStatus err;
1544
1545 if (rstate->ts != t_complete)
1546 {
1547 LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
1548 abort_request(rstate);
1549 unlink_request(rstate);
1550 return;
1551 }
1552
1553 // extract the data from the message
1554 ptr = rstate->msgdata;
1555 if (!ptr)
1556 {
1557 LogMsg("ERROR: handle_resolve_request - NULL msgdata");
1558 abort_request(rstate);
1559 unlink_request(rstate);
1560 return;
1561 }
1562 flags = get_flags(&ptr);
1563 interfaceIndex = get_long(&ptr);
1564 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
1565 if (interfaceIndex && !InterfaceID)
1566 { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
1567 if (get_string(&ptr, name, 256) < 0 ||
1568 get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1569 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
1570 { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
1571
1572 // free memory in rstate since we don't need it anymore
1573 freeL("handle_resolve_request", rstate->msgbuf);
1574 rstate->msgbuf = NULL;
1575
1576 if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
1577 { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
1578
1579 // set up termination info
1580 term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
1581 bzero(term, sizeof(*term));
1582 if (!term) FatalError("ERROR: malloc");
1583
1584 // format questions
1585 term->qsrv.InterfaceID = InterfaceID;
1586 term->qsrv.Target = zeroAddr;
1587 memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
1588 term->qsrv.qtype = kDNSType_SRV;
1589 term->qsrv.qclass = kDNSClass_IN;
1590 term->qsrv.LongLived = mDNSfalse;
1591 term->qsrv.ExpectUnique = mDNStrue;
1592 term->qsrv.ForceMCast = mDNSfalse;
1593 term->qsrv.QuestionCallback = resolve_result_callback;
1594 term->qsrv.QuestionContext = rstate;
1595
1596 term->qtxt.InterfaceID = InterfaceID;
1597 term->qtxt.Target = zeroAddr;
1598 memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
1599 term->qtxt.qtype = kDNSType_TXT;
1600 term->qtxt.qclass = kDNSClass_IN;
1601 term->qtxt.LongLived = mDNSfalse;
1602 term->qtxt.ExpectUnique = mDNStrue;
1603 term->qtxt.ForceMCast = mDNSfalse;
1604 term->qtxt.QuestionCallback = resolve_result_callback;
1605 term->qtxt.QuestionContext = rstate;
1606
1607 term->rstate = rstate;
1608 rstate->termination_context = term;
1609 rstate->terminate = resolve_termination_callback;
1610
1611 // ask the questions
1612 LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
1613 err = mDNS_StartQuery(gmDNS, &term->qsrv);
1614 if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
1615
1616 if (err)
1617 {
1618 freeL("handle_resolve_request", term);
1619 rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
1620 }
1621 if (deliver_error(rstate, err) < 0 || err)
1622 {
1623 abort_request(rstate);
1624 unlink_request(rstate);
1625 }
1626 return;
1627
1628 bad_param:
1629 deliver_error(rstate, mStatus_BadParamErr);
1630 abort_request(rstate);
1631 unlink_request(rstate);
1632 }
1633
resolve_termination_callback(void * context)1634 mDNSlocal void resolve_termination_callback(void *context)
1635 {
1636 resolve_termination_t *term = context;
1637 request_state *rs;
1638
1639 if (!term)
1640 {
1641 LogMsg("ERROR: resolve_termination_callback: double termination");
1642 return;
1643 }
1644 rs = term->rstate;
1645 LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
1646
1647 mDNS_StopQuery(gmDNS, &term->qtxt);
1648 mDNS_StopQuery(gmDNS, &term->qsrv);
1649
1650 freeL("resolve_termination_callback", term);
1651 rs->termination_context = NULL;
1652 }
1653
resolve_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)1654 mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1655 {
1656 size_t len = 0;
1657 char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
1658 char *data;
1659 transfer_state result;
1660 reply_state *rep;
1661 request_state *rs = question->QuestionContext;
1662 resolve_termination_t *res = rs->termination_context;
1663 (void)m; // Unused
1664
1665 LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
1666 rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
1667
1668 // This code used to do this trick of just keeping a copy of the pointer to
1669 // the answer record in the cache, but the unicast query code doesn't currently
1670 // put its answer records in the cache, so for now we can't do this.
1671
1672 if (!AddRecord)
1673 {
1674 // After unicast query code is updated to store its records in the common cache, use this...
1675 // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
1676 // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
1677 // intead of this...
1678 if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
1679 res->srv = mDNSfalse;
1680 if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
1681 res->txt = mDNSfalse;
1682 return;
1683 }
1684
1685 // After unicast query code is updated to store its records in the common cache, use this...
1686 // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
1687 // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
1688 // intead of this...
1689 if (answer->rrtype == kDNSType_SRV)
1690 {
1691 res->srvdata = answer->rdata->u.srv;
1692 res->srv = mDNStrue;
1693 }
1694 if (answer->rrtype == kDNSType_TXT)
1695 {
1696 if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
1697 res->txtlen = answer->rdlength;
1698 mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
1699 res->txt = mDNStrue;
1700 }
1701
1702 if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
1703
1704 ConvertDomainNameToCString(answer->name, fullname);
1705 ConvertDomainNameToCString(&res->srvdata.target, target);
1706
1707 // calculate reply length
1708 len += sizeof(DNSServiceFlags);
1709 len += sizeof(uint32_t); // interface index
1710 len += sizeof(DNSServiceErrorType);
1711 len += strlen(fullname) + 1;
1712 len += strlen(target) + 1;
1713 len += 2 * sizeof(uint16_t); // port, txtLen
1714 len += res->txtlen;
1715
1716 // allocate/init reply header
1717 rep = create_reply(resolve_reply_op, len, rs);
1718 rep->rhdr->flags = dnssd_htonl(0);
1719 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1720 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1721
1722 data = rep->sdata;
1723
1724 // write reply data to message
1725 put_string(fullname, &data);
1726 put_string(target, &data);
1727 *data++ = res->srvdata.port.b[0];
1728 *data++ = res->srvdata.port.b[1];
1729 put_short(res->txtlen, &data);
1730 put_rdata(res->txtlen, res->txtdata, &data);
1731
1732 result = send_msg(rep);
1733 if (result == t_error || result == t_terminated)
1734 {
1735 abort_request(rs);
1736 unlink_request(rs);
1737 freeL("resolve_result_callback", rep);
1738 }
1739 else if (result == t_complete) freeL("resolve_result_callback", rep);
1740 else append_reply(rs, rep);
1741 }
1742
1743 // what gets called when a resolve is completed and we need to send the data back to the client
question_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)1744 mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
1745 {
1746 char *data;
1747 char name[MAX_ESCAPED_DOMAIN_NAME];
1748 request_state *req = question->QuestionContext;
1749 reply_state *rep;
1750 size_t len;
1751 (void)m; // Unused
1752
1753 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
1754 //mDNS_StopQuery(m, question);
1755
1756 if (answer->rdlength == 0)
1757 {
1758 deliver_async_error(req, query_reply_op, kDNSServiceErr_NoSuchRecord);
1759 return;
1760 }
1761
1762 // calculate reply data length
1763 len = sizeof(DNSServiceFlags);
1764 len += 2 * sizeof(uint32_t); // if index + ttl
1765 len += sizeof(DNSServiceErrorType);
1766 len += 3 * sizeof(uint16_t); // type, class, rdlen
1767 len += answer->rdlength;
1768 ConvertDomainNameToCString(answer->name, name);
1769 len += strlen(name) + 1;
1770
1771 rep = create_reply(query_reply_op, len, req);
1772
1773 rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
1774 rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
1775 rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
1776
1777 data = rep->sdata;
1778
1779 put_string(name, &data);
1780 put_short(answer->rrtype, &data);
1781 put_short(answer->rrclass, &data);
1782 put_short(answer->rdlength, &data);
1783 put_rdata(answer->rdlength, answer->rdata->u.data, &data);
1784 put_long(AddRecord ? answer->rroriginalttl : 0, &data);
1785
1786 append_reply(req, rep);
1787 return;
1788 }
1789
question_termination_callback(void * context)1790 mDNSlocal void question_termination_callback(void *context)
1791 {
1792 DNSQuestion *q = context;
1793 LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
1794 mDNS_StopQuery(gmDNS, q); // no need to error check
1795 freeL("question_termination_callback", q);
1796 }
1797
1798 // If there's a comma followed by another character,
1799 // FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
1800 // Otherwise, it returns a pointer to the final nul at the end of the string
FindFirstSubType(char * p)1801 mDNSlocal char *FindFirstSubType(char *p)
1802 {
1803 while (*p)
1804 {
1805 if (p[0] == '\\' && p[1]) p += 2;
1806 else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
1807 else p++;
1808 }
1809 return(p);
1810 }
1811
1812 // If there's a comma followed by another character,
1813 // FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
1814 // If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
1815 // Otherwise, it returns a pointer to the final nul at the end of the string
FindNextSubType(char * p)1816 mDNSlocal char *FindNextSubType(char *p)
1817 {
1818 while (*p)
1819 {
1820 if (p[0] == '\\' && p[1]) // If escape character
1821 p += 2; // ignore following character
1822 else if (p[0] == ',') // If we found a comma
1823 {
1824 if (p[1]) *p++ = 0;
1825 return(p);
1826 }
1827 else if (p[0] == '.')
1828 return(mDNSNULL);
1829 else p++;
1830 }
1831 return(p);
1832 }
1833
1834 // Returns -1 if illegal subtype found
ChopSubTypes(char * regtype)1835 mDNSexport mDNSs32 ChopSubTypes(char *regtype)
1836 {
1837 mDNSs32 NumSubTypes = 0;
1838 char *stp = FindFirstSubType(regtype);
1839 while (stp && *stp) // If we found a comma...
1840 {
1841 if (*stp == ',') return(-1);
1842 NumSubTypes++;
1843 stp = FindNextSubType(stp);
1844 }
1845 if (!stp) return(-1);
1846 return(NumSubTypes);
1847 }
1848
AllocateSubTypes(mDNSs32 NumSubTypes,char * p)1849 mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
1850 {
1851 AuthRecord *st = mDNSNULL;
1852 if (NumSubTypes)
1853 {
1854 mDNSs32 i;
1855 st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
1856 if (!st) return(mDNSNULL);
1857 for (i = 0; i < NumSubTypes; i++)
1858 {
1859 mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
1860 while (*p) p++;
1861 p++;
1862 if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
1863 { freeL("ServiceSubTypes", st); return(mDNSNULL); }
1864 }
1865 }
1866 return(st);
1867 }
1868
1869 #ifdef _HAVE_SETDOMAIN_SUPPORT_
free_defdomain(mDNS * const m,AuthRecord * const rr,mStatus result)1870 mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
1871 {
1872 (void)m; // unused
1873 if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
1874 }
1875 #endif
1876
handle_setdomain_request(request_state * request)1877 mDNSlocal void handle_setdomain_request(request_state *request)
1878 {
1879 mStatus err = mStatus_NoError;
1880 char *ptr;
1881 char domainstr[MAX_ESCAPED_DOMAIN_NAME];
1882 domainname domain;
1883 DNSServiceFlags flags;
1884 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1885 struct xucred xuc;
1886 socklen_t xuclen;
1887 #endif
1888
1889 if (request->ts != t_complete)
1890 {
1891 LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
1892 abort_request(request);
1893 unlink_request(request);
1894 return;
1895 }
1896
1897 // extract flags/domain from message
1898 ptr = request->msgdata;
1899 flags = get_flags(&ptr);
1900 if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
1901 !MakeDomainNameFromDNSNameString(&domain, domainstr))
1902 { err = mStatus_BadParamErr; goto end; }
1903
1904 freeL("handle_setdomain_request", request->msgbuf);
1905 request->msgbuf = NULL;
1906
1907 debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
1908
1909 #ifdef _HAVE_SETDOMAIN_SUPPORT_
1910 // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
1911 // the existence of this socket option
1912 xuclen = sizeof(xuc);
1913 if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
1914 { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
1915 if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
1916 LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
1917
1918 if (flags & kDNSServiceFlagsAdd)
1919 {
1920 // register a local-only PRT record
1921 default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
1922 if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
1923 mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
1924 MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
1925 AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
1926 AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
1927 newelem->uid = xuc.cr_uid;
1928 err = mDNS_Register(gmDNS, &newelem->ptr_rec);
1929 if (err) free(newelem);
1930 else
1931 {
1932 // link into list
1933 newelem->next = default_browse_list;
1934 default_browse_list = newelem;
1935 }
1936
1937 }
1938 else
1939 {
1940 // remove - find in list, deregister
1941 default_browse_list_t *ptr = default_browse_list, *prev = NULL;
1942 while (ptr)
1943 {
1944 if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
1945 {
1946 if (prev) prev->next = ptr->next;
1947 else default_browse_list = ptr->next;
1948 err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
1949 break;
1950 }
1951 prev = ptr;
1952 ptr = ptr->next;
1953 }
1954 if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
1955 }
1956 #else
1957 err = mStatus_NoError;
1958 #endif // _HAVE_SETDOMAIN_SUPPORT_
1959
1960 end:
1961 deliver_error(request, err);
1962 abort_request(request);
1963 unlink_request(request);
1964 }
1965
1966 // Generates a response message giving name, type, domain, plus interface index,
1967 // suitable for a browse result or service registration result.
1968 // On successful completion rep is set to point to a malloc'd reply_state struct
GenerateNTDResponse(domainname * servicename,mDNSInterfaceID id,request_state * request,reply_state ** rep)1969 mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
1970 {
1971 domainlabel name;
1972 domainname type, dom;
1973 *rep = NULL;
1974 if (!DeconstructServiceName(servicename, &name, &type, &dom))
1975 return kDNSServiceErr_Invalid;
1976 else
1977 {
1978 char namestr[MAX_DOMAIN_LABEL+1];
1979 char typestr[MAX_ESCAPED_DOMAIN_NAME];
1980 char domstr [MAX_ESCAPED_DOMAIN_NAME];
1981 int len;
1982 char *data;
1983
1984 ConvertDomainLabelToCString_unescaped(&name, namestr);
1985 ConvertDomainNameToCString(&type, typestr);
1986 ConvertDomainNameToCString(&dom, domstr);
1987
1988 // Calculate reply data length
1989 len = sizeof(DNSServiceFlags);
1990 len += sizeof(uint32_t); // if index
1991 len += sizeof(DNSServiceErrorType);
1992 len += (int) (strlen(namestr) + 1);
1993 len += (int) (strlen(typestr) + 1);
1994 len += (int) (strlen(domstr) + 1);
1995
1996 // Build reply header
1997 *rep = create_reply(query_reply_op, len, request);
1998 (*rep)->rhdr->flags = dnssd_htonl(0);
1999 (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
2000 (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
2001
2002 // Build reply body
2003 data = (*rep)->sdata;
2004 put_string(namestr, &data);
2005 put_string(typestr, &data);
2006 put_string(domstr, &data);
2007
2008 return mStatus_NoError;
2009 }
2010 }
2011
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)2012 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
2013 {
2014 request_state *req = question->QuestionContext;
2015 reply_state *rep;
2016 (void)m; // Unused
2017
2018 if (answer->rrtype != kDNSType_PTR)
2019 { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
2020
2021 if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
2022 {
2023 LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
2024 req->sd, answer->name->c, answer->rdata->u.name.c);
2025 return;
2026 }
2027
2028 LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
2029 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
2030
2031 if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
2032 append_reply(req, rep);
2033 }
2034
add_domain_to_browser(browser_info_t * info,const domainname * d)2035 mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
2036 {
2037 browser_t *b, *p;
2038 mStatus err;
2039
2040 for (p = info->browsers; p; p = p->next)
2041 {
2042 if (SameDomainName(&p->domain, d))
2043 { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
2044 }
2045
2046 b = mallocL("browser_t", sizeof(*b));
2047 if (!b) return mStatus_NoMemoryErr;
2048 AssignDomainName(&b->domain, d);
2049 err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
2050 if (err)
2051 {
2052 LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
2053 freeL("browser_t", b);
2054 }
2055 else
2056 {
2057 b->next = info->browsers;
2058 info->browsers = b;
2059 }
2060 return err;
2061 }
2062
handle_browse_request(request_state * request)2063 mDNSlocal void handle_browse_request(request_state *request)
2064 {
2065 DNSServiceFlags flags;
2066 uint32_t interfaceIndex;
2067 mDNSInterfaceID InterfaceID;
2068 char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
2069 domainname typedn, d, temp;
2070 mDNSs32 NumSubTypes;
2071 char *ptr;
2072 mStatus err = mStatus_NoError;
2073 DNameListElem *search_domain_list, *sdom;
2074 browser_info_t *info = NULL;
2075
2076 if (request->ts != t_complete)
2077 {
2078 LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
2079 abort_request(request);
2080 unlink_request(request);
2081 return;
2082 }
2083
2084 // extract data from message
2085 ptr = request->msgdata;
2086 flags = get_flags(&ptr);
2087 interfaceIndex = get_long(&ptr);
2088 if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2089 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
2090 { err = mStatus_BadParamErr; goto error; }
2091 freeL("handle_browse_request", request->msgbuf);
2092 request->msgbuf = NULL;
2093
2094 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
2095 if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
2096
2097 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
2098 if ( !domain || ( domain[0] == '\0' ) )
2099 {
2100 dDNS_RegisterSearchDomains( gmDNS );
2101 }
2102 #endif
2103
2104 typedn.c[0] = 0;
2105 NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
2106 if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
2107 if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
2108 { err = mStatus_BadParamErr; goto error; }
2109
2110 if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
2111
2112 if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
2113 if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
2114
2115 // allocate and set up browser info
2116 info = mallocL("browser_info_t", sizeof(*info));
2117 if (!info) { err = mStatus_NoMemoryErr; goto error; }
2118
2119 request->browser_info = info;
2120 info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
2121 info->interface_id = InterfaceID;
2122 AssignDomainName(&info->regtype, &typedn);
2123 info->rstate = request;
2124 info->default_domain = !domain[0];
2125 info->browsers = NULL;
2126
2127 // setup termination context
2128 request->termination_context = info;
2129 request->terminate = browse_termination_callback;
2130
2131 LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
2132 if (domain[0])
2133 {
2134 if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
2135 err = add_domain_to_browser(info, &d);
2136 }
2137
2138 else
2139 {
2140 search_domain_list = mDNSPlatformGetSearchDomainList();
2141 for (sdom = search_domain_list; sdom; sdom = sdom->next)
2142 {
2143 err = add_domain_to_browser(info, &sdom->name);
2144 if (err)
2145 {
2146 if (SameDomainName(&sdom->name, &localdomain)) break;
2147 else err = mStatus_NoError; // suppress errors for non-local "default" domains
2148 }
2149
2150 }
2151 mDNS_FreeDNameList(search_domain_list);
2152 }
2153
2154 deliver_error(request, err);
2155 return;
2156
2157 error:
2158 if (info) freeL("browser_info_t", info);
2159 if (request->termination_context) request->termination_context = NULL;
2160 deliver_error(request, err);
2161 abort_request(request);
2162 unlink_request(request);
2163 }
2164
browse_termination_callback(void * context)2165 mDNSlocal void browse_termination_callback(void *context)
2166 {
2167 browser_info_t *info = context;
2168 browser_t *ptr;
2169
2170 if (!info) return;
2171
2172 while(info->browsers)
2173 {
2174 ptr = info->browsers;
2175 info->browsers = ptr->next;
2176 LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
2177 mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
2178 freeL("browse_termination_callback", ptr);
2179 }
2180
2181 info->rstate->termination_context = NULL;
2182 freeL("browser_info", info);
2183 }
2184
udsserver_default_browse_domain_changed(const domainname * d,mDNSBool add)2185 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
2186 {
2187 request_state *r;
2188
2189 for (r = all_requests; r; r = r->next)
2190 {
2191 browser_info_t *info = r->browser_info;
2192
2193 if (!info || !info->default_domain) continue;
2194 if (add) add_domain_to_browser(info, d);
2195 else
2196 {
2197 browser_t **ptr = &info->browsers;
2198 while (*ptr)
2199 {
2200 if (SameDomainName(&(*ptr)->domain, d))
2201 {
2202 browser_t *remove = *ptr;
2203 *ptr = (*ptr)->next;
2204 if (remove->q.LongLived)
2205 {
2206 // Give goodbyes for known answers.
2207 // Note that this a special case where we know that the QuestionCallback function is our own
2208 // code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
2209 // don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
2210 CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
2211 while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
2212 }
2213 mDNS_StopBrowse(gmDNS, &remove->q);
2214 freeL("browser_t", remove);
2215 return;
2216 }
2217 ptr = &(*ptr)->next;
2218 }
2219 LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
2220 }
2221 }
2222 }
2223
2224 // Count how many other service records we have locally with the same name, but different rdata.
2225 // For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
2226 // the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
CountPeerRegistrations(mDNS * const m,ServiceRecordSet * const srs)2227 mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
2228 {
2229 int count = 0;
2230 ResourceRecord *r = &srs->RR_SRV.resrec;
2231 AuthRecord *rr;
2232 ServiceRecordSet *s;
2233
2234 for (rr = m->ResourceRecords; rr; rr=rr->next)
2235 if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2236 count++;
2237
2238 for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
2239 if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
2240 count++;
2241
2242 for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
2243 if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
2244 count++;
2245
2246 verbosedebugf("%d peer registrations for %##s", count, r->name->c);
2247 return(count);
2248 }
2249
CountExistingRegistrations(domainname * srv,mDNSIPPort port)2250 mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
2251 {
2252 int count = 0;
2253 AuthRecord *rr;
2254 for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
2255 if (rr->resrec.rrtype == kDNSType_SRV &&
2256 rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
2257 SameDomainName(rr->resrec.name, srv))
2258 count++;
2259 return(count);
2260 }
2261
register_service_instance(request_state * request,const domainname * domain)2262 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
2263 {
2264 service_info *info = request->service_registration;
2265 service_instance *ptr, *instance;
2266 int instance_size;
2267 mStatus result;
2268
2269 for (ptr = info->instances; ptr; ptr = ptr->next)
2270 {
2271 if (SameDomainName(&ptr->domain, domain))
2272 { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
2273 }
2274
2275 instance_size = sizeof(*instance);
2276 if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
2277 instance = mallocL("service_instance", instance_size);
2278 if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
2279
2280 instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
2281 if (info->num_subtypes && !instance->subtypes)
2282 { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
2283 instance->request = request;
2284 instance->sd = request->sd;
2285 instance->autoname = info->autoname;
2286 instance->autorename = info->autorename;
2287 instance->allowremotequery = info->allowremotequery;
2288 instance->rename_on_memfree = 0;
2289 instance->name = info->name;
2290 AssignDomainName(&instance->domain, domain);
2291 instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
2292 result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
2293 info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
2294
2295 if (result) free_service_instance(instance);
2296 else
2297 {
2298 instance->next = info->instances;
2299 info->instances = instance;
2300 }
2301 return result;
2302 }
2303
udsserver_default_reg_domain_changed(const domainname * d,mDNSBool add)2304 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
2305 {
2306 request_state *rstate;
2307 service_info *info;
2308
2309 LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
2310 for (rstate = all_requests; rstate; rstate = rstate->next)
2311 {
2312 if (rstate->terminate != regservice_termination_callback) continue;
2313 info = rstate->service_registration;
2314 if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
2315 if (!info->default_domain) continue;
2316
2317 // valid default registration
2318 if (add) register_service_instance(rstate, d);
2319 else
2320 {
2321 // find the instance to remove
2322 service_instance *si = rstate->service_registration->instances, *prev = NULL;
2323 while (si)
2324 {
2325 if (SameDomainName(&si->domain, d))
2326 {
2327 mStatus err;
2328 if (prev) prev->next = si->next;
2329 else info->instances = si->next;
2330 err = mDNS_DeregisterService(gmDNS, &si->srs);
2331 if (err)
2332 {
2333 LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
2334 free_service_instance(si);
2335 }
2336 break;
2337 }
2338 prev = si;
2339 si = si->next;
2340 }
2341 if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
2342 }
2343 }
2344 }
2345
2346 // service registration
handle_regservice_request(request_state * request)2347 mDNSlocal void handle_regservice_request(request_state *request)
2348 {
2349 DNSServiceFlags flags;
2350 uint32_t ifi;
2351 char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
2352 char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
2353 char *ptr;
2354 domainname d, srv;
2355 mStatus result;
2356 service_info *service = NULL;
2357
2358 if (request->ts != t_complete)
2359 {
2360 LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
2361 abort_request(request);
2362 unlink_request(request);
2363 return;
2364 }
2365
2366 service = mallocL("service_info", sizeof(*service));
2367 if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2368
2369 service->instances = NULL;
2370 service->request = request;
2371 service->txtlen = 0;
2372 service->txtdata = NULL;
2373 request->service_registration = service;
2374 request->termination_context = request->service_registration;
2375 request->terminate = regservice_termination_callback;
2376
2377 // extract data from message
2378 ptr = request->msgdata;
2379 flags = get_flags(&ptr);
2380 ifi = get_long(&ptr);
2381 service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
2382 if (ifi && !service->InterfaceID)
2383 { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
2384 if (get_string(&ptr, name, sizeof(name)) < 0 ||
2385 get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2386 get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
2387 get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
2388 { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
2389
2390 service->port.b[0] = *ptr++;
2391 service->port.b[1] = *ptr++;
2392
2393 service->txtlen = get_short(&ptr);
2394 if (service->txtlen)
2395 {
2396 service->txtdata = mallocL("txtdata", service->txtlen);
2397 if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
2398 memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
2399 }
2400 else service->txtdata = NULL;
2401
2402 // Check for sub-types after the service type
2403 service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
2404 if (service->num_subtypes < 0)
2405 { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
2406
2407 // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
2408 if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
2409 { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
2410
2411 if (!name[0])
2412 {
2413 service->name = (gmDNS)->nicelabel;
2414 service->autoname = mDNStrue;
2415 }
2416 else
2417 {
2418 // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
2419 if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
2420 {
2421 int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
2422 name[newlen] = 0;
2423 }
2424 if (!MakeDomainLabelFromLiteralString(&service->name, name))
2425 { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
2426 service->autoname = mDNSfalse;
2427 }
2428
2429 if (*domain)
2430 {
2431 service->default_domain = mDNSfalse;
2432 if (!MakeDomainNameFromDNSNameString(&d, domain))
2433 { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
2434 }
2435 else
2436 {
2437 service->default_domain = mDNStrue;
2438 MakeDomainNameFromDNSNameString(&d, "local.");
2439 }
2440
2441 if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
2442 { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
2443
2444 if (!MakeDomainNameFromDNSNameString(&service->host, host))
2445 { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
2446 service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
2447 service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
2448
2449 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
2450 // a port number of zero. When two instances of the protected client are allowed to run on one
2451 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
2452 if (service->port.NotAnInteger)
2453 {
2454 int count = CountExistingRegistrations(&srv, service->port);
2455 if (count)
2456 LogMsg("Client application registered %d identical instances of service %##s port %u.",
2457 count+1, srv.c, mDNSVal16(service->port));
2458 }
2459
2460 LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
2461 request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
2462 result = register_service_instance(request, &d);
2463
2464 if (!result && !*domain)
2465 {
2466 DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
2467 for (ptr = def_domains; ptr; ptr = ptr->next)
2468 register_service_instance(request, &ptr->name);
2469 // note that we don't report errors for non-local, non-explicit domains
2470 mDNS_FreeDNameList(def_domains);
2471 }
2472
2473 finish:
2474 deliver_error(request, result);
2475 if (result != mStatus_NoError)
2476 {
2477 abort_request(request);
2478 unlink_request(request);
2479 }
2480 else
2481 reset_connected_rstate(request); // prepare to receive add/remove messages
2482
2483 return;
2484
2485 bad_param:
2486 //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
2487 deliver_error(request, mStatus_BadParamErr);
2488 abort_request(request);
2489 unlink_request(request);
2490 }
2491
2492 // service registration callback performs three duties - frees memory for deregistered services,
2493 // handles name conflicts, and delivers completed registration information to the client (via
2494 // process_service_registraion())
2495
regservice_callback(mDNS * const m,ServiceRecordSet * const srs,mStatus result)2496 mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
2497 {
2498 mStatus err;
2499 mDNSBool SuppressError = mDNSfalse;
2500 service_instance *instance = srs->ServiceContext;
2501 (void)m; // Unused
2502 if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
2503 if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
2504
2505 if (instance->request && instance->request->service_registration)
2506 {
2507 service_info *info = instance->request->service_registration;
2508 if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
2509 // don't send errors up to client for wide-area, empty-string registrations
2510 }
2511
2512 if (result == mStatus_NoError)
2513 LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2514 else if (result == mStatus_MemFree)
2515 LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2516 else if (result == mStatus_NameConflict)
2517 LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
2518 else
2519 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);
2520
2521 if (result == mStatus_NoError)
2522 {
2523 request_state *req = instance->request;
2524 if (instance->allowremotequery)
2525 {
2526 ExtraResourceRecord *e;
2527 srs->RR_ADV.AllowRemoteQuery = mDNStrue;
2528 srs->RR_PTR.AllowRemoteQuery = mDNStrue;
2529 srs->RR_SRV.AllowRemoteQuery = mDNStrue;
2530 srs->RR_TXT.AllowRemoteQuery = mDNStrue;
2531 for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
2532 }
2533
2534 if (!req) LogMsg("ERROR: regservice_callback - null request object");
2535 else
2536 {
2537 reply_state *rep;
2538 if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
2539 LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
2540 else
2541 {
2542 transfer_state send_result = send_msg(rep);
2543 if (send_result == t_error || send_result == t_terminated)
2544 { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
2545 else if (send_result == t_complete) freeL("regservice_callback", rep);
2546 else append_reply(req, rep);
2547 }
2548 }
2549 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2550 RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
2551 return;
2552 }
2553 else if (result == mStatus_MemFree)
2554 {
2555 if (instance->rename_on_memfree)
2556 {
2557 instance->rename_on_memfree = 0;
2558 instance->name = gmDNS->nicelabel;
2559 err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
2560 if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
2561 // error should never happen - safest to log and continue
2562 }
2563 else
2564 {
2565 free_service_instance(instance);
2566 return;
2567 }
2568 }
2569 else if (result == mStatus_NameConflict)
2570 {
2571 if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
2572 {
2573 // On conflict for an autoname service, rename and reregister *all* autoname services
2574 IncrementLabelSuffix(&m->nicelabel, mDNStrue);
2575 m->MainCallback(m, mStatus_ConfigChanged);
2576 }
2577 else if (instance->autoname || instance->autorename)
2578 {
2579 mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
2580 return;
2581 }
2582 else
2583 {
2584 request_state *rs = instance->request;
2585 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2586 free_service_instance(instance);
2587 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2588 {
2589 abort_request(rs);
2590 unlink_request(rs);
2591 }
2592 return;
2593 }
2594 }
2595 else
2596 {
2597 request_state *rs = instance->request;
2598 if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
2599 if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
2600 free_service_instance(instance);
2601 if (!SuppressError && deliver_async_error(rs, reg_service_reply_op, result) < 0)
2602 {
2603 abort_request(rs);
2604 unlink_request(rs);
2605 }
2606 return;
2607 }
2608 }
2609
FreeExtraRR(mDNS * const m,AuthRecord * const rr,mStatus result)2610 mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
2611 {
2612 ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
2613 (void)m; //unused
2614
2615 if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
2616
2617 debugf("%##s: MemFree", rr->resrec.name->c);
2618 if (rr->resrec.rdata != &rr->rdatastorage)
2619 freeL("Extra RData", rr->resrec.rdata);
2620 freeL("ExtraResourceRecord", extra);
2621 }
2622
add_record_to_service(request_state * rstate,service_instance * instance,uint16_t rrtype,uint16_t rdlen,char * rdata,uint32_t ttl)2623 mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
2624 {
2625 ServiceRecordSet *srs = &instance->srs;
2626 ExtraResourceRecord *extra;
2627 mStatus result;
2628 int size;
2629
2630 if (rdlen > sizeof(RDataBody)) size = rdlen;
2631 else size = sizeof(RDataBody);
2632
2633 extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
2634 if (!extra)
2635 {
2636 my_perror("ERROR: malloc");
2637 return mStatus_NoMemoryErr;
2638 }
2639
2640 bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
2641 extra->r.resrec.rrtype = rrtype;
2642 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
2643 extra->r.resrec.rdlength = rdlen;
2644 memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
2645
2646 result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
2647 if (result) { freeL("ExtraResourceRecord", extra); return result; }
2648
2649 extra->ClientID = rstate->hdr.reg_index;
2650 return result;
2651 }
2652
handle_add_request(request_state * rstate)2653 mDNSlocal mStatus handle_add_request(request_state *rstate)
2654 {
2655 uint32_t ttl;
2656 uint16_t rrtype, rdlen;
2657 char *ptr, *rdata;
2658 mStatus result = mStatus_UnknownErr;
2659 DNSServiceFlags flags;
2660 service_info *srvinfo = rstate->service_registration;
2661 service_instance *i;
2662
2663 if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
2664
2665 ptr = rstate->msgdata;
2666 flags = get_flags(&ptr);
2667 rrtype = get_short(&ptr);
2668 rdlen = get_short(&ptr);
2669 rdata = get_rdata(&ptr, rdlen);
2670 ttl = get_long(&ptr);
2671
2672 if (!ttl) ttl = DefaultTTLforRRType(rrtype);
2673
2674 LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
2675 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
2676
2677 for (i = srvinfo->instances; i; i = i->next)
2678 {
2679 result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
2680 if (result && i->default_local) break;
2681 else result = mStatus_NoError; // suppress non-local default errors
2682 }
2683
2684 return(result);
2685 }
2686
update_record(AuthRecord * rr,uint16_t rdlen,char * rdata,uint32_t ttl)2687 mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
2688 {
2689 int rdsize;
2690 RData *newrd;
2691 mStatus result;
2692
2693 if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
2694 else rdsize = sizeof(RDataBody);
2695 newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
2696 if (!newrd) FatalError("ERROR: malloc");
2697 newrd->MaxRDLength = (mDNSu16) rdsize;
2698 memcpy(&newrd->u, rdata, rdlen);
2699
2700 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2701 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2702 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2703 if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
2704
2705 result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
2706 if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
2707 return result;
2708 }
2709
handle_update_request(request_state * rstate)2710 mDNSlocal mStatus handle_update_request(request_state *rstate)
2711 {
2712 uint16_t rdlen;
2713 char *ptr, *rdata;
2714 uint32_t ttl;
2715 mStatus result = mStatus_BadReferenceErr;
2716 service_info *srvinfo = rstate->service_registration;
2717 service_instance *i;
2718 AuthRecord *rr = NULL;
2719
2720 // get the message data
2721 ptr = rstate->msgdata;
2722 get_flags(&ptr); // flags unused
2723 rdlen = get_short(&ptr);
2724 rdata = get_rdata(&ptr, rdlen);
2725 ttl = get_long(&ptr);
2726
2727 if (rstate->reg_recs)
2728 {
2729 // update an individually registered record
2730 registered_record_entry *reptr;
2731 for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
2732 {
2733 if (reptr->key == rstate->hdr.reg_index)
2734 {
2735 result = update_record(reptr->rr, rdlen, rdata, ttl);
2736 goto end;
2737 }
2738 }
2739 result = mStatus_BadReferenceErr;
2740 goto end;
2741 }
2742
2743 // update a record from a service record set
2744 if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
2745 for (i = srvinfo->instances; i; i = i->next)
2746 {
2747 if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
2748 else
2749 {
2750 ExtraResourceRecord *e;
2751 for (e = i->srs.Extras; e; e = e->next)
2752 if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
2753 }
2754
2755 if (!rr) { result = mStatus_BadReferenceErr; goto end; }
2756 result = update_record(rr, rdlen, rdata, ttl);
2757 if (result && i->default_local) goto end;
2758 else result = mStatus_NoError; // suppress non-local default errors
2759 }
2760
2761 end:
2762 LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
2763 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
2764 rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
2765
2766 return(result);
2767 }
2768
update_callback(mDNS * const m,AuthRecord * const rr,RData * oldrd)2769 mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
2770 {
2771 (void)m; // Unused
2772 if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
2773 }
2774
free_service_instance(service_instance * srv)2775 mDNSlocal void free_service_instance(service_instance *srv)
2776 {
2777 request_state *rstate = srv->request;
2778 ExtraResourceRecord *e = srv->srs.Extras, *tmp;
2779
2780 // clear pointers from parent struct
2781 if (rstate)
2782 {
2783 service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
2784 while (ptr)
2785 {
2786 if (ptr == srv)
2787 {
2788 if (prev) prev->next = ptr->next;
2789 else rstate->service_registration->instances = ptr->next;
2790 break;
2791 }
2792 prev = ptr;
2793 ptr = ptr->next;
2794 }
2795 }
2796
2797 while(e)
2798 {
2799 e->r.RecordContext = e;
2800 tmp = e;
2801 e = e->next;
2802 FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
2803 }
2804
2805 if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
2806 freeL("regservice_callback", srv);
2807 }
2808
regservice_termination_callback(void * context)2809 mDNSlocal void regservice_termination_callback(void *context)
2810 {
2811 service_info *info = context;
2812 service_instance *i, *p;
2813 if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
2814 if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
2815 i = info->instances;
2816 while (i)
2817 {
2818 p = i;
2819 i = i->next;
2820 p->request = NULL; // clear back pointer
2821 // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
2822 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));
2823 if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
2824 }
2825 info->request->service_registration = NULL; // clear pointer from request back to info
2826 if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
2827 freeL("service_info", info);
2828 }
2829
handle_regrecord_request(request_state * rstate)2830 mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
2831 {
2832 AuthRecord *rr;
2833 registered_record_entry *re;
2834 mStatus result;
2835
2836 if (rstate->ts != t_complete)
2837 {
2838 LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
2839 abort_request(rstate);
2840 unlink_request(rstate);
2841 return(-1);
2842 }
2843
2844 rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
2845 if (!rr) return(mStatus_BadParamErr);
2846
2847 // allocate registration entry, link into list
2848 re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
2849 if (!re) FatalError("ERROR: malloc");
2850 re->key = rstate->hdr.reg_index;
2851 re->rr = rr;
2852 re->rstate = rstate;
2853 re->client_context = rstate->hdr.client_context;
2854 rr->RecordContext = re;
2855 rr->RecordCallback = regrecord_callback;
2856 re->next = rstate->reg_recs;
2857 rstate->reg_recs = re;
2858
2859 if (!rstate->terminate)
2860 {
2861 rstate->terminate = connected_registration_termination;
2862 rstate->termination_context = rstate;
2863 }
2864
2865 if (rr->resrec.rroriginalttl == 0)
2866 rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
2867
2868 LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
2869 result = mDNS_Register(gmDNS, rr);
2870 return(result);
2871 }
2872
regrecord_callback(mDNS * const m,AuthRecord * rr,mStatus result)2873 mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
2874 {
2875 registered_record_entry *re = rr->RecordContext;
2876 request_state *rstate = re ? re->rstate : NULL;
2877 int len;
2878 reply_state *reply;
2879 transfer_state ts;
2880 (void)m; // Unused
2881
2882 if (!re)
2883 {
2884 // parent struct alreadt freed by termination callback
2885 if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
2886 else
2887 {
2888 if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
2889 freeL("regrecord_callback", rr);
2890 }
2891 return;
2892 }
2893
2894 // format result, add to the list for the request, including the client context in the header
2895 len = sizeof(DNSServiceFlags);
2896 len += sizeof(uint32_t); //interfaceIndex
2897 len += sizeof(DNSServiceErrorType);
2898
2899 reply = create_reply(reg_record_reply_op, len, rstate);
2900 reply->mhdr->client_context = re->client_context;
2901 reply->rhdr->flags = dnssd_htonl(0);
2902 reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
2903 reply->rhdr->error = dnssd_htonl(result);
2904
2905 if (result)
2906 {
2907 // unlink from list, free memory
2908 registered_record_entry **ptr = &re->rstate->reg_recs;
2909 while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
2910 if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
2911 *ptr = (*ptr)->next;
2912 freeL("regrecord_callback", re->rr);
2913 re->rr = rr = NULL;
2914 freeL("regrecord_callback", re);
2915 re = NULL;
2916 }
2917
2918 ts = send_msg(reply);
2919
2920 if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
2921 else if (ts == t_complete) freeL("regrecord_callback", reply);
2922 else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
2923 }
2924
connected_registration_termination(void * context)2925 mDNSlocal void connected_registration_termination(void *context)
2926 {
2927 int shared;
2928 registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
2929 while(ptr)
2930 {
2931 fptr = ptr;
2932 ptr = ptr->next;
2933 shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
2934 fptr->rr->RecordContext = NULL;
2935 mDNS_Deregister(gmDNS, fptr->rr);
2936 freeL("connected_registration_termination", fptr);
2937 }
2938 }
2939
handle_removerecord_request(request_state * rstate)2940 mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
2941 {
2942 mStatus err = mStatus_BadReferenceErr;
2943 char *ptr;
2944 service_info *srvinfo = rstate->service_registration;
2945
2946 ptr = rstate->msgdata;
2947 get_flags(&ptr); // flags unused
2948
2949 if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
2950 else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
2951 else
2952 {
2953 service_instance *i;
2954 LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
2955 (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
2956 for (i = srvinfo->instances; i; i = i->next)
2957 {
2958 err = remove_extra(rstate, i);
2959 if (err && i->default_local) break;
2960 else err = mStatus_NoError; // suppress non-local default errors
2961 }
2962 }
2963
2964 return(err);
2965 }
2966
2967 // remove a resource record registered via DNSServiceRegisterRecord()
remove_record(request_state * rstate)2968 mDNSlocal mStatus remove_record(request_state *rstate)
2969 {
2970 int shared;
2971 mStatus err = mStatus_UnknownErr;
2972 registered_record_entry *e, **ptr = &rstate->reg_recs;
2973
2974 while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
2975 if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
2976 e = *ptr;
2977 *ptr = e->next; // unlink
2978
2979 LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
2980 shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
2981 e->rr->RecordContext = NULL;
2982 err = mDNS_Deregister(gmDNS, e->rr);
2983 if (err)
2984 {
2985 LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
2986 freeL("remove_record", e->rr);
2987 freeL("remove_record", e);
2988 }
2989 return err;
2990 }
2991
remove_extra(request_state * rstate,service_instance * serv)2992 mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
2993 {
2994 mStatus err = mStatus_BadReferenceErr;
2995 ExtraResourceRecord *ptr;
2996
2997 for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
2998 {
2999 if (ptr->ClientID == rstate->hdr.reg_index) // found match
3000 return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
3001 }
3002 return err;
3003 }
3004
3005 // domain enumeration
handle_enum_request(request_state * rstate)3006 mDNSlocal void handle_enum_request(request_state *rstate)
3007 {
3008 DNSServiceFlags flags;
3009 uint32_t ifi;
3010 mDNSInterfaceID InterfaceID;
3011 char *ptr = rstate->msgdata;
3012 domain_enum_t *def, *all;
3013 enum_termination_t *term;
3014 mStatus err;
3015 int result;
3016
3017 if (rstate->ts != t_complete)
3018 {
3019 LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
3020 abort_request(rstate);
3021 unlink_request(rstate);
3022 return;
3023 }
3024
3025 flags = get_flags(&ptr);
3026 ifi = get_long(&ptr);
3027 InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
3028 if (ifi && !InterfaceID)
3029 {
3030 deliver_error(rstate, mStatus_BadParamErr);
3031 abort_request(rstate);
3032 unlink_request(rstate);
3033 return;
3034 }
3035
3036 // allocate context structures
3037 def = mallocL("handle_enum_request", sizeof(domain_enum_t));
3038 all = mallocL("handle_enum_request", sizeof(domain_enum_t));
3039 term = mallocL("handle_enum_request", sizeof(enum_termination_t));
3040 if (!def || !all || !term) FatalError("ERROR: malloc");
3041
3042 #if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
3043 dDNS_RegisterSearchDomains( gmDNS );
3044 #endif
3045
3046 // enumeration requires multiple questions, so we must link all the context pointers so that
3047 // necessary context can be reached from the callbacks
3048 def->rstate = rstate;
3049 all->rstate = rstate;
3050 term->def = def;
3051 term->all = all;
3052 term->rstate = rstate;
3053 rstate->termination_context = term;
3054 rstate->terminate = enum_termination_callback;
3055 def->question.QuestionContext = def;
3056 def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3057 mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
3058 all->question.QuestionContext = all;
3059 all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
3060 mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
3061
3062 // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
3063 if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
3064
3065 // make the calls
3066 LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
3067 (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
3068 (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
3069 err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
3070 if (err == mStatus_NoError)
3071 err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
3072 result = deliver_error(rstate, err); // send error *before* returning local domain
3073
3074 if (result < 0 || err)
3075 {
3076 abort_request(rstate);
3077 unlink_request(rstate);
3078 return;
3079 }
3080 }
3081
enum_result_callback(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)3082 mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
3083 {
3084 char domain[MAX_ESCAPED_DOMAIN_NAME];
3085 domain_enum_t *de = question->QuestionContext;
3086 DNSServiceFlags flags = 0;
3087 reply_state *reply;
3088 (void)m; // Unused
3089
3090 if (answer->rrtype != kDNSType_PTR) return;
3091 if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
3092
3093 if (AddRecord)
3094 {
3095 flags |= kDNSServiceFlagsAdd;
3096 if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
3097 flags |= kDNSServiceFlagsDefault;
3098 }
3099 ConvertDomainNameToCString(&answer->rdata->u.name, domain);
3100 // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
3101 // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
3102 // network, so we just pass kDNSServiceInterfaceIndexAny
3103 reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
3104 if (!reply)
3105 {
3106 LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
3107 return;
3108 }
3109 reply->next = NULL;
3110 append_reply(de->rstate, reply);
3111 return;
3112 }
3113
format_enumeration_reply(request_state * rstate,const char * domain,DNSServiceFlags flags,uint32_t ifi,DNSServiceErrorType err)3114 mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
3115 {
3116 size_t len;
3117 reply_state *reply;
3118 char *data;
3119
3120 len = sizeof(DNSServiceFlags);
3121 len += sizeof(uint32_t);
3122 len += sizeof(DNSServiceErrorType);
3123 len += strlen(domain) + 1;
3124
3125 reply = create_reply(enumeration_reply_op, len, rstate);
3126 reply->rhdr->flags = dnssd_htonl(flags);
3127 reply->rhdr->ifi = dnssd_htonl(ifi);
3128 reply->rhdr->error = dnssd_htonl(err);
3129 data = reply->sdata;
3130 put_string(domain, &data);
3131 return reply;
3132 }
3133
enum_termination_callback(void * context)3134 mDNSlocal void enum_termination_callback(void *context)
3135 {
3136 enum_termination_t *t = context;
3137 mDNS *coredata = gmDNS;
3138
3139 mDNS_StopGetDomains(coredata, &t->all->question);
3140 mDNS_StopGetDomains(coredata, &t->def->question);
3141 freeL("enum_termination_callback", t->all);
3142 freeL("enum_termination_callback", t->def);
3143 t->rstate->termination_context = NULL;
3144 freeL("enum_termination_callback", t);
3145 }
3146
handle_reconfirm_request(request_state * rstate)3147 mDNSlocal void handle_reconfirm_request(request_state *rstate)
3148 {
3149 AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
3150 if (rr)
3151 {
3152 mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
3153 LogOperation(
3154 (status == mStatus_NoError) ?
3155 "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
3156 "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
3157 rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
3158 mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
3159 status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
3160 }
3161 abort_request(rstate);
3162 unlink_request(rstate);
3163 freeL("handle_reconfirm_request", rr);
3164 }
3165
3166 // setup rstate to accept new reg/dereg requests
reset_connected_rstate(request_state * rstate)3167 mDNSlocal void reset_connected_rstate(request_state *rstate)
3168 {
3169 rstate->ts = t_morecoming;
3170 rstate->hdr_bytes = 0;
3171 rstate->data_bytes = 0;
3172 if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
3173 rstate->msgbuf = NULL;
3174 rstate->bufsize = 0;
3175 }
3176
3177 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
3178 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
3179 // (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
read_rr_from_ipc_msg(char * msgbuf,int GetTTL,int validate_flags)3180 mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
3181 {
3182 char *rdata, name[256];
3183 AuthRecord *rr;
3184 DNSServiceFlags flags;
3185 uint32_t interfaceIndex;
3186 uint16_t type, class, rdlen;
3187 int storage_size;
3188
3189 flags = get_flags(&msgbuf);
3190 if (validate_flags &&
3191 !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
3192 !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
3193 {
3194 LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
3195 return NULL;
3196 }
3197
3198 interfaceIndex = get_long(&msgbuf);
3199 if (get_string(&msgbuf, name, 256) < 0)
3200 {
3201 LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
3202 return NULL;
3203 }
3204 type = get_short(&msgbuf);
3205 class = get_short(&msgbuf);
3206 rdlen = get_short(&msgbuf);
3207
3208 if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
3209 else storage_size = sizeof(RDataBody);
3210
3211 rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
3212 if (!rr) FatalError("ERROR: malloc");
3213 bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
3214
3215 mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
3216 type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
3217
3218 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
3219 {
3220 LogMsg("ERROR: bad name: %s", name);
3221 freeL("read_rr_from_ipc_msg", rr);
3222 return NULL;
3223 }
3224
3225 if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
3226 rr->resrec.rrclass = class;
3227 rr->resrec.rdlength = rdlen;
3228 rr->resrec.rdata->MaxRDLength = rdlen;
3229 rdata = get_rdata(&msgbuf, rdlen);
3230 memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
3231 if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
3232 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
3233 SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
3234 return rr;
3235 }
3236
build_domainname_from_strings(domainname * srv,char * name,char * regtype,char * domain)3237 mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
3238 {
3239 domainlabel n;
3240 domainname d, t;
3241
3242 if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
3243 if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
3244 if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
3245 if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
3246 return 0;
3247 }
3248
3249 // append a reply to the list in a request object
append_reply(request_state * req,reply_state * rep)3250 mDNSlocal void append_reply(request_state *req, reply_state *rep)
3251 {
3252 reply_state *ptr;
3253
3254 if (!req->replies) req->replies = rep;
3255 else
3256 {
3257 ptr = req->replies;
3258 while (ptr->next) ptr = ptr->next;
3259 ptr->next = rep;
3260 }
3261 rep->next = NULL;
3262 }
3263
3264 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
3265 // returns the current state of the request (morecoming, error, complete, terminated.)
3266 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
read_msg(request_state * rs)3267 mDNSlocal int read_msg(request_state *rs)
3268 {
3269 uint32_t nleft;
3270 int nread;
3271 char buf[4]; // dummy for death notification
3272
3273 if (rs->ts == t_terminated || rs->ts == t_error)
3274 {
3275 LogMsg("ERROR: read_msg called with transfer state terminated or error");
3276 rs->ts = t_error;
3277 return t_error;
3278 }
3279
3280 if (rs->ts == t_complete)
3281 { // this must be death or something is wrong
3282 nread = recv(rs->sd, buf, 4, 0);
3283 if (!nread) { rs->ts = t_terminated; return t_terminated; }
3284 if (nread < 0) goto rerror;
3285 LogMsg("ERROR: read data from a completed request.");
3286 rs->ts = t_error;
3287 return t_error;
3288 }
3289
3290 if (rs->ts != t_morecoming)
3291 {
3292 LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
3293 rs->ts = t_error;
3294 return t_error;
3295 }
3296
3297 if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
3298 {
3299 nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
3300 nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
3301 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3302 if (nread < 0) goto rerror;
3303 rs->hdr_bytes += nread;
3304 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3305 {
3306 ConvertHeaderBytes(&rs->hdr);
3307 if (rs->hdr.version != VERSION)
3308 {
3309 LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
3310 rs->ts = t_error;
3311 return t_error;
3312 }
3313 }
3314 if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
3315 {
3316 LogMsg("ERROR: read_msg - read too many header bytes");
3317 rs->ts = t_error;
3318 return t_error;
3319 }
3320 }
3321
3322 // only read data if header is complete
3323 if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
3324 {
3325 if (rs->hdr.datalen == 0) // ok in removerecord requests
3326 {
3327 rs->ts = t_complete;
3328 rs->msgbuf = NULL;
3329 return t_complete;
3330 }
3331
3332 if (!rs->msgbuf) // allocate the buffer first time through
3333 {
3334 rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
3335 if (!rs->msgbuf)
3336 {
3337 my_perror("ERROR: malloc");
3338 rs->ts = t_error;
3339 return t_error;
3340 }
3341 rs->msgdata = rs->msgbuf;
3342 bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
3343 }
3344 nleft = rs->hdr.datalen - rs->data_bytes;
3345 nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
3346 if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
3347 if (nread < 0) goto rerror;
3348 rs->data_bytes += nread;
3349 if (rs->data_bytes > rs->hdr.datalen)
3350 {
3351 LogMsg("ERROR: read_msg - read too many data bytes");
3352 rs->ts = t_error;
3353 return t_error;
3354 }
3355 }
3356
3357 if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
3358 rs->ts = t_complete;
3359 else rs->ts = t_morecoming;
3360
3361 return rs->ts;
3362
3363 rerror:
3364 if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
3365 my_perror("ERROR: read_msg");
3366 rs->ts = t_error;
3367 return t_error;
3368 }
3369
send_msg(reply_state * rs)3370 mDNSlocal int send_msg(reply_state *rs)
3371 {
3372 ssize_t nwriten;
3373
3374 if (!rs->msgbuf)
3375 {
3376 LogMsg("ERROR: send_msg called with NULL message buffer");
3377 return t_error;
3378 }
3379
3380 if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
3381 {
3382 rs->ts = t_complete;
3383 freeL("send_msg", rs->msgbuf);
3384 return t_complete;
3385 }
3386
3387 ConvertHeaderBytes(rs->mhdr);
3388 nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
3389 ConvertHeaderBytes(rs->mhdr);
3390 if (nwriten < 0)
3391 {
3392 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
3393 else
3394 {
3395 #if !defined(PLATFORM_NO_EPIPE)
3396 if (dnssd_errno() == EPIPE)
3397 {
3398 debugf("%3d: broken pipe", rs->sd);
3399 rs->ts = t_terminated;
3400 rs->request->ts = t_terminated;
3401 return t_terminated;
3402 }
3403 else
3404 #endif
3405 {
3406 my_perror("ERROR: send\n");
3407 rs->ts = t_error;
3408 return t_error;
3409 }
3410 }
3411 }
3412 rs->nwriten += nwriten;
3413
3414 if (rs->nwriten == rs->len)
3415 {
3416 rs->ts = t_complete;
3417 freeL("send_msg", rs->msgbuf);
3418 }
3419 return rs->ts;
3420 }
3421
create_reply(reply_op_t op,size_t datalen,request_state * request)3422 mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
3423 {
3424 reply_state *reply;
3425 int totallen;
3426
3427 if ((unsigned)datalen < sizeof(reply_hdr))
3428 {
3429 LogMsg("ERROR: create_reply - data length less than lenght of required fields");
3430 return NULL;
3431 }
3432
3433 totallen = (int) (datalen + sizeof(ipc_msg_hdr));
3434 reply = mallocL("create_reply", sizeof(reply_state));
3435 if (!reply) FatalError("ERROR: malloc");
3436 bzero(reply, sizeof(reply_state));
3437 reply->ts = t_morecoming;
3438 reply->sd = request->sd;
3439 reply->request = request;
3440 reply->len = totallen;
3441 reply->msgbuf = mallocL("create_reply", totallen);
3442 if (!reply->msgbuf) FatalError("ERROR: malloc");
3443 bzero(reply->msgbuf, totallen);
3444 reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
3445 reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
3446 reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
3447 reply->mhdr->version = VERSION;
3448 reply->mhdr->op = op;
3449 reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
3450 return reply;
3451 }
3452
deliver_error(request_state * rstate,mStatus err)3453 mDNSlocal int deliver_error(request_state *rstate, mStatus err)
3454 {
3455 int nwritten = -1;
3456 undelivered_error_t *undeliv;
3457
3458 err = dnssd_htonl(err);
3459 nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
3460 if (nwritten < (int)sizeof(mStatus))
3461 {
3462 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3463 nwritten = 0;
3464 if (nwritten < 0)
3465 {
3466 my_perror("ERROR: send - unable to deliver error to client");
3467 return(-1);
3468 }
3469 else
3470 {
3471 //client blocked - store result and come backr
3472 undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
3473 if (!undeliv) FatalError("ERROR: malloc");
3474 undeliv->err = err;
3475 undeliv->nwritten = nwritten;
3476 undeliv->sd = rstate->sd;
3477 rstate->u_err = undeliv;
3478 return 0;
3479 }
3480 }
3481 return 0;
3482 }
3483
3484 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
send_undelivered_error(request_state * rs)3485 mDNSlocal transfer_state send_undelivered_error(request_state *rs)
3486 {
3487 int nwritten;
3488
3489 nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
3490 if (nwritten < 0)
3491 {
3492 if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
3493 nwritten = 0;
3494 else
3495 {
3496 my_perror("ERROR: send - unable to deliver error to client\n");
3497 return t_error;
3498 }
3499 }
3500 if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
3501 {
3502 freeL("send_undelivered_error", rs->u_err);
3503 rs->u_err = NULL;
3504 return t_complete;
3505 }
3506 rs->u_err->nwritten += nwritten;
3507 return t_morecoming;
3508 }
3509
3510 // send bogus data along with an error code to the app callback
3511 // returns 0 on success (linking reply into list of not fully delivered),
3512 // -1 on failure (request should be aborted)
deliver_async_error(request_state * rs,reply_op_t op,mStatus err)3513 mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
3514 {
3515 int len;
3516 reply_state *reply;
3517 transfer_state ts;
3518
3519 if (rs->no_reply) return 0;
3520 len = 256; // long enough for any reply handler to read all args w/o buffer overrun
3521 reply = create_reply(op, len, rs);
3522 reply->rhdr->error = dnssd_htonl(err);
3523 ts = send_msg(reply);
3524 if (ts == t_error || ts == t_terminated)
3525 {
3526 freeL("deliver_async_error", reply);
3527 return -1;
3528 }
3529 else if (ts == t_complete) freeL("deliver_async_error", reply);
3530 else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
3531 return 0;
3532 }
3533
abort_request(request_state * rs)3534 mDNSlocal void abort_request(request_state *rs)
3535 {
3536 reply_state *rep, *ptr;
3537
3538 if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
3539 if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
3540 LogOperation("%3d: Removing FD", rs->sd);
3541 udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
3542
3543 // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
3544 // for detecting when the memory for an object is inadvertently freed while the object is still on some list
3545 rs->sd = -2;
3546
3547 // free pending replies
3548 rep = rs->replies;
3549 while(rep)
3550 {
3551 if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
3552 ptr = rep;
3553 rep = rep->next;
3554 freeL("abort_request", ptr);
3555 }
3556
3557 if (rs->u_err)
3558 {
3559 freeL("abort_request", rs->u_err);
3560 rs->u_err = NULL;
3561 }
3562 }
3563
unlink_request(request_state * rs)3564 mDNSlocal void unlink_request(request_state *rs)
3565 {
3566 request_state *ptr;
3567
3568 if (rs == all_requests)
3569 {
3570 all_requests = all_requests->next;
3571 freeL("unlink_request", rs);
3572 return;
3573 }
3574 for(ptr = all_requests; ptr->next; ptr = ptr->next)
3575 if (ptr->next == rs)
3576 {
3577 ptr->next = rs->next;
3578 freeL("unlink_request", rs);
3579 return;
3580 }
3581 }
3582
3583 //hack to search-replace perror's to LogMsg's
my_perror(char * errmsg)3584 mDNSlocal void my_perror(char *errmsg)
3585 {
3586 LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
3587 }
3588
3589 // check that the message delivered by the client is sufficiently long to extract the required data from the buffer
3590 // without overrunning it.
3591 // returns 0 on success, -1 on error.
3592
validate_message(request_state * rstate)3593 mDNSlocal int validate_message(request_state *rstate)
3594 {
3595 uint32_t min_size;
3596
3597 switch(rstate->hdr.op)
3598 {
3599 case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
3600 sizeof(uint32_t) + // interface
3601 (3 * sizeof(char)); // name, regtype, domain
3602 break;
3603 case query_request: min_size = sizeof(DNSServiceFlags) + // flags
3604 sizeof(uint32_t) + // interface
3605 sizeof(char) + // fullname
3606 (2 * sizeof(uint16_t)); // type, class
3607 break;
3608 case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
3609 sizeof(uint32_t) + // interface
3610 (2 * sizeof(char)); // regtype, domain
3611 break;
3612 case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
3613 sizeof(uint32_t) + // interface
3614 (4 * sizeof(char)) + // name, type, domain, host
3615 (2 * sizeof(uint16_t)); // port, textlen
3616 break;
3617 case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
3618 sizeof(uint32_t); // interface
3619 break;
3620 case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3621 sizeof(uint32_t) + // interface
3622 sizeof(char) + // fullname
3623 (3 * sizeof(uint16_t)) + // type, class, rdlen
3624 sizeof(uint32_t); // ttl
3625 break;
3626 case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3627 (2 * sizeof(uint16_t)) + // type, rdlen
3628 sizeof(uint32_t); // ttl
3629 break;
3630 case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
3631 sizeof(uint16_t) + // rdlen
3632 sizeof(uint32_t); // ttl
3633 break;
3634 case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
3635 break;
3636 case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
3637 sizeof(uint32_t) + // interface
3638 sizeof(char) + // fullname
3639 (3 * sizeof(uint16_t)); // type, class, rdlen
3640 break;
3641 case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
3642 break;
3643 default:
3644 LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
3645 return -1;
3646 }
3647
3648 return (rstate->data_bytes >= min_size ? 0 : -1);
3649
3650 }
3651
dnssd_htonl(uint32_t l)3652 mDNSlocal uint32_t dnssd_htonl(uint32_t l)
3653 {
3654 uint32_t ret;
3655 char * data;
3656
3657 data = (char*) &ret;
3658
3659 put_long(l, &data);
3660
3661 return ret;
3662 }
3663
3664 #if defined(_WIN32)
3665
win32_strerror(int inErrorCode)3666 mDNSlocal char * win32_strerror(int inErrorCode)
3667 {
3668 static char buffer[1024];
3669 DWORD n;
3670
3671 memset(buffer, 0, sizeof(buffer));
3672
3673 n = FormatMessageA(
3674 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
3675 NULL,
3676 (DWORD) inErrorCode,
3677 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
3678 buffer,
3679 sizeof( buffer ),
3680 NULL );
3681
3682 if( n > 0 )
3683 {
3684 // Remove any trailing CR's or LF's since some messages have them.
3685
3686 while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
3687 {
3688 buffer[ --n ] = '\0';
3689 }
3690 }
3691
3692 return buffer;
3693 }
3694
3695 #endif
3696