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