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