1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-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 * This code is completely 100% portable C. It does not depend on any external header files 18 * from outside the mDNS project -- all the types it expects to find are defined right here. 19 * 20 * The previous point is very important: This file does not depend on any external 21 * header files. It should complile on *any* platform that has a C compiler, without 22 * making *any* assumptions about availability of so-called "standard" C functions, 23 * routines, or types (which may or may not be present on any given platform). 24 25 * Formatting notes: 26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion 27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, 28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially 29 * part of an "if" statement; they are the beginning and ending markers of a compound statement; 30 * therefore common sense dictates that if they are part of a compound statement then they 31 * should be indented to the same level as everything else in that compound statement. 32 * Indenting curly braces at the same level as the "if" implies that curly braces are 33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" 34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't 35 * understand why variable y is not of type "char*" just proves the point that poor code 36 * layout leads people to unfortunate misunderstandings about how the C language really works.) 37 38 Change History (most recent first): 39 40 $Log: mDNS.c,v $ 41 Revision 1.537.2.1 2006/08/29 06:24:22 cheshire 42 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 43 44 Revision 1.537 2006/03/19 02:00:07 cheshire 45 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions 46 47 Revision 1.536 2006/03/08 23:29:53 cheshire 48 <rdar://problem/4468716> Improve "Service Renamed" log message 49 50 Revision 1.535 2006/03/02 20:41:17 cheshire 51 <rdar://problem/4111464> After record update, old record sometimes remains in cache 52 Minor code tidying and comments to reduce the risk of similar programming errors in future 53 54 Revision 1.534 2006/03/02 03:25:46 cheshire 55 <rdar://problem/4111464> After record update, old record sometimes remains in cache 56 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records 57 58 Revision 1.533 2006/02/26 00:54:41 cheshire 59 Fixes to avoid code generation warning/error on FreeBSD 7 60 61 Revision 1.532 2005/12/02 20:24:36 cheshire 62 <rdar://problem/4363209> Adjust cutoff time for KA list by one second 63 64 Revision 1.531 2005/12/02 19:05:42 cheshire 65 Tidy up constants 66 67 Revision 1.530 2005/11/07 01:49:48 cheshire 68 For consistency, use NonZeroTime() function instead of ?: expression 69 70 Revision 1.529 2005/10/25 23:42:24 cheshire 71 <rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match 72 Changed switch statement to an "if" 73 74 Revision 1.528 2005/10/25 23:34:22 cheshire 75 <rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep 76 77 Revision 1.527 2005/10/25 22:43:59 cheshire 78 Add clarifying comments 79 80 Revision 1.526 2005/10/20 00:10:33 cheshire 81 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code 82 83 Revision 1.525 2005/09/24 00:47:17 cheshire 84 Fix comment typos 85 86 Revision 1.524 2005/09/16 21:06:49 cheshire 87 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place 88 89 Revision 1.523 2005/03/21 00:33:51 shersche 90 <rdar://problem/4021486> Fix build warnings on Win32 platform 91 92 Revision 1.522 2005/03/04 21:48:12 cheshire 93 <rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity 94 95 Revision 1.521 2005/02/25 04:21:00 cheshire 96 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing 97 98 Revision 1.520 2005/02/16 01:14:11 cheshire 99 Convert RR Cache LogOperation() calls to debugf() 100 101 Revision 1.519 2005/02/15 01:57:20 cheshire 102 When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero 103 104 Revision 1.518 2005/02/10 22:35:17 cheshire 105 <rdar://problem/3727944> Update name 106 107 Revision 1.517 2005/02/03 00:21:21 cheshire 108 Update comments about BIND named and zero-length TXT records 109 110 Revision 1.516 2005/01/28 06:06:32 cheshire 111 Update comment 112 113 Revision 1.515 2005/01/27 00:21:49 cheshire 114 <rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message 115 116 Revision 1.514 2005/01/21 01:33:45 cheshire 117 <rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM 118 119 Revision 1.513 2005/01/21 00:07:54 cheshire 120 <rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict 121 122 Revision 1.512 2005/01/20 00:37:45 cheshire 123 <rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse 124 Take care not to recycle records while they are on the CacheFlushRecords list 125 126 Revision 1.511 2005/01/19 22:48:53 cheshire 127 <rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService() 128 129 Revision 1.510 2005/01/19 03:12:45 cheshire 130 Move LocalRecordReady() macro from mDNS.c to DNSCommon.h 131 132 Revision 1.509 2005/01/19 03:08:49 cheshire 133 <rdar://problem/3961051> CPU Spin in mDNSResponder 134 Log messages to help catch and report CPU spins 135 136 Revision 1.508 2005/01/18 18:56:32 cheshire 137 <rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate 138 139 Revision 1.507 2005/01/18 01:12:07 cheshire 140 <rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes 141 142 Revision 1.506 2005/01/17 23:28:53 cheshire 143 Fix compile error 144 145 Revision 1.505 2005/01/11 02:02:56 shersche 146 Move variable declaration to the beginning of statement block 147 148 Revision 1.504 2004/12/20 20:24:35 cheshire 149 <rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer 150 151 Revision 1.503 2004/12/20 18:41:47 cheshire 152 <rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space 153 154 Revision 1.502 2004/12/20 18:04:08 cheshire 155 <rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache 156 157 Revision 1.501 2004/12/19 23:50:18 cheshire 158 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records 159 Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services 160 161 Revision 1.500 2004/12/18 03:13:46 cheshire 162 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records 163 164 Revision 1.499 2004/12/17 23:37:45 cheshire 165 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association 166 (and other repetitive configuration changes) 167 168 Revision 1.498 2004/12/17 05:25:46 cheshire 169 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs 170 171 Revision 1.497 2004/12/17 03:20:58 cheshire 172 <rdar://problem/3925168> Don't send unicast replies we know will be ignored 173 174 Revision 1.496 2004/12/16 22:18:26 cheshire 175 Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces 176 177 Revision 1.495 2004/12/16 21:27:37 ksekar 178 Fixed build failures when compiled with verbose debugging messages 179 180 Revision 1.494 2004/12/16 20:46:56 cheshire 181 Fix compiler warnings 182 183 Revision 1.493 2004/12/16 20:13:00 cheshire 184 <rdar://problem/3324626> Cache memory management improvements 185 186 Revision 1.492 2004/12/16 08:03:24 shersche 187 Fix compilation error when UNICAST_DISABLED is set 188 189 Revision 1.491 2004/12/11 01:52:11 cheshire 190 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too 191 192 Revision 1.490 2004/12/10 20:06:25 cheshire 193 <rdar://problem/3915074> Reduce egregious stack space usage 194 Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes 195 196 Revision 1.489 2004/12/10 20:03:43 cheshire 197 <rdar://problem/3915074> Reduce egregious stack space usage 198 Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes 199 200 Revision 1.488 2004/12/10 19:50:41 cheshire 201 <rdar://problem/3915074> Reduce egregious stack space usage 202 Reduced SendResponses() stack frame from 9K to 176 bytes 203 204 Revision 1.487 2004/12/10 19:39:13 cheshire 205 <rdar://problem/3915074> Reduce egregious stack space usage 206 Reduced SendQueries() stack frame from 18K to 112 bytes 207 208 Revision 1.486 2004/12/10 14:16:17 cheshire 209 <rdar://problem/3889788> Relax update rate limiting 210 We now allow an average rate of ten updates per minute. 211 Updates in excess of that are rate limited, but more gently than before. 212 213 Revision 1.485 2004/12/10 02:09:24 cheshire 214 <rdar://problem/3898376> Modify default TTLs 215 216 Revision 1.484 2004/12/09 03:15:40 ksekar 217 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains 218 219 Revision 1.483 2004/12/07 23:00:14 ksekar 220 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration: 221 Call RecordProbeFailure even if there is no record callback 222 223 Revision 1.482 2004/12/07 22:49:06 cheshire 224 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records 225 226 Revision 1.481 2004/12/07 21:26:04 ksekar 227 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration 228 229 Revision 1.480 2004/12/07 20:42:33 cheshire 230 Add explicit context parameter to mDNS_RemoveRecordFromService() 231 232 Revision 1.479 2004/12/07 17:50:49 ksekar 233 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records 234 235 Revision 1.478 2004/12/06 21:15:22 ksekar 236 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations 237 238 Revision 1.477 2004/12/04 02:12:45 cheshire 239 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack 240 241 Revision 1.476 2004/11/29 23:34:31 cheshire 242 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero 243 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function 244 only nudges the time value to 1 if the interval calculation happens to result in the value zero. 245 246 Revision 1.475 2004/11/29 23:13:31 cheshire 247 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set 248 Additional check: Make sure we don't unnecessarily send packets containing only additionals. 249 (This could occur with multi-packet KA lists, if the answer and additionals were marked 250 by the query packet, and then the answer were later suppressed in a subsequent KA packet.) 251 252 Revision 1.474 2004/11/29 17:18:12 cheshire 253 Remove "Unknown DNS packet type" message for update responses 254 255 Revision 1.473 2004/11/25 01:57:52 cheshire 256 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set 257 258 Revision 1.472 2004/11/25 01:28:09 cheshire 259 <rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too) 260 261 Revision 1.471 2004/11/25 01:10:13 cheshire 262 Move code to add additional records to a subroutine called AddAdditionalsToResponseList() 263 264 Revision 1.470 2004/11/24 21:54:44 cheshire 265 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly 266 267 Revision 1.469 2004/11/24 04:50:39 cheshire 268 Minor tidying 269 270 Revision 1.468 2004/11/24 01:47:07 cheshire 271 <rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success. 272 273 Revision 1.467 2004/11/24 01:41:28 cheshire 274 Rename CompleteProbing() to AcknowledgeRecord() 275 276 Revision 1.466 2004/11/23 21:08:07 ksekar 277 Don't use ID to demux multicast/unicast now that unicast uses random IDs 278 279 Revision 1.465 2004/11/15 20:09:21 ksekar 280 <rdar://problem/3719050> Wide Area support for Add/Remove record 281 282 Revision 1.464 2004/11/03 01:44:36 cheshire 283 Update debugging messages 284 285 Revision 1.463 2004/10/29 02:38:48 cheshire 286 Fix Windows compile errors 287 288 Revision 1.462 2004/10/28 19:21:07 cheshire 289 Guard against registering interface with zero InterfaceID 290 291 Revision 1.461 2004/10/28 19:02:16 cheshire 292 Remove \n from LogMsg() call 293 294 Revision 1.460 2004/10/28 03:24:40 cheshire 295 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 296 297 Revision 1.459 2004/10/26 22:34:37 cheshire 298 <rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding 299 300 Revision 1.458 2004/10/26 20:45:28 cheshire 301 Show mask in "invalid mask" message 302 303 Revision 1.457 2004/10/26 06:28:36 cheshire 304 Now that we don't check IP TTL any more, remove associated log message 305 306 Revision 1.456 2004/10/26 06:21:42 cheshire 307 Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address) 308 309 Revision 1.455 2004/10/26 06:11:40 cheshire 310 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed 311 312 Revision 1.454 2004/10/23 01:16:00 cheshire 313 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts 314 315 Revision 1.453 2004/10/22 20:52:06 ksekar 316 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries 317 318 Revision 1.452 2004/10/20 01:50:40 cheshire 319 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API 320 Implemented ForceMCast mode for AuthRecords as well as for Questions 321 322 Revision 1.451 2004/10/19 21:33:15 cheshire 323 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API 324 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name 325 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want 326 327 Revision 1.450 2004/10/19 17:42:59 ksekar 328 Fixed compiler warnings for non-debug builds. 329 330 Revision 1.449 2004/10/18 22:57:07 cheshire 331 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1 332 333 Revision 1.448 2004/10/16 00:16:59 cheshire 334 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check 335 336 Revision 1.447 2004/10/15 00:51:21 cheshire 337 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1 338 339 Revision 1.446 2004/10/14 00:43:34 cheshire 340 <rdar://problem/3815984> Services continue to announce SRV and HINFO 341 342 Revision 1.445 2004/10/12 21:07:09 cheshire 343 Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit() 344 345 Revision 1.444 2004/10/11 17:54:16 ksekar 346 Changed hashtable pointer output from debugf to verbosedebugf. 347 348 Revision 1.443 2004/10/10 07:05:45 cheshire 349 For consistency, use symbol "localdomain" instead of literal string 350 351 Revision 1.442 2004/10/08 20:25:10 cheshire 352 Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time 353 354 Revision 1.441 2004/10/08 03:25:01 ksekar 355 <rdar://problem/3831716> domain enumeration should use LLQs 356 357 Revision 1.440 2004/10/06 01:44:19 cheshire 358 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record 359 360 Revision 1.439 2004/10/03 23:14:11 cheshire 361 Add "mDNSEthAddr" type and "zeroEthAddr" constant 362 363 Revision 1.438 2004/09/29 23:07:04 cheshire 364 Patch from Pavel Repin to fix compile error on Windows 365 366 Revision 1.437 2004/09/28 02:23:50 cheshire 367 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events 368 Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot 369 For records with the cache flush bit set, defer the decision until the end of the packet 370 371 Revision 1.436 2004/09/28 01:27:04 cheshire 372 Update incorrect log message 373 374 Revision 1.435 2004/09/25 02:41:39 cheshire 375 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events 376 377 Revision 1.434 2004/09/25 02:32:06 cheshire 378 Update comments 379 380 Revision 1.433 2004/09/25 02:24:27 cheshire 381 Removed unused rr->UseCount 382 383 Revision 1.432 2004/09/24 21:35:17 cheshire 384 <rdar://problem/3561220> Browses are no longer piggybacking on other browses 385 TargetPort and TargetQID are allowed to be undefined if no question->Target is set 386 387 Revision 1.431 2004/09/24 21:33:12 cheshire 388 Adjust comment 389 390 Revision 1.430 2004/09/24 02:15:49 cheshire 391 <rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces 392 393 Revision 1.429 2004/09/24 00:20:21 cheshire 394 <rdar://problem/3483349> Any rrtype is a conflict for unique records 395 396 Revision 1.428 2004/09/24 00:12:25 cheshire 397 Get rid of unused RRUniqueOrKnownUnique(RR) 398 399 Revision 1.427 2004/09/23 20:44:11 cheshire 400 <rdar://problem/3813148> Reduce timeout before expiring records on failure 401 402 Revision 1.426 2004/09/23 20:21:07 cheshire 403 <rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic 404 Associate a unique sequence number with each received packet, and only increment the count of recent answer 405 packets if the packet sequence number for this answer record is not one we've already seen and counted. 406 407 Revision 1.425 2004/09/23 20:14:38 cheshire 408 Rename "question->RecentAnswers" to "question->RecentAnswerPkts" 409 410 Revision 1.424 2004/09/23 00:58:36 cheshire 411 <rdar://problem/3781269> Rate limiting interferes with updating TXT records 412 413 Revision 1.423 2004/09/23 00:50:53 cheshire 414 <rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep 415 416 Revision 1.422 2004/09/22 02:34:46 cheshire 417 Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h 418 419 Revision 1.421 2004/09/21 23:29:49 cheshire 420 <rdar://problem/3680045> DNSServiceResolve should delay sending packets 421 422 Revision 1.420 2004/09/21 23:01:42 cheshire 423 Update debugf messages 424 425 Revision 1.419 2004/09/21 19:51:14 cheshire 426 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c 427 428 Revision 1.418 2004/09/21 18:40:17 cheshire 429 <rdar://problem/3376752> Adjust default record TTLs 430 431 Revision 1.417 2004/09/21 17:32:16 cheshire 432 <rdar://problem/3809484> Rate limiting imposed too soon 433 434 Revision 1.416 2004/09/20 23:52:01 cheshire 435 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c 436 437 Revision 1.415 2004/09/18 01:14:09 cheshire 438 <rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces 439 440 Revision 1.414 2004/09/18 01:06:48 cheshire 441 Add comments 442 443 Revision 1.413 2004/09/17 01:08:48 cheshire 444 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h 445 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces 446 declared in that file are ONLY appropriate to single-address-space embedded applications. 447 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. 448 449 Revision 1.412 2004/09/17 00:46:33 cheshire 450 mDNS_TimeNow should take const mDNS parameter 451 452 Revision 1.411 2004/09/17 00:31:51 cheshire 453 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' 454 455 Revision 1.410 2004/09/17 00:19:10 cheshire 456 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 457 458 Revision 1.409 2004/09/16 21:59:15 cheshire 459 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr 460 461 Revision 1.408 2004/09/16 21:36:36 cheshire 462 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 463 Changes to add necessary locking calls around unicast DNS operations 464 465 Revision 1.407 2004/09/16 02:29:39 cheshire 466 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around 467 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService 468 469 Revision 1.406 2004/09/16 01:58:14 cheshire 470 Fix compiler warnings 471 472 Revision 1.405 2004/09/16 00:24:48 cheshire 473 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 474 475 Revision 1.404 2004/09/15 21:44:11 cheshire 476 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init 477 Show time value in log to help diagnose errors 478 479 Revision 1.403 2004/09/15 00:46:32 ksekar 480 Changed debugf to verbosedebugf in CheckCacheExpiration 481 482 Revision 1.402 2004/09/14 23:59:55 cheshire 483 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init 484 485 Revision 1.401 2004/09/14 23:27:46 cheshire 486 Fix compile errors 487 488 Revision 1.400 2004/09/02 03:48:47 cheshire 489 <rdar://problem/3709039> Disable targeted unicast query support by default 490 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record 491 2. New field AllowRemoteQuery in AuthRecord structure 492 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set 493 4. mDNS.c only answers remote queries if AllowRemoteQuery is set 494 495 Revision 1.399 2004/09/02 01:39:40 cheshire 496 For better readability, follow consistent convention that QR bit comes first, followed by OP bits 497 498 Revision 1.398 2004/09/01 03:59:29 ksekar 499 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows 500 501 Revision 1.397 2004/08/25 22:04:25 rpantos 502 Fix the standard Windows compile error. 503 504 Revision 1.396 2004/08/25 00:37:27 ksekar 505 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code 506 507 Revision 1.395 2004/08/18 17:21:18 ksekar 508 Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs() 509 510 Revision 1.394 2004/08/14 03:22:41 cheshire 511 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue 512 Add GetUserSpecifiedDDNSName() routine 513 Convert ServiceRegDomain to domainname instead of C string 514 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs 515 516 Revision 1.393 2004/08/13 23:42:52 cheshire 517 Removed unused "zeroDomainNamePtr" 518 519 Revision 1.392 2004/08/13 23:37:02 cheshire 520 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with 521 "uDNS_info.UnicastHostname" for clarity 522 523 Revision 1.391 2004/08/13 23:25:00 cheshire 524 Now that we do both uDNS and mDNS, global replace "m->hostname" with 525 "m->MulticastHostname" for clarity 526 527 Revision 1.390 2004/08/11 02:17:01 cheshire 528 <rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record 529 530 Revision 1.389 2004/08/10 23:19:14 ksekar 531 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery 532 Moved routines/constants to allow extern access for garbage collection daemon 533 534 Revision 1.388 2004/07/30 17:40:06 ksekar 535 <rdar://problem/3739115>: TXT Record updates not available for wide-area services 536 537 Revision 1.387 2004/07/26 22:49:30 ksekar 538 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client 539 540 Revision 1.386 2004/07/13 21:24:24 rpantos 541 Fix for <rdar://problem/3701120>. 542 543 Revision 1.385 2004/06/18 19:09:59 cheshire 544 <rdar://problem/3588761> Current method of doing subtypes causes name collisions 545 546 Revision 1.384 2004/06/15 04:31:23 cheshire 547 Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion() 548 549 Revision 1.383 2004/06/11 00:04:59 cheshire 550 <rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord 551 552 Revision 1.382 2004/06/08 04:59:40 cheshire 553 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it 554 555 Revision 1.381 2004/06/05 00:57:30 cheshire 556 Remove incorrect LogMsg() 557 558 Revision 1.380 2004/06/05 00:04:26 cheshire 559 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration 560 561 Revision 1.379 2004/05/28 23:42:36 ksekar 562 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805) 563 564 Revision 1.378 2004/05/25 17:25:25 cheshire 565 Remove extraneous blank lines and white space 566 567 Revision 1.377 2004/05/18 23:51:25 cheshire 568 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers 569 570 Revision 1.376 2004/05/05 18:30:44 ksekar 571 Restored surpressed Cache Tail debug messages. 572 573 Revision 1.375 2004/04/26 21:36:25 cheshire 574 Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive 575 is indicated as being available on that interface 576 577 Revision 1.374 2004/04/21 02:53:26 cheshire 578 Typo in debugf statement 579 580 Revision 1.373 2004/04/21 02:49:11 cheshire 581 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' 582 583 Revision 1.372 2004/04/21 02:38:51 cheshire 584 Add debugging checks 585 586 Revision 1.371 2004/04/14 23:09:28 ksekar 587 Support for TSIG signed dynamic updates. 588 589 Revision 1.370 2004/04/09 17:40:26 cheshire 590 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field 591 592 Revision 1.369 2004/04/09 16:34:00 cheshire 593 Debugging code for later; currently unused 594 595 Revision 1.368 2004/04/02 19:19:48 cheshire 596 Add code to do optional logging of multi-packet KA list time intervals 597 598 Revision 1.367 2004/03/20 03:16:10 cheshire 599 Minor refinement to "Excessive update rate" message 600 601 Revision 1.366 2004/03/20 03:12:57 cheshire 602 <rdar://problem/3587619>: UpdateCredits not granted promptly enough 603 604 Revision 1.365 2004/03/19 23:51:22 cheshire 605 Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60) 606 607 Revision 1.364 2004/03/13 01:57:33 ksekar 608 <rdar://problem/3192546>: DynDNS: Dynamic update of service records 609 610 Revision 1.363 2004/03/12 21:00:51 cheshire 611 Also show port numbers when logging "apparent spoof mDNS Response" messages 612 613 Revision 1.362 2004/03/12 08:58:18 cheshire 614 Guard against empty TXT records 615 616 Revision 1.361 2004/03/09 03:00:46 cheshire 617 <rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good. 618 619 Revision 1.360 2004/03/08 02:52:41 cheshire 620 Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages 621 622 Revision 1.359 2004/03/02 03:21:56 cheshire 623 <rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries 624 625 Revision 1.358 2004/02/20 08:18:34 cheshire 626 <rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily 627 628 Revision 1.357 2004/02/18 01:47:41 cheshire 629 <rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms 630 631 Revision 1.356 2004/02/06 23:04:19 ksekar 632 Basic Dynamic Update support via mDNS_Register (dissabled via 633 UNICAST_REGISTRATION #define) 634 635 Revision 1.355 2004/02/05 09:32:33 cheshire 636 Fix from Bob Bradley: When using the "%.*s" string form, 637 guard against truncating in the middle of a multi-byte UTF-8 character. 638 639 Revision 1.354 2004/02/05 09:30:22 cheshire 640 Update comments 641 642 Revision 1.353 2004/01/28 03:41:00 cheshire 643 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries 644 645 Revision 1.352 2004/01/28 02:30:07 ksekar 646 Added default Search Domains to unicast browsing, controlled via 647 Networking sharing prefs pane. Stopped sending unicast messages on 648 every interface. Fixed unicast resolving via mach-port API. 649 650 Revision 1.351 2004/01/27 20:15:22 cheshire 651 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53 652 653 Revision 1.350 2004/01/24 23:38:16 cheshire 654 Use mDNSVal16() instead of shifting and ORing operations 655 656 Revision 1.349 2004/01/23 23:23:14 ksekar 657 Added TCP support for truncated unicast messages. 658 659 Revision 1.348 2004/01/22 03:54:11 cheshire 660 Create special meta-interface 'mDNSInterface_ForceMCast' (-2), 661 which means "do this query via multicast, even if it's apparently a unicast domain" 662 663 Revision 1.347 2004/01/22 03:50:49 cheshire 664 If the client has specified an explicit InterfaceID, then do query by multicast, not unicast 665 666 Revision 1.346 2004/01/22 03:48:41 cheshire 667 Make sure uDNS client doesn't accidentally use query ID zero 668 669 Revision 1.345 2004/01/22 03:43:08 cheshire 670 Export constants like mDNSInterface_LocalOnly so that the client layers can use them 671 672 Revision 1.344 2004/01/21 21:53:18 cheshire 673 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port 674 675 Revision 1.343 2003/12/23 00:07:47 cheshire 676 Make port number in debug message be five-character field, left justified 677 678 Revision 1.342 2003/12/20 01:34:28 cheshire 679 <rdar://problem/3515876>: Error putting additional records into packets 680 Another fix from Rampi: responseptr needs to be updated inside the "for" loop, 681 after every record, not once at the end. 682 683 Revision 1.341 2003/12/18 22:56:12 cheshire 684 <rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets 685 686 Revision 1.340 2003/12/16 02:31:37 cheshire 687 Minor update to comments 688 689 Revision 1.339 2003/12/13 05:50:33 bradley 690 Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform 691 layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to 692 fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf. 693 694 Revision 1.338 2003/12/13 03:05:27 ksekar 695 <rdar://problem/3192548>: DynDNS: Unicast query of service records 696 697 Revision 1.337 2003/12/01 21:46:05 cheshire 698 mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist 699 700 Revision 1.336 2003/12/01 21:26:19 cheshire 701 Guard against zero-length sbuffer in mDNS_vsnprintf() 702 703 Revision 1.335 2003/12/01 20:27:48 cheshire 704 Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors 705 706 Revision 1.334 2003/11/20 22:59:53 cheshire 707 Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h 708 Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work. 709 710 Revision 1.333 2003/11/20 20:49:53 cheshire 711 Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures 712 713 Revision 1.332 2003/11/20 05:47:37 cheshire 714 <rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query 715 Now that we only include answers in the known answer list if they are less than 716 halfway to expiry, the check to also see if we have another query scheduled 717 before the record expires is no longer necessary (and in fact, not correct). 718 719 Revision 1.331 2003/11/19 22:31:48 cheshire 720 When automatically adding A records to SRVs, add them as additionals, not answers 721 722 Revision 1.330 2003/11/19 22:28:50 cheshire 723 Increment/Decrement mDNS_reentrancy around calls to m->MainCallback() 724 to allow client to make mDNS calls (specifically the call to mDNS_GrowCache()) 725 726 Revision 1.329 2003/11/19 22:19:24 cheshire 727 Show log message when ignoring packets with bad TTL. 728 This is to help diagnose problems on Linux versions that may not report the TTL reliably. 729 730 Revision 1.328 2003/11/19 22:06:38 cheshire 731 Show log messages when a service or hostname is renamed 732 733 Revision 1.327 2003/11/19 22:03:44 cheshire 734 Move common "m->NextScheduledResponse = m->timenow" to before "if" statement 735 736 Revision 1.326 2003/11/17 22:27:02 cheshire 737 Another fix from ramaprasad.kr@hp.com: Improve reply delay computation 738 on platforms that have native clock rates below fifty ticks per second. 739 740 Revision 1.325 2003/11/17 20:41:44 cheshire 741 Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls. 742 743 Revision 1.324 2003/11/17 20:36:32 cheshire 744 Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and 745 DeadvertiseInterface() -- they're internal private routines, not API routines. 746 747 Revision 1.323 2003/11/14 20:59:08 cheshire 748 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. 749 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. 750 751 Revision 1.322 2003/11/14 19:47:52 cheshire 752 Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString 753 754 Revision 1.321 2003/11/14 19:18:34 cheshire 755 Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too 756 757 Revision 1.320 2003/11/13 06:45:04 cheshire 758 Fix compiler warning on certain compilers 759 760 Revision 1.319 2003/11/13 00:47:40 cheshire 761 <rdar://problem/3437556> We should delay AAAA record query if A record already in cache. 762 763 Revision 1.318 2003/11/13 00:33:26 cheshire 764 Change macro "RRIsAddressType" to "RRTypeIsAddressType" 765 766 Revision 1.317 2003/11/13 00:10:49 cheshire 767 <rdar://problem/3436412>: Verify that rr data is different before updating. 768 769 Revision 1.316 2003/11/08 23:37:54 cheshire 770 Give explicit zero initializers to blank static structure, required by certain compilers. 771 (Thanks to ramaprasad.kr@hp.com for reporting this.) 772 773 Revision 1.315 2003/11/07 03:32:56 cheshire 774 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order 775 This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes 776 purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is 777 to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR() 778 can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place. 779 780 Revision 1.314 2003/11/07 03:19:49 cheshire 781 Minor variable renaming for clarity 782 783 Revision 1.313 2003/11/07 03:14:49 cheshire 784 Previous checkin proved to be overly simplistic; reversing 785 786 Revision 1.312 2003/11/03 23:45:15 cheshire 787 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order 788 Build cache lists in FIFO order, not customary C LIFO order 789 (Append new elements to tail of cache list, instead of prepending at the head.) 790 791 Revision 1.311 2003/10/09 18:00:11 cheshire 792 Another compiler warning fix. 793 794 Revision 1.310 2003/10/07 20:27:05 cheshire 795 Patch from Bob Bradley, to fix warning and compile error on Windows 796 797 Revision 1.309 2003/09/26 01:06:36 cheshire 798 <rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too 799 Made new routine HaveSentEntireRRSet() to check if flag should be set 800 801 Revision 1.308 2003/09/23 01:05:01 cheshire 802 Minor changes to comments and debugf() message 803 804 Revision 1.307 2003/09/09 20:13:30 cheshire 805 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it 806 Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented 807 rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount 808 809 Revision 1.306 2003/09/09 03:00:03 cheshire 810 <rdar://problem/3413099> Services take a long time to disappear when switching networks. 811 Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect 812 813 Revision 1.305 2003/09/09 02:49:31 cheshire 814 <rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep 815 816 Revision 1.304 2003/09/09 02:41:19 cheshire 817 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it 818 819 Revision 1.303 2003/09/05 19:55:02 cheshire 820 <rdar://problem/3409533> Include address records when announcing SRV records 821 822 Revision 1.302 2003/09/05 00:01:36 cheshire 823 <rdar://problem/3407549> Don't accelerate queries that have large KA lists 824 825 Revision 1.301 2003/09/04 22:51:13 cheshire 826 <rdar://problem/3398213> Group probes and goodbyes better 827 828 Revision 1.300 2003/09/03 02:40:37 cheshire 829 <rdar://problem/3404842> mDNSResponder complains about '_'s 830 Underscores are not supposed to be legal in standard DNS names, but IANA appears 831 to have allowed them in previous service name registrations, so we should too. 832 833 Revision 1.299 2003/09/03 02:33:09 cheshire 834 <rdar://problem/3404795> CacheRecordRmv ERROR 835 Don't update m->NewQuestions until *after* CheckCacheExpiration(); 836 837 Revision 1.298 2003/09/03 01:47:01 cheshire 838 <rdar://problem/3319418> Services always in a state of flux 839 Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds 840 841 Revision 1.297 2003/08/29 19:44:15 cheshire 842 <rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears 843 1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries 844 that already have at least one unique answer in the cache 845 2. For these queries, go straight to QM, skipping QU 846 847 Revision 1.296 2003/08/29 19:08:21 cheshire 848 <rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep 849 Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time. 850 851 Revision 1.295 2003/08/28 01:10:59 cheshire 852 <rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst 853 854 Revision 1.294 2003/08/27 02:30:22 cheshire 855 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve() 856 One more change: "query->GotTXT" is now a straightforward bi-state boolean again 857 858 Revision 1.293 2003/08/27 02:25:31 cheshire 859 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve() 860 861 Revision 1.292 2003/08/21 19:27:36 cheshire 862 <rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL 863 864 Revision 1.291 2003/08/21 18:57:44 cheshire 865 <rdar://problem/3387140> Synchronized queries on the network 866 867 Revision 1.290 2003/08/21 02:25:23 cheshire 868 Minor changes to comments and debugf() messages 869 870 Revision 1.289 2003/08/21 02:21:50 cheshire 871 <rdar://problem/3386473> Efficiency: Reduce repeated queries 872 873 Revision 1.288 2003/08/20 23:39:30 cheshire 874 <rdar://problem/3344098> Review syslog messages, and remove as appropriate 875 876 Revision 1.287 2003/08/20 20:47:18 cheshire 877 Fix compiler warning 878 879 Revision 1.286 2003/08/20 02:18:51 cheshire 880 <rdar://problem/3344098> Cleanup: Review syslog messages 881 882 Revision 1.285 2003/08/20 01:59:06 cheshire 883 <rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata 884 Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place 885 886 Revision 1.284 2003/08/19 22:20:00 cheshire 887 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured 888 More minor refinements 889 890 Revision 1.283 2003/08/19 22:16:27 cheshire 891 Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case. 892 893 Revision 1.282 2003/08/19 06:48:25 cheshire 894 <rdar://problem/3376552> Guard against excessive record updates 895 Each record starts with 10 UpdateCredits. 896 Every update consumes one UpdateCredit. 897 UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10. 898 As the number of UpdateCredits declines, the number of announcements is similarly scaled back. 899 When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount. 900 901 Revision 1.281 2003/08/19 04:49:28 cheshire 902 <rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right 903 1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6. 904 2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface. 905 3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface. 906 907 Revision 1.280 2003/08/19 02:33:36 cheshire 908 Update comments 909 910 Revision 1.279 2003/08/19 02:31:11 cheshire 911 <rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries 912 Final expiration queries now only mark the question for sending on the particular interface 913 pertaining to the record that's expiring. 914 915 Revision 1.278 2003/08/18 22:53:37 cheshire 916 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime() 917 918 Revision 1.277 2003/08/18 19:05:44 cheshire 919 <rdar://problem/3382423> UpdateRecord not working right 920 Added "newrdlength" field to hold new length of updated rdata 921 922 Revision 1.276 2003/08/16 03:39:00 cheshire 923 <rdar://problem/3338440> InterfaceID -1 indicates "local only" 924 925 Revision 1.275 2003/08/16 02:51:27 cheshire 926 <rdar://problem/3366590> mDNSResponder takes too much RPRVT 927 Don't try to compute namehash etc, until *after* validating the name 928 929 Revision 1.274 2003/08/16 01:12:40 cheshire 930 <rdar://problem/3366590> mDNSResponder takes too much RPRVT 931 Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a 932 simple C structure assignment of a domainname, because that object is defined to be 256 bytes long, 933 and in the process of copying it, the C compiler may run off the end of the rdata object into 934 unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a 935 call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid. 936 937 Revision 1.273 2003/08/15 20:16:02 cheshire 938 <rdar://problem/3366590> mDNSResponder takes too much RPRVT 939 We want to avoid touching the rdata pages, so we don't page them in. 940 1. RDLength was stored with the rdata, which meant touching the page just to find the length. 941 Moved this from the RData to the ResourceRecord object. 942 2. To avoid unnecessarily touching the rdata just to compare it, 943 compute a hash of the rdata and store the hash in the ResourceRecord object. 944 945 Revision 1.272 2003/08/14 19:29:04 cheshire 946 <rdar://problem/3378473> Include cache records in SIGINFO output 947 Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them 948 949 Revision 1.271 2003/08/14 02:17:05 cheshire 950 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord 951 952 Revision 1.270 2003/08/13 17:07:28 ksekar 953 <rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash 954 Added check to result of mDNS_Register() before linking extra record into list. 955 956 Revision 1.269 2003/08/12 19:56:23 cheshire 957 Update to APSL 2.0 958 959 Revision 1.268 2003/08/12 15:01:10 cheshire 960 Add comments 961 962 Revision 1.267 2003/08/12 14:59:27 cheshire 963 <rdar://problem/3374490> Rate-limiting blocks some legitimate responses 964 When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine 965 whether to suppress the response, also check LastMCInterface to see if it matches. 966 967 Revision 1.266 2003/08/12 12:47:16 cheshire 968 In mDNSCoreMachineSleep debugf message, display value of m->timenow 969 970 Revision 1.265 2003/08/11 20:04:28 cheshire 971 <rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache 972 973 Revision 1.264 2003/08/09 00:55:02 cheshire 974 <rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU 975 Don't scan the whole cache after every packet. 976 977 Revision 1.263 2003/08/09 00:35:29 cheshire 978 Moved AnswerNewQuestion() later in the file, in preparation for next checkin 979 980 Revision 1.262 2003/08/08 19:50:33 cheshire 981 <rdar://problem/3370332> Remove "Cache size now xxx" messages 982 983 Revision 1.261 2003/08/08 19:18:45 cheshire 984 <rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug 985 986 Revision 1.260 2003/08/08 18:55:48 cheshire 987 <rdar://problem/3370365> Guard against time going backwards 988 989 Revision 1.259 2003/08/08 18:36:04 cheshire 990 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug 991 992 Revision 1.258 2003/08/08 16:22:05 cheshire 993 <rdar://problem/3335473> Need to check validity of TXT (and other) records 994 Remove unneeded LogMsg 995 996 Revision 1.257 2003/08/07 01:41:08 cheshire 997 <rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones) 998 999 Revision 1.256 2003/08/06 23:25:51 cheshire 1000 <rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four 1001 1002 Revision 1.255 2003/08/06 23:22:50 cheshire 1003 Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours) 1004 1005 Revision 1.254 2003/08/06 21:33:39 cheshire 1006 Fix compiler warnings on PocketPC 2003 (Windows CE) 1007 1008 Revision 1.253 2003/08/06 20:43:57 cheshire 1009 <rdar://problem/3335473> Need to check validity of TXT (and other) records 1010 Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update() 1011 1012 Revision 1.252 2003/08/06 20:35:47 cheshire 1013 Enhance debugging routine GetRRDisplayString() so it can also be used to display 1014 other RDataBody objects, not just the one currently attached the given ResourceRecord 1015 1016 Revision 1.251 2003/08/06 19:07:34 cheshire 1017 <rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should 1018 Was checking LastAPTime instead of LastMCTime 1019 1020 Revision 1.250 2003/08/06 19:01:55 cheshire 1021 Update comments 1022 1023 Revision 1.249 2003/08/06 00:13:28 cheshire 1024 Tidy up debugf messages 1025 1026 Revision 1.248 2003/08/05 22:20:15 cheshire 1027 <rdar://problem/3330324> Need to check IP TTL on responses 1028 1029 Revision 1.247 2003/08/05 00:56:39 cheshire 1030 <rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed 1031 1032 Revision 1.246 2003/08/04 19:20:49 cheshire 1033 Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages 1034 1035 Revision 1.245 2003/08/02 01:56:29 cheshire 1036 For debugging: log message if we ever get more than one question in a truncated packet 1037 1038 Revision 1.244 2003/08/01 23:55:32 cheshire 1039 Fix for compiler warnings on Windows, submitted by Bob Bradley 1040 1041 Revision 1.243 2003/07/25 02:26:09 cheshire 1042 Typo: FIxed missing semicolon 1043 1044 Revision 1.242 2003/07/25 01:18:41 cheshire 1045 Fix memory leak on shutdown in mDNS_Close() (detected in Windows version) 1046 1047 Revision 1.241 2003/07/23 21:03:42 cheshire 1048 Only show "Found record..." debugf message in verbose mode 1049 1050 Revision 1.240 2003/07/23 21:01:11 cheshire 1051 <rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one 1052 After sending a packet, suppress further sending for the next 100ms. 1053 1054 Revision 1.239 2003/07/22 01:30:05 cheshire 1055 <rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once 1056 1057 Revision 1.238 2003/07/22 00:10:20 cheshire 1058 <rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters 1059 1060 Revision 1.237 2003/07/19 03:23:13 cheshire 1061 <rdar://problem/2986147> mDNSResponder needs to receive and cache larger records 1062 1063 Revision 1.236 2003/07/19 03:04:55 cheshire 1064 Fix warnings; some debugf message improvements 1065 1066 Revision 1.235 2003/07/19 00:03:32 cheshire 1067 <rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received 1068 ScheduleNextTask is quite an expensive operation. 1069 We don't need to do all that work after receiving a no-op packet that didn't change our state. 1070 1071 Revision 1.234 2003/07/18 23:52:11 cheshire 1072 To improve consistency of field naming, global search-and-replace: 1073 NextProbeTime -> NextScheduledProbe 1074 NextResponseTime -> NextScheduledResponse 1075 1076 Revision 1.233 2003/07/18 00:29:59 cheshire 1077 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead 1078 1079 Revision 1.232 2003/07/18 00:11:38 cheshire 1080 Add extra case to switch statements to handle HINFO data for Get, Put and Display 1081 (In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT) 1082 1083 Revision 1.231 2003/07/18 00:06:37 cheshire 1084 To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->" 1085 1086 Revision 1.230 2003/07/17 18:16:54 cheshire 1087 <rdar://problem/3319418> Services always in a state of flux 1088 In preparation for working on this, made some debugf messages a little more selective 1089 1090 Revision 1.229 2003/07/17 17:35:04 cheshire 1091 <rdar://problem/3325583> Rate-limit responses, to guard against packet flooding 1092 1093 Revision 1.228 2003/07/16 20:50:27 cheshire 1094 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass 1095 1096 Revision 1.227 2003/07/16 05:01:36 cheshire 1097 Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for 1098 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass 1099 1100 Revision 1.226 2003/07/16 04:51:44 cheshire 1101 Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval' 1102 1103 Revision 1.225 2003/07/16 04:46:41 cheshire 1104 Minor wording cleanup: The correct DNS term is "response", not "reply" 1105 1106 Revision 1.224 2003/07/16 04:39:02 cheshire 1107 Textual cleanup (no change to functionality): 1108 Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)" 1109 1110 Revision 1.223 2003/07/16 00:09:22 cheshire 1111 Textual cleanup (no change to functionality): 1112 Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places; 1113 replace with macro "TicksTTL(rr)" 1114 Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" 1115 replaced with macro "RRExpireTime(rr)" 1116 1117 Revision 1.222 2003/07/15 23:40:46 cheshire 1118 Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo() 1119 1120 Revision 1.221 2003/07/15 22:17:56 cheshire 1121 <rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries 1122 1123 Revision 1.220 2003/07/15 02:12:51 cheshire 1124 Slight tidy-up of debugf messages and comments 1125 1126 Revision 1.219 2003/07/15 01:55:12 cheshire 1127 <rdar://problem/3315777> Need to implement service registration with subtypes 1128 1129 Revision 1.218 2003/07/14 16:26:06 cheshire 1130 <rdar://problem/3324795> Duplicate query suppression not working right 1131 Refinement: Don't record DS information for a question in the first quarter second 1132 right after we send it -- in the case where a question happens to be accelerated by 1133 the maximum allowed amount, we don't want it to then be suppressed because the previous 1134 time *we* sent that question falls (just) within the valid duplicate suppression window. 1135 1136 Revision 1.217 2003/07/13 04:43:53 cheshire 1137 <rdar://problem/3325169> Services on multiple interfaces not always resolving 1138 Minor refinement: No need to make address query broader than the original SRV query that provoked it 1139 1140 Revision 1.216 2003/07/13 03:13:17 cheshire 1141 <rdar://problem/3325169> Services on multiple interfaces not always resolving 1142 If we get an identical SRV on a second interface, convert address queries to non-specific 1143 1144 Revision 1.215 2003/07/13 02:28:00 cheshire 1145 <rdar://problem/3325166> SendResponses didn't all its responses 1146 Delete all references to RRInterfaceActive -- it's now superfluous 1147 1148 Revision 1.214 2003/07/13 01:47:53 cheshire 1149 Fix one error and one warning in the Windows build 1150 1151 Revision 1.213 2003/07/12 04:25:48 cheshire 1152 Fix minor signed/unsigned warnings 1153 1154 Revision 1.212 2003/07/12 01:59:11 cheshire 1155 Minor changes to debugf messages 1156 1157 Revision 1.211 2003/07/12 01:47:01 cheshire 1158 <rdar://problem/3324495> After name conflict, appended number should be higher than previous number 1159 1160 Revision 1.210 2003/07/12 01:43:28 cheshire 1161 <rdar://problem/3324795> Duplicate query suppression not working right 1162 The correct cutoff time for duplicate query suppression is timenow less one-half the query interval. 1163 The code was incorrectly using the last query time plus one-half the query interval. 1164 This was only correct in the case where query acceleration was not in effect. 1165 1166 Revision 1.209 2003/07/12 01:27:50 cheshire 1167 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens 1168 Fix missing "-1" in RemoveLabelSuffix() 1169 1170 Revision 1.208 2003/07/11 01:32:38 cheshire 1171 Syntactic cleanup (no change to funcationality): Now that we only have one host name, 1172 rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A". 1173 1174 Revision 1.207 2003/07/11 01:28:00 cheshire 1175 <rdar://problem/3161289> No more local.arpa 1176 1177 Revision 1.206 2003/07/11 00:45:02 cheshire 1178 <rdar://problem/3321909> Client should get callback confirming successful host name registration 1179 1180 Revision 1.205 2003/07/11 00:40:18 cheshire 1181 Tidy up debug message in HostNameCallback() 1182 1183 Revision 1.204 2003/07/11 00:20:32 cheshire 1184 <rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes 1185 1186 Revision 1.203 2003/07/10 23:53:41 cheshire 1187 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens 1188 1189 Revision 1.202 2003/07/04 02:23:20 cheshire 1190 <rdar://problem/3311955> Responder too aggressive at flushing stale data 1191 Changed mDNSResponder to require four unanswered queries before purging a record, instead of two. 1192 1193 Revision 1.201 2003/07/04 01:09:41 cheshire 1194 <rdar://problem/3315775> Need to implement subtype queries 1195 Modified ConstructServiceName() to allow three-part service types 1196 1197 Revision 1.200 2003/07/03 23:55:26 cheshire 1198 Minor change to wording of syslog warning messages 1199 1200 Revision 1.199 2003/07/03 23:51:13 cheshire 1201 <rdar://problem/3315652>: Lots of "have given xxx answers" syslog warnings 1202 Added more detailed debugging information 1203 1204 Revision 1.198 2003/07/03 22:19:30 cheshire 1205 <rdar://problem/3314346> Bug fix in 3274153 breaks TiVo 1206 Make exception to allow _tivo_servemedia._tcp. 1207 1208 Revision 1.197 2003/07/02 22:33:05 cheshire 1209 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed 1210 Minor refinements: 1211 When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not 1212 Allow cache to grow to 512 records before considering it a potential denial-of-service attack 1213 1214 Revision 1.196 2003/07/02 21:19:45 cheshire 1215 <rdar://problem/3313413> Update copyright notices, etc., in source code comments 1216 1217 Revision 1.195 2003/07/02 19:56:58 cheshire 1218 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed 1219 Minor refinement: m->rrcache_active was not being decremented when 1220 an active record was deleted because its TTL expired 1221 1222 Revision 1.194 2003/07/02 18:47:40 cheshire 1223 Minor wording change to log messages 1224 1225 Revision 1.193 2003/07/02 02:44:13 cheshire 1226 Fix warning in non-debug build 1227 1228 Revision 1.192 2003/07/02 02:41:23 cheshire 1229 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed 1230 1231 Revision 1.191 2003/07/02 02:30:51 cheshire 1232 HashSlot() returns an array index. It can't be negative; hence it should not be signed. 1233 1234 Revision 1.190 2003/06/27 00:03:05 vlubet 1235 <rdar://problem/3304625> Merge of build failure fix for gcc 3.3 1236 1237 Revision 1.189 2003/06/11 19:24:03 cheshire 1238 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces 1239 Slight refinement to previous checkin 1240 1241 Revision 1.188 2003/06/10 20:33:28 cheshire 1242 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces 1243 1244 Revision 1.187 2003/06/10 04:30:44 cheshire 1245 <rdar://problem/3286234> Need to re-probe/re-announce on configuration change 1246 Only interface-specific records were re-probing and re-announcing, not non-specific records. 1247 1248 Revision 1.186 2003/06/10 04:24:39 cheshire 1249 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache 1250 Some additional refinements: 1251 Don't try to do this for unicast-response queries 1252 better tracking of Qs and KAs in multi-packet KA lists 1253 1254 Revision 1.185 2003/06/10 03:52:49 cheshire 1255 Update comments and debug messages 1256 1257 Revision 1.184 2003/06/10 02:26:39 cheshire 1258 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function 1259 Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines 1260 1261 Revision 1.183 2003/06/09 18:53:13 cheshire 1262 Simplify some debugf() statements (replaced block of 25 lines with 2 lines) 1263 1264 Revision 1.182 2003/06/09 18:38:42 cheshire 1265 <rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network 1266 Only issue a correction if the TTL in the proxy packet is less than half the correct value. 1267 1268 Revision 1.181 2003/06/07 06:45:05 cheshire 1269 <rdar://problem/3283666> No need for multiple machines to all be sending the same queries 1270 1271 Revision 1.180 2003/06/07 06:31:07 cheshire 1272 Create little four-line helper function "FindIdenticalRecordInCache()" 1273 1274 Revision 1.179 2003/06/07 06:28:13 cheshire 1275 For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq" 1276 1277 Revision 1.178 2003/06/07 06:25:12 cheshire 1278 Update some comments 1279 1280 Revision 1.177 2003/06/07 04:50:53 cheshire 1281 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache 1282 1283 Revision 1.176 2003/06/07 04:33:26 cheshire 1284 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records 1285 Minor change: Increment/decrement logic for q->CurrentAnswers should be in 1286 CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord() 1287 1288 Revision 1.175 2003/06/07 04:11:52 cheshire 1289 Minor changes to comments and debug messages 1290 1291 Revision 1.174 2003/06/07 01:46:38 cheshire 1292 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records 1293 1294 Revision 1.173 2003/06/07 01:22:13 cheshire 1295 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function 1296 1297 Revision 1.172 2003/06/07 00:59:42 cheshire 1298 <rdar://problem/3283454> Need some randomness to spread queries on the network 1299 1300 Revision 1.171 2003/06/06 21:41:10 cheshire 1301 For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines 1302 1303 Revision 1.170 2003/06/06 21:38:55 cheshire 1304 Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we 1305 already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.) 1306 1307 Revision 1.169 2003/06/06 21:35:55 cheshire 1308 Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget 1309 (the target is a domain name, but not necessarily a host name) 1310 1311 Revision 1.168 2003/06/06 21:33:31 cheshire 1312 Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval" 1313 1314 Revision 1.167 2003/06/06 21:30:42 cheshire 1315 <rdar://problem/3282962> Don't delay queries for shared record types 1316 1317 Revision 1.166 2003/06/06 17:20:14 cheshire 1318 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass 1319 (Global search-and-replace; no functional change to code execution.) 1320 1321 Revision 1.165 2003/06/04 02:53:21 cheshire 1322 Add some "#pragma warning" lines so it compiles clean on Microsoft compilers 1323 1324 Revision 1.164 2003/06/04 01:25:33 cheshire 1325 <rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages 1326 Display time interval between first and subsequent queries 1327 1328 Revision 1.163 2003/06/03 19:58:14 cheshire 1329 <rdar://problem/3277665> mDNS_DeregisterService() fixes: 1330 When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet. 1331 Guard against a couple of possible mDNS_DeregisterService() race conditions. 1332 1333 Revision 1.162 2003/06/03 19:30:39 cheshire 1334 Minor addition refinements for 1335 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be 1336 1337 Revision 1.161 2003/06/03 18:29:03 cheshire 1338 Minor changes to comments and debugf() messages 1339 1340 Revision 1.160 2003/06/03 05:02:16 cheshire 1341 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be 1342 1343 Revision 1.159 2003/06/03 03:31:57 cheshire 1344 <rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine 1345 1346 Revision 1.158 2003/06/02 22:57:09 cheshire 1347 Minor clarifying changes to comments and log messages; 1348 IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord() 1349 1350 Revision 1.157 2003/05/31 00:09:49 cheshire 1351 <rdar://problem/3274862> Add ability to discover what services are on a network 1352 1353 Revision 1.156 2003/05/30 23:56:49 cheshire 1354 <rdar://problem/3274847> Crash after error in mDNS_RegisterService() 1355 Need to set "sr->Extras = mDNSNULL" before returning 1356 1357 Revision 1.155 2003/05/30 23:48:00 cheshire 1358 <rdar://problem/3274832> Announcements not properly grouped 1359 Due to inconsistent setting of rr->LastAPTime at different places in the 1360 code, announcements were not properly grouped into a single packet. 1361 Fixed by creating a single routine called InitializeLastAPTime(). 1362 1363 Revision 1.154 2003/05/30 23:38:14 cheshire 1364 <rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records 1365 Wrote buffer[32] where it should have said buffer[64] 1366 1367 Revision 1.153 2003/05/30 19:10:56 cheshire 1368 <rdar://problem/3274153> ConstructServiceName needs to be more restrictive 1369 1370 Revision 1.152 2003/05/29 22:39:16 cheshire 1371 <rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character 1372 1373 Revision 1.151 2003/05/29 06:35:42 cheshire 1374 <rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record 1375 1376 Revision 1.150 2003/05/29 06:25:45 cheshire 1377 <rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion() 1378 1379 Revision 1.149 2003/05/29 06:18:39 cheshire 1380 <rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv 1381 1382 Revision 1.148 2003/05/29 06:11:34 cheshire 1383 <rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks 1384 1385 Revision 1.147 2003/05/29 06:01:18 cheshire 1386 Change some debugf() calls to LogMsg() calls to help with debugging 1387 1388 Revision 1.146 2003/05/28 21:00:44 cheshire 1389 Re-enable "immediate answer burst" debugf message 1390 1391 Revision 1.145 2003/05/28 20:57:44 cheshire 1392 <rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet 1393 known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2 1394 version of mDNSResponder, so for now we should suppress this warning message. 1395 1396 Revision 1.144 2003/05/28 18:05:12 cheshire 1397 <rdar://problem/3009899> mDNSResponder allows invalid service registrations 1398 Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names 1399 1400 Revision 1.143 2003/05/28 04:31:29 cheshire 1401 <rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time 1402 1403 Revision 1.142 2003/05/28 03:13:07 cheshire 1404 <rdar://problem/3009899> mDNSResponder allows invalid service registrations 1405 Require that the transport protocol be _udp or _tcp 1406 1407 Revision 1.141 2003/05/28 02:19:12 cheshire 1408 <rdar://problem/3270634> Misleading messages generated by iChat 1409 Better fix: Only generate the log message for queries where the TC bit is set. 1410 1411 Revision 1.140 2003/05/28 01:55:24 cheshire 1412 Minor change to log messages 1413 1414 Revision 1.139 2003/05/28 01:52:51 cheshire 1415 <rdar://problem/3270634> Misleading messages generated by iChat 1416 1417 Revision 1.138 2003/05/27 22:35:00 cheshire 1418 <rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions 1419 1420 Revision 1.137 2003/05/27 20:04:33 cheshire 1421 <rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf() 1422 1423 Revision 1.136 2003/05/27 18:50:07 cheshire 1424 <rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes 1425 1426 Revision 1.135 2003/05/26 04:57:28 cheshire 1427 <rdar://problem/3268953> Delay queries when there are already answers in the cache 1428 1429 Revision 1.134 2003/05/26 04:54:54 cheshire 1430 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead 1431 Accidentally deleted '%' case from the switch statement 1432 1433 Revision 1.133 2003/05/26 03:21:27 cheshire 1434 Tidy up address structure naming: 1435 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) 1436 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 1437 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 1438 1439 Revision 1.132 2003/05/26 03:01:26 cheshire 1440 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead 1441 1442 Revision 1.131 2003/05/26 00:42:05 cheshire 1443 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets 1444 1445 Revision 1.130 2003/05/24 16:39:48 cheshire 1446 <rdar://problem/3268631> SendResponses also needs to handle multihoming better 1447 1448 Revision 1.129 2003/05/23 02:15:37 cheshire 1449 Fixed misleading use of the term "duplicate suppression" where it should have 1450 said "known answer suppression". (Duplicate answer suppression is something 1451 different, and duplicate question suppression is yet another thing, so the use 1452 of the completely vague term "duplicate suppression" was particularly bad.) 1453 1454 Revision 1.128 2003/05/23 01:55:13 cheshire 1455 <rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness 1456 1457 Revision 1.127 2003/05/23 01:02:15 ksekar 1458 <rdar://problem/3032577>: mDNSResponder needs to include unique id in default name 1459 1460 Revision 1.126 2003/05/22 02:29:22 cheshire 1461 <rdar://problem/2984918> SendQueries needs to handle multihoming better 1462 Complete rewrite of SendQueries. Works much better now :-) 1463 1464 Revision 1.125 2003/05/22 01:50:45 cheshire 1465 Fix warnings, and improve log messages 1466 1467 Revision 1.124 2003/05/22 01:41:50 cheshire 1468 DiscardDeregistrations doesn't need InterfaceID parameter 1469 1470 Revision 1.123 2003/05/22 01:38:55 cheshire 1471 Change bracketing of #pragma mark 1472 1473 Revision 1.122 2003/05/21 19:59:04 cheshire 1474 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior 1475 Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character 1476 1477 Revision 1.121 2003/05/21 17:54:07 ksekar 1478 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior 1479 New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)" 1480 1481 Revision 1.120 2003/05/19 22:14:14 ksekar 1482 <rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type 1483 1484 Revision 1.119 2003/05/16 01:34:10 cheshire 1485 Fix some warnings 1486 1487 Revision 1.118 2003/05/14 18:48:40 cheshire 1488 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations 1489 More minor refinements: 1490 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory 1491 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away 1492 1493 Revision 1.117 2003/05/14 07:08:36 cheshire 1494 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations 1495 Previously, when there was any network configuration change, mDNSResponder 1496 would tear down the entire list of active interfaces and start again. 1497 That was very disruptive, and caused the entire cache to be flushed, 1498 and caused lots of extra network traffic. Now it only removes interfaces 1499 that have really gone, and only adds new ones that weren't there before. 1500 1501 Revision 1.116 2003/05/14 06:51:56 cheshire 1502 <rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep 1503 1504 Revision 1.115 2003/05/14 06:44:31 cheshire 1505 Improve debugging message 1506 1507 Revision 1.114 2003/05/07 01:47:03 cheshire 1508 <rdar://problem/3250330> Also protect against NULL domainlabels 1509 1510 Revision 1.113 2003/05/07 00:28:18 cheshire 1511 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients 1512 1513 Revision 1.112 2003/05/06 00:00:46 cheshire 1514 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions 1515 1516 Revision 1.111 2003/05/05 23:42:08 cheshire 1517 <rdar://problem/3245631> Resolves never succeed 1518 Was setting "rr->LastAPTime = timenow - rr->LastAPTime" 1519 instead of "rr->LastAPTime = timenow - rr->ThisAPInterval" 1520 1521 Revision 1.110 2003/04/30 21:09:59 cheshire 1522 <rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names 1523 1524 Revision 1.109 2003/04/26 02:41:56 cheshire 1525 <rdar://problem/3241281> Change timenow from a local variable to a structure member 1526 1527 Revision 1.108 2003/04/25 01:45:56 cheshire 1528 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name 1529 1530 Revision 1.107 2003/04/25 00:41:31 cheshire 1531 <rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future 1532 1533 Revision 1.106 2003/04/22 03:14:45 cheshire 1534 <rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now 1535 1536 Revision 1.105 2003/04/22 01:07:43 cheshire 1537 <rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl 1538 If TTL parameter is zero, leave record TTL unchanged 1539 1540 Revision 1.104 2003/04/21 19:15:52 cheshire 1541 Fix some compiler warnings 1542 1543 Revision 1.103 2003/04/19 02:26:35 cheshire 1544 <rdar://problem/3233804> Incorrect goodbye packet after conflict 1545 1546 Revision 1.102 2003/04/17 03:06:28 cheshire 1547 <rdar://problem/3231321> No need to query again when a service goes away 1548 Set UnansweredQueries to 2 when receiving a "goodbye" packet 1549 1550 Revision 1.101 2003/04/15 20:58:31 jgraessl 1551 <rdar://problem/3229014> Added a hash to lookup records in the cache. 1552 1553 Revision 1.100 2003/04/15 18:53:14 cheshire 1554 <rdar://problem/3229064> Bug in ScheduleNextTask 1555 mDNS.c 1.94 incorrectly combined two "if" statements into one. 1556 1557 Revision 1.99 2003/04/15 18:09:13 jgraessl 1558 <rdar://problem/3228892> 1559 Reviewed by: Stuart Cheshire 1560 Added code to keep track of when the next cache item will expire so we can 1561 call TidyRRCache only when necessary. 1562 1563 Revision 1.98 2003/04/03 03:43:55 cheshire 1564 <rdar://problem/3216837> Off-by-one error in probe rate limiting 1565 1566 Revision 1.97 2003/04/02 01:48:17 cheshire 1567 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets 1568 Additional fix pointed out by Josh: 1569 Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state 1570 1571 Revision 1.96 2003/04/01 23:58:55 cheshire 1572 Minor comment changes 1573 1574 Revision 1.95 2003/04/01 23:46:05 cheshire 1575 <rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles 1576 mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface 1577 to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second 1578 window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in 1579 FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed. 1580 1581 Revision 1.94 2003/03/29 01:55:19 cheshire 1582 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets 1583 Solution: Major cleanup of packet timing and conflict handling rules 1584 1585 Revision 1.93 2003/03/28 01:54:36 cheshire 1586 Minor tidyup of IPv6 (AAAA) code 1587 1588 Revision 1.92 2003/03/27 03:30:55 cheshire 1589 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash 1590 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback 1591 Fixes: 1592 1. Make mDNS_DeregisterInterface() safe to call from a callback 1593 2. Make HostNameCallback() use DeadvertiseInterface() instead 1594 (it never really needed to deregister the interface at all) 1595 1596 Revision 1.91 2003/03/15 04:40:36 cheshire 1597 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" 1598 1599 Revision 1.90 2003/03/14 20:26:37 cheshire 1600 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf") 1601 1602 Revision 1.89 2003/03/12 19:57:50 cheshire 1603 Fixed typo in debug message 1604 1605 Revision 1.88 2003/03/12 00:17:44 cheshire 1606 <rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records 1607 1608 Revision 1.87 2003/03/11 01:27:20 cheshire 1609 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf") 1610 1611 Revision 1.86 2003/03/06 20:44:33 cheshire 1612 Comment tidyup 1613 1614 Revision 1.85 2003/03/05 03:38:35 cheshire 1615 <rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found! 1616 Fixed by leaving client in list after conflict, until client explicitly deallocates 1617 1618 Revision 1.84 2003/03/05 01:27:30 cheshire 1619 <rdar://problem/3185482> Different TTL for multicast versus unicast responses 1620 When building unicast responses, record TTLs are capped to 10 seconds 1621 1622 Revision 1.83 2003/03/04 23:48:52 cheshire 1623 <rdar://problem/3188865> Double probes after wake from sleep 1624 Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another 1625 1626 Revision 1.82 2003/03/04 23:38:29 cheshire 1627 <rdar://problem/3099194> mDNSResponder needs performance improvements 1628 Only set rr->CRActiveQuestion to point to the 1629 currently active representative of a question set 1630 1631 Revision 1.81 2003/02/21 03:35:34 cheshire 1632 <rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section 1633 1634 Revision 1.80 2003/02/21 02:47:53 cheshire 1635 <rdar://problem/3099194> mDNSResponder needs performance improvements 1636 Several places in the code were calling CacheRRActive(), which searched the entire 1637 question list every time, to see if this cache resource record answers any question. 1638 Instead, we now have a field "CRActiveQuestion" in the resource record structure 1639 1640 Revision 1.79 2003/02/21 01:54:07 cheshire 1641 <rdar://problem/3099194> mDNSResponder needs performance improvements 1642 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") 1643 1644 Revision 1.78 2003/02/20 06:48:32 cheshire 1645 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations 1646 Reviewed by: Josh Graessley, Bob Bradley 1647 1648 Revision 1.77 2003/01/31 03:35:59 cheshire 1649 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results 1650 When there were *two* active questions in the list, they were incorrectly 1651 finding *each other* and *both* being marked as duplicates of another question 1652 1653 Revision 1.76 2003/01/29 02:46:37 cheshire 1654 Fix for IPv6: 1655 A physical interface is identified solely by its InterfaceID (not by IP and type). 1656 On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts. 1657 In cases where the requested outbound protocol (v4 or v6) is not supported on 1658 that InterfaceID, the platform support layer should simply discard that packet. 1659 1660 Revision 1.75 2003/01/29 01:47:40 cheshire 1661 Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity 1662 1663 Revision 1.74 2003/01/28 05:26:25 cheshire 1664 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results 1665 Add 'Active' flag for interfaces 1666 1667 Revision 1.73 2003/01/28 03:45:12 cheshire 1668 Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)" 1669 1670 Revision 1.72 2003/01/28 01:49:48 cheshire 1671 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results 1672 FindDuplicateQuestion() was incorrectly finding the question itself in the list, 1673 and incorrectly marking it as a duplicate (of itself), so that it became inactive. 1674 1675 Revision 1.71 2003/01/28 01:41:44 cheshire 1676 <rdar://problem/3153091> Race condition when network change causes bad stuff 1677 When an interface goes away, interface-specific questions on that interface become orphaned. 1678 Orphan questions cause HaveQueries to return true, but there's no interface to send them on. 1679 Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions() 1680 1681 Revision 1.70 2003/01/23 19:00:20 cheshire 1682 Protect against infinite loops in mDNS_Execute 1683 1684 Revision 1.69 2003/01/21 22:56:32 jgraessl 1685 <rdar://problem/3124348> service name changes are not properly handled 1686 Submitted by: Stuart Cheshire 1687 Reviewed by: Joshua Graessley 1688 Applying changes for 3124348 to main branch. 3124348 changes went in to a 1689 branch for SU. 1690 1691 Revision 1.68 2003/01/17 04:09:27 cheshire 1692 <rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts 1693 1694 Revision 1.67 2003/01/17 03:56:45 cheshire 1695 Default 24-hour TTL is far too long. Changing to two hours. 1696 1697 Revision 1.66 2003/01/13 23:49:41 jgraessl 1698 Merged changes for the following fixes in to top of tree: 1699 <rdar://problem/3086540> computer name changes not handled properly 1700 <rdar://problem/3124348> service name changes are not properly handled 1701 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test 1702 1703 Revision 1.65 2002/12/23 22:13:28 jgraessl 1704 Reviewed by: Stuart Cheshire 1705 Initial IPv6 support for mDNSResponder. 1706 1707 Revision 1.64 2002/11/26 20:49:06 cheshire 1708 <rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit 1709 1710 Revision 1.63 2002/09/21 20:44:49 zarzycki 1711 Added APSL info 1712 1713 Revision 1.62 2002/09/20 03:25:37 cheshire 1714 Fix some compiler warnings 1715 1716 Revision 1.61 2002/09/20 01:05:24 cheshire 1717 Don't kill the Extras list in mDNS_DeregisterService() 1718 1719 Revision 1.60 2002/09/19 23:47:35 cheshire 1720 Added mDNS_RegisterNoSuchService() function for assertion of non-existence 1721 of a particular named service 1722 1723 Revision 1.59 2002/09/19 21:25:34 cheshire 1724 mDNS_snprintf() doesn't need to be in a separate file 1725 1726 Revision 1.58 2002/09/19 04:20:43 cheshire 1727 Remove high-ascii characters that confuse some systems 1728 1729 Revision 1.57 2002/09/17 01:07:08 cheshire 1730 Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init() 1731 1732 Revision 1.56 2002/09/16 19:44:17 cheshire 1733 Merge in license terms from Quinn's copy, in preparation for Darwin release 1734 */ 1735 1736 #pragma ident "%Z%%M% %I% %E% SMI" 1737 1738 #include "DNSCommon.h" // Defines general DNS untility routines 1739 #include "uDNS.h" // Defines entry points into unicast-specific routines 1740 // Disable certain benign warnings with Microsoft compilers 1741 #if(defined(_MSC_VER)) 1742 // Disable "conditional expression is constant" warning for debug macros. 1743 // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 1744 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 1745 #pragma warning(disable:4127) 1746 1747 // Disable "assignment within conditional expression". 1748 // Other compilers understand the convention that if you place the assignment expression within an extra pair 1749 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. 1750 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal 1751 // to the compiler that the assignment is intentional, we have to just turn this warning off completely. 1752 #pragma warning(disable:4706) 1753 #endif 1754 1755 // *************************************************************************** 1756 #if COMPILER_LIKES_PRAGMA_MARK 1757 #pragma mark - 1758 #pragma mark - Program Constants 1759 #endif 1760 1761 mDNSexport const mDNSIPPort zeroIPPort = { { 0 } }; 1762 mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } }; 1763 mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } }; 1764 mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } }; 1765 mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } }; 1766 mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } }; 1767 mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} }; 1768 1769 mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; 1770 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1; 1771 1772 mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0; 1773 1774 #define UnicastDNSPortAsNumber 53 1775 #define NATPMPPortAsNumber 5351 1776 #define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. 1777 #define MulticastDNSPortAsNumber 5353 1778 #define LoopbackIPCPortAsNumber 5354 1779 1780 mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; 1781 mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; 1782 mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; 1783 mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; 1784 mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; 1785 1786 mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; 1787 mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; 1788 mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; 1789 1790 mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; 1791 mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; 1792 mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; 1793 mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; 1794 mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; 1795 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; 1796 1797 // Any records bigger than this are considered 'large' records 1798 #define SmallRecordLimit 1024 1799 1800 #define kMaxUpdateCredits 10 1801 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) 1802 1803 mDNSexport const char *const mDNS_DomainTypeNames[] = 1804 { 1805 "b._dns-sd._udp.", // Browse 1806 "db._dns-sd._udp.", // Default Browse 1807 "lb._dns-sd._udp.", // Legacy Browse 1808 "r._dns-sd._udp.", // Registration 1809 "dr._dns-sd._udp." // Default Registration 1810 }; 1811 1812 #ifdef UNICAST_DISABLED 1813 #define uDNS_IsActiveQuery(q, u) mDNSfalse 1814 #endif 1815 1816 // *************************************************************************** 1817 #if COMPILER_LIKES_PRAGMA_MARK 1818 #pragma mark - 1819 #pragma mark - Specialized mDNS version of vsnprintf 1820 #endif 1821 1822 static const struct mDNSprintf_format 1823 { 1824 unsigned leftJustify : 1; 1825 unsigned forceSign : 1; 1826 unsigned zeroPad : 1; 1827 unsigned havePrecision : 1; 1828 unsigned hSize : 1; 1829 unsigned lSize : 1; 1830 char altForm; 1831 char sign; // +, - or space 1832 unsigned int fieldWidth; 1833 unsigned int precision; 1834 } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1835 1836 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) 1837 { 1838 mDNSu32 nwritten = 0; 1839 int c; 1840 if (buflen == 0) return(0); 1841 buflen--; // Pre-reserve one space in the buffer for the terminating null 1842 if (buflen == 0) goto exit; 1843 1844 for (c = *fmt; c != 0; c = *++fmt) 1845 { 1846 if (c != '%') 1847 { 1848 *sbuffer++ = (char)c; 1849 if (++nwritten >= buflen) goto exit; 1850 } 1851 else 1852 { 1853 unsigned int i=0, j; 1854 // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for 1855 // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. 1856 // The size needs to be enough for a 256-byte domain name plus some error text. 1857 #define mDNS_VACB_Size 300 1858 char mDNS_VACB[mDNS_VACB_Size]; 1859 #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) 1860 #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s)) 1861 char *s = mDNS_VACB_Lim, *digits; 1862 struct mDNSprintf_format F = mDNSprintf_format_default; 1863 1864 while (1) // decode flags 1865 { 1866 c = *++fmt; 1867 if (c == '-') F.leftJustify = 1; 1868 else if (c == '+') F.forceSign = 1; 1869 else if (c == ' ') F.sign = ' '; 1870 else if (c == '#') F.altForm++; 1871 else if (c == '0') F.zeroPad = 1; 1872 else break; 1873 } 1874 1875 if (c == '*') // decode field width 1876 { 1877 int f = va_arg(arg, int); 1878 if (f < 0) { f = -f; F.leftJustify = 1; } 1879 F.fieldWidth = (unsigned int)f; 1880 c = *++fmt; 1881 } 1882 else 1883 { 1884 for (; c >= '0' && c <= '9'; c = *++fmt) 1885 F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); 1886 } 1887 1888 if (c == '.') // decode precision 1889 { 1890 if ((c = *++fmt) == '*') 1891 { F.precision = va_arg(arg, unsigned int); c = *++fmt; } 1892 else for (; c >= '0' && c <= '9'; c = *++fmt) 1893 F.precision = (10 * F.precision) + (c - '0'); 1894 F.havePrecision = 1; 1895 } 1896 1897 if (F.leftJustify) F.zeroPad = 0; 1898 1899 conv: 1900 switch (c) // perform appropriate conversion 1901 { 1902 unsigned long n; 1903 case 'h' : F.hSize = 1; c = *++fmt; goto conv; 1904 case 'l' : // fall through 1905 case 'L' : F.lSize = 1; c = *++fmt; goto conv; 1906 case 'd' : 1907 case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long); 1908 else n = (unsigned long)va_arg(arg, int); 1909 if (F.hSize) n = (short) n; 1910 if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } 1911 else if (F.forceSign) F.sign = '+'; 1912 goto decimal; 1913 case 'u' : if (F.lSize) n = va_arg(arg, unsigned long); 1914 else n = va_arg(arg, unsigned int); 1915 if (F.hSize) n = (unsigned short) n; 1916 F.sign = 0; 1917 goto decimal; 1918 decimal: if (!F.havePrecision) 1919 { 1920 if (F.zeroPad) 1921 { 1922 F.precision = F.fieldWidth; 1923 if (F.sign) --F.precision; 1924 } 1925 if (F.precision < 1) F.precision = 1; 1926 } 1927 if (F.precision > mDNS_VACB_Size - 1) 1928 F.precision = mDNS_VACB_Size - 1; 1929 for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0'); 1930 for (; i < F.precision; i++) *--s = '0'; 1931 if (F.sign) { *--s = F.sign; i++; } 1932 break; 1933 1934 case 'o' : if (F.lSize) n = va_arg(arg, unsigned long); 1935 else n = va_arg(arg, unsigned int); 1936 if (F.hSize) n = (unsigned short) n; 1937 if (!F.havePrecision) 1938 { 1939 if (F.zeroPad) F.precision = F.fieldWidth; 1940 if (F.precision < 1) F.precision = 1; 1941 } 1942 if (F.precision > mDNS_VACB_Size - 1) 1943 F.precision = mDNS_VACB_Size - 1; 1944 for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0'); 1945 if (F.altForm && i && *s != '0') { *--s = '0'; i++; } 1946 for (; i < F.precision; i++) *--s = '0'; 1947 break; 1948 1949 case 'a' : { 1950 unsigned char *a = va_arg(arg, unsigned char *); 1951 if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 1952 else 1953 { 1954 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 1955 if (F.altForm) 1956 { 1957 mDNSAddr *ip = (mDNSAddr*)a; 1958 switch (ip->type) 1959 { 1960 case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; 1961 case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; 1962 default: F.precision = 0; break; 1963 } 1964 } 1965 switch (F.precision) 1966 { 1967 case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d", 1968 a[0], a[1], a[2], a[3]); break; 1969 case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", 1970 a[0], a[1], a[2], a[3], a[4], a[5]); break; 1971 case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), 1972 "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", 1973 a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7], 1974 a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break; 1975 default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify" 1976 " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; 1977 } 1978 } 1979 } 1980 break; 1981 1982 case 'p' : F.havePrecision = F.lSize = 1; 1983 F.precision = 8; 1984 case 'X' : digits = "0123456789ABCDEF"; 1985 goto hexadecimal; 1986 case 'x' : digits = "0123456789abcdef"; 1987 hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long); 1988 else n = va_arg(arg, unsigned int); 1989 if (F.hSize) n = (unsigned short) n; 1990 if (!F.havePrecision) 1991 { 1992 if (F.zeroPad) 1993 { 1994 F.precision = F.fieldWidth; 1995 if (F.altForm) F.precision -= 2; 1996 } 1997 if (F.precision < 1) F.precision = 1; 1998 } 1999 if (F.precision > mDNS_VACB_Size - 1) 2000 F.precision = mDNS_VACB_Size - 1; 2001 for (i = 0; n; n /= 16, i++) *--s = digits[n % 16]; 2002 for (; i < F.precision; i++) *--s = '0'; 2003 if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } 2004 break; 2005 2006 case 'c' : *--s = (char)va_arg(arg, int); i = 1; break; 2007 2008 case 's' : s = va_arg(arg, char *); 2009 if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; } 2010 else switch (F.altForm) 2011 { 2012 case 0: i=0; 2013 if (!F.havePrecision) // C string 2014 while(s[i]) i++; 2015 else 2016 { 2017 while ((i < F.precision) && s[i]) i++; 2018 // Make sure we don't truncate in the middle of a UTF-8 character 2019 // If last character we got was any kind of UTF-8 multi-byte character, 2020 // then see if we have to back up. 2021 // This is not as easy as the similar checks below, because 2022 // here we can't assume it's safe to examine the *next* byte, so we 2023 // have to confine ourselves to working only backwards in the string. 2024 j = i; // Record where we got to 2025 // Now, back up until we find first non-continuation-char 2026 while (i>0 && (s[i-1] & 0xC0) == 0x80) i--; 2027 // Now s[i-1] is the first non-continuation-char 2028 // and (j-i) is the number of continuation-chars we found 2029 if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char 2030 { 2031 i--; // Tentatively eliminate this start-char as well 2032 // Now (j-i) is the number of characters we're considering eliminating. 2033 // To be legal UTF-8, the start-char must contain (j-i) one-bits, 2034 // followed by a zero bit. If we shift it right by (7-(j-i)) bits 2035 // (with sign extension) then the result has to be 0xFE. 2036 // If this is right, then we reinstate the tentatively eliminated bytes. 2037 if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j; 2038 } 2039 } 2040 break; 2041 case 1: i = (unsigned char) *s++; break; // Pascal string 2042 case 2: { // DNS label-sequence name 2043 unsigned char *a = (unsigned char *)s; 2044 s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end 2045 if (*a == 0) *s++ = '.'; // Special case for root DNS name 2046 while (*a) 2047 { 2048 if (*a > 63) 2049 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; } 2050 if (s + *a >= &mDNS_VACB[254]) 2051 { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; } 2052 s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a); 2053 a += 1 + *a; 2054 } 2055 i = (mDNSu32)(s - mDNS_VACB); 2056 s = mDNS_VACB; // Reset s back to the start of the buffer 2057 break; 2058 } 2059 } 2060 // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below) 2061 if (F.havePrecision && i > F.precision) 2062 { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } 2063 break; 2064 2065 case 'n' : s = va_arg(arg, char *); 2066 if (F.hSize) * (short *) s = (short)nwritten; 2067 else if (F.lSize) * (long *) s = (long)nwritten; 2068 else * (int *) s = (int)nwritten; 2069 continue; 2070 2071 default: s = mDNS_VACB; 2072 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c); 2073 2074 case '%' : *sbuffer++ = (char)c; 2075 if (++nwritten >= buflen) goto exit; 2076 break; 2077 } 2078 2079 if (i < F.fieldWidth && !F.leftJustify) // Pad on the left 2080 do { 2081 *sbuffer++ = ' '; 2082 if (++nwritten >= buflen) goto exit; 2083 } while (i < --F.fieldWidth); 2084 2085 // Make sure we don't truncate in the middle of a UTF-8 character. 2086 // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the 2087 // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, 2088 // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly 2089 // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). 2090 if (i > buflen - nwritten) 2091 { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } 2092 for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result 2093 nwritten += i; 2094 if (nwritten >= buflen) goto exit; 2095 2096 for (; i < F.fieldWidth; i++) // Pad on the right 2097 { 2098 *sbuffer++ = ' '; 2099 if (++nwritten >= buflen) goto exit; 2100 } 2101 } 2102 } 2103 exit: 2104 *sbuffer++ = 0; 2105 return(nwritten); 2106 } 2107 2108 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) 2109 { 2110 mDNSu32 length; 2111 2112 va_list ptr; 2113 va_start(ptr,fmt); 2114 length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr); 2115 va_end(ptr); 2116 2117 return(length); 2118 } 2119 2120 // *************************************************************************** 2121 #if COMPILER_LIKES_PRAGMA_MARK 2122 #pragma mark - 2123 #pragma mark - General Utility Functions 2124 #endif 2125 2126 #define InitialQuestionInterval (mDNSPlatformOneSecond/2) 2127 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf) 2128 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0) 2129 2130 mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) 2131 { 2132 if (ActiveQuestion(q)) 2133 if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0) 2134 m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval); 2135 } 2136 2137 mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 2138 { 2139 CacheGroup *cg; 2140 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) 2141 if (cg->namehash == namehash && SameDomainName(cg->name, name)) 2142 break; 2143 return(cg); 2144 } 2145 2146 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 2147 { 2148 return(CacheGroupForName(m, slot, rr->namehash, rr->name)); 2149 } 2150 2151 mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) 2152 { 2153 NetworkInterfaceInfo *intf; 2154 2155 if (addr->type == mDNSAddrType_IPv4) 2156 { 2157 if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue); 2158 for (intf = m->HostInterfaces; intf; intf = intf->next) 2159 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 2160 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) 2161 return(mDNStrue); 2162 } 2163 2164 if (addr->type == mDNSAddrType_IPv6) 2165 { 2166 if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue); 2167 for (intf = m->HostInterfaces; intf; intf = intf->next) 2168 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 2169 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && 2170 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && 2171 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && 2172 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) 2173 return(mDNStrue); 2174 } 2175 2176 return(mDNSfalse); 2177 } 2178 2179 // Set up a AuthRecord with sensible default values. 2180 // These defaults may be overwritten with new values before mDNS_Register is called 2181 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, 2182 mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context) 2183 { 2184 mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo)); 2185 // Don't try to store a TTL bigger than we can represent in platform time units 2186 if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond) 2187 ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond; 2188 else if (ttl == 0) // And Zero TTL is illegal 2189 ttl = DefaultTTLforRRType(rrtype); 2190 2191 // Field Group 1: The actual information pertaining to this resource record 2192 rr->resrec.RecordType = RecordType; 2193 rr->resrec.InterfaceID = InterfaceID; 2194 rr->resrec.name = &rr->namestorage; 2195 rr->resrec.rrtype = rrtype; 2196 rr->resrec.rrclass = kDNSClass_IN; 2197 rr->resrec.rroriginalttl = ttl; 2198 // rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal 2199 // rr->resrec.rdestimate = set in mDNS_Register_internal 2200 // rr->resrec.rdata = MUST be set by client 2201 2202 if (RDataStorage) 2203 rr->resrec.rdata = RDataStorage; 2204 else 2205 { 2206 rr->resrec.rdata = &rr->rdatastorage; 2207 rr->resrec.rdata->MaxRDLength = sizeof(RDataBody); 2208 } 2209 2210 // Field Group 2: Persistent metadata for Authoritative Records 2211 rr->Additional1 = mDNSNULL; 2212 rr->Additional2 = mDNSNULL; 2213 rr->DependentOn = mDNSNULL; 2214 rr->RRSet = mDNSNULL; 2215 rr->RecordCallback = Callback; 2216 rr->RecordContext = Context; 2217 2218 rr->HostTarget = mDNSfalse; 2219 rr->AllowRemoteQuery = mDNSfalse; 2220 rr->ForceMCast = mDNSfalse; 2221 2222 // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal) 2223 2224 rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() 2225 } 2226 2227 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord 2228 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion() 2229 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord) 2230 { 2231 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it 2232 if (AddRecord) rr->LocalAnswer = mDNStrue; 2233 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2234 if (q->QuestionCallback) 2235 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 2236 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2237 } 2238 2239 // When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers 2240 // to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). 2241 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any. 2242 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal() 2243 mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord) 2244 { 2245 if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set"); 2246 2247 m->CurrentQuestion = m->LocalOnlyQuestions; 2248 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) 2249 { 2250 DNSQuestion *q = m->CurrentQuestion; 2251 m->CurrentQuestion = q->next; 2252 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 2253 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again 2254 } 2255 2256 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions 2257 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 2258 { 2259 m->CurrentQuestion = m->Questions; 2260 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 2261 { 2262 DNSQuestion *q = m->CurrentQuestion; 2263 m->CurrentQuestion = q->next; 2264 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 2265 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again 2266 } 2267 } 2268 2269 m->CurrentQuestion = mDNSNULL; 2270 } 2271 2272 // *************************************************************************** 2273 #if COMPILER_LIKES_PRAGMA_MARK 2274 #pragma mark - 2275 #pragma mark - Resource Record Utility Functions 2276 #endif 2277 2278 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) 2279 2280 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ 2281 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 2282 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 2283 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) 2284 2285 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ 2286 (ResourceRecordIsValidAnswer(RR) && \ 2287 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) 2288 2289 #define DefaultProbeCountForTypeUnique ((mDNSu8)3) 2290 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) 2291 2292 #define InitialAnnounceCount ((mDNSu8)10) 2293 2294 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. 2295 // This means that because the announce interval is doubled after sending the first packet, the first 2296 // observed on-the-wire inter-packet interval between announcements is actually one second. 2297 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. 2298 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) 2299 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) 2300 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) 2301 2302 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \ 2303 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \ 2304 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0) 2305 2306 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) 2307 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) 2308 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) 2309 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) 2310 2311 #define MaxUnansweredQueries 4 2312 2313 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent 2314 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). 2315 // TTL and rdata may differ. 2316 // This is used for cache flush management: 2317 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent 2318 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed 2319 mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2) 2320 { 2321 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } 2322 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } 2323 if (r1->InterfaceID && 2324 r2->InterfaceID && 2325 r1->InterfaceID != r2->InterfaceID) return(mDNSfalse); 2326 return(mDNSBool)( 2327 r1->rrtype == r2->rrtype && 2328 r1->rrclass == r2->rrclass && 2329 r1->namehash == r2->namehash && 2330 SameDomainName(r1->name, r2->name)); 2331 } 2332 2333 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our 2334 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have 2335 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. 2336 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, 2337 // so a response of any type should match, even if it is not actually the type the client plans to use. 2338 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) 2339 { 2340 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } 2341 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } 2342 if (pktrr->resrec.InterfaceID && 2343 authrr->resrec.InterfaceID && 2344 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); 2345 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); 2346 return(mDNSBool)( 2347 pktrr->resrec.rrclass == authrr->resrec.rrclass && 2348 pktrr->resrec.namehash == authrr->resrec.namehash && 2349 SameDomainName(pktrr->resrec.name, authrr->resrec.name)); 2350 } 2351 2352 // IdenticalResourceRecord returns true if two resources records have 2353 // the same name, type, class, and identical rdata (InterfaceID and TTL may differ) 2354 mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) 2355 { 2356 if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); } 2357 if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); } 2358 if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) 2359 return(mDNSfalse); 2360 return(SameRData(r1, r2)); 2361 } 2362 2363 // CacheRecord *ks is the CacheRecord from the known answer list in the query. 2364 // This is the information that the requester believes to be correct. 2365 // AuthRecord *rr is the answer we are proposing to give, if not suppressed. 2366 // This is the information that we believe to be correct. 2367 // We've already determined that we plan to give this answer on this interface 2368 // (either the record is non-specific, or it is specific to this interface) 2369 // so now we just need to check the name, type, class, rdata and TTL. 2370 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) 2371 { 2372 // If RR signature is different, or data is different, then don't suppress our answer 2373 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); 2374 2375 // If the requester's indicated TTL is less than half the real TTL, 2376 // we need to give our answer before the requester's copy expires. 2377 // If the requester's indicated TTL is at least half the real TTL, 2378 // then we can suppress our answer this time. 2379 // If the requester's indicated TTL is greater than the TTL we believe, 2380 // then that's okay, and we don't need to do anything about it. 2381 // (If two responders on the network are offering the same information, 2382 // that's okay, and if they are offering the information with different TTLs, 2383 // the one offering the lower TTL should defer to the one offering the higher TTL.) 2384 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); 2385 } 2386 2387 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) 2388 { 2389 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 2390 { 2391 //LogMsg("ProbeCount %d Next %ld %s", 2392 // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); 2393 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 2394 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); 2395 } 2396 else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr)) 2397 { 2398 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 2399 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 2400 } 2401 } 2402 2403 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) 2404 { 2405 // To allow us to aggregate probes when a group of services are registered together, 2406 // the first probe is delayed 1/4 second. This means the common-case behaviour is: 2407 // 1/4 second wait; probe 2408 // 1/4 second wait; probe 2409 // 1/4 second wait; probe 2410 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) 2411 2412 // If we have no probe suppression time set, or it is in the past, set it now 2413 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) 2414 { 2415 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique); 2416 // If we already have a probe scheduled to go out sooner, then use that time to get better aggregation 2417 if (m->SuppressProbes - m->NextScheduledProbe >= 0) 2418 m->SuppressProbes = m->NextScheduledProbe; 2419 // If we already have a query scheduled to go out sooner, then use that time to get better aggregation 2420 if (m->SuppressProbes - m->NextScheduledQuery >= 0) 2421 m->SuppressProbes = m->NextScheduledQuery; 2422 } 2423 2424 // We announce to flush stale data from other caches. It is a reasonable assumption that any 2425 // old stale copies will probably have the same TTL we're using, so announcing longer than 2426 // this serves no purpose -- any stale copies of that record will have expired by then anyway. 2427 rr->AnnounceUntil = m->timenow + TicksTTL(rr); 2428 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; 2429 // Set LastMCTime to now, to inhibit multicast responses 2430 // (no need to send additional multicast responses when we're announcing anyway) 2431 rr->LastMCTime = m->timenow; 2432 rr->LastMCInterface = mDNSInterfaceMark; 2433 2434 // If this is a record type that's not going to probe, then delay its first announcement so that 2435 // it will go out synchronized with the first announcement for the other records that *are* probing. 2436 // This is a minor performance tweak that helps keep groups of related records synchronized together. 2437 // The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are 2438 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. 2439 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, 2440 // because they will meet the criterion of being at least half-way to their scheduled announcement time. 2441 if (rr->resrec.RecordType != kDNSRecordTypeUnique) 2442 rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; 2443 2444 SetNextAnnounceProbeTime(m, rr); 2445 } 2446 2447 #define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS) 2448 2449 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) 2450 { 2451 domainname *target = GetRRDomainNameTarget(&rr->resrec); 2452 2453 if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype); 2454 2455 if (target && SameDomainName(target, &m->MulticastHostname)) 2456 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); 2457 2458 if (target && !SameDomainName(target, &m->MulticastHostname)) 2459 { 2460 AssignDomainName(target, &m->MulticastHostname); 2461 SetNewRData(&rr->resrec, mDNSNULL, 0); 2462 2463 // If we're in the middle of probing this record, we need to start again, 2464 // because changing its rdata may change the outcome of the tie-breaker. 2465 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) 2466 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 2467 2468 // If we've announced this record, we really should send a goodbye packet for the old rdata before 2469 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, 2470 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. 2471 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) 2472 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", 2473 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2474 2475 rr->AnnounceCount = InitialAnnounceCount; 2476 rr->RequireGoodbye = mDNSfalse; 2477 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); 2478 InitializeLastAPTime(m,rr); 2479 } 2480 } 2481 2482 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) 2483 { 2484 if (!rr->Acknowledged && rr->RecordCallback) 2485 { 2486 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 2487 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 2488 rr->Acknowledged = mDNStrue; 2489 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2490 rr->RecordCallback(m, rr, mStatus_NoError); 2491 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2492 } 2493 } 2494 2495 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified 2496 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ 2497 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified)) 2498 #define RecordIsLocalDuplicate(A,B) \ 2499 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) 2500 2501 mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) 2502 { 2503 domainname *target = GetRRDomainNameTarget(&rr->resrec); 2504 AuthRecord *r; 2505 AuthRecord **p = &m->ResourceRecords; 2506 AuthRecord **d = &m->DuplicateRecords; 2507 2508 mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo)); 2509 2510 if ((mDNSs32)rr->resrec.rroriginalttl <= 0) 2511 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 2512 2513 #ifndef UNICAST_DISABLED 2514 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)) 2515 rr->uDNS_info.id = zeroID; 2516 else return uDNS_RegisterRecord(m, rr); 2517 #endif 2518 2519 while (*p && *p != rr) p=&(*p)->next; 2520 while (*d && *d != rr) d=&(*d)->next; 2521 if (*d || *p) 2522 { 2523 LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", 2524 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2525 return(mStatus_AlreadyRegistered); 2526 } 2527 2528 if (rr->DependentOn) 2529 { 2530 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 2531 rr->resrec.RecordType = kDNSRecordTypeVerified; 2532 else 2533 { 2534 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", 2535 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2536 return(mStatus_Invalid); 2537 } 2538 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified))) 2539 { 2540 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", 2541 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); 2542 return(mStatus_Invalid); 2543 } 2544 } 2545 2546 // If this resource record is referencing a specific interface, make sure it exists 2547 if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 2548 { 2549 NetworkInterfaceInfo *intf; 2550 for (intf = m->HostInterfaces; intf; intf = intf->next) 2551 if (intf->InterfaceID == rr->resrec.InterfaceID) break; 2552 if (!intf) 2553 { 2554 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); 2555 return(mStatus_BadReferenceErr); 2556 } 2557 } 2558 2559 rr->next = mDNSNULL; 2560 2561 // Field Group 1: Persistent metadata for Authoritative Records 2562 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2563 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2564 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2565 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2566 // rr->Callback = already set in mDNS_SetupResourceRecord 2567 // rr->Context = already set in mDNS_SetupResourceRecord 2568 // rr->RecordType = already set in mDNS_SetupResourceRecord 2569 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 2570 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 2571 // Make sure target is not uninitialized data, or we may crash writing debugging log messages 2572 if (rr->HostTarget && target) target->c[0] = 0; 2573 2574 // Field Group 2: Transient state for Authoritative Records 2575 rr->Acknowledged = mDNSfalse; 2576 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 2577 rr->AnnounceCount = InitialAnnounceCount; 2578 rr->RequireGoodbye = mDNSfalse; 2579 rr->LocalAnswer = mDNSfalse; 2580 rr->IncludeInProbe = mDNSfalse; 2581 rr->ImmedAnswer = mDNSNULL; 2582 rr->ImmedUnicast = mDNSfalse; 2583 rr->ImmedAdditional = mDNSNULL; 2584 rr->SendRNow = mDNSNULL; 2585 rr->v4Requester = zerov4Addr; 2586 rr->v6Requester = zerov6Addr; 2587 rr->NextResponse = mDNSNULL; 2588 rr->NR_AnswerTo = mDNSNULL; 2589 rr->NR_AdditionalTo = mDNSNULL; 2590 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); 2591 if (!rr->HostTarget) InitializeLastAPTime(m, rr); 2592 // rr->AnnounceUntil = Set for us in InitializeLastAPTime() 2593 // rr->LastAPTime = Set for us in InitializeLastAPTime() 2594 // rr->LastMCTime = Set for us in InitializeLastAPTime() 2595 // rr->LastMCInterface = Set for us in InitializeLastAPTime() 2596 rr->NewRData = mDNSNULL; 2597 rr->newrdlength = 0; 2598 rr->UpdateCallback = mDNSNULL; 2599 rr->UpdateCredits = kMaxUpdateCredits; 2600 rr->NextUpdateCredit = 0; 2601 rr->UpdateBlocked = 0; 2602 2603 // rr->resrec.interface = already set in mDNS_SetupResourceRecord 2604 // rr->resrec.name->c = MUST be set by client 2605 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord 2606 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord 2607 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord 2608 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set 2609 2610 if (rr->HostTarget) 2611 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); 2612 else 2613 { 2614 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); 2615 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); 2616 } 2617 2618 if (!ValidateDomainName(rr->resrec.name)) 2619 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 2620 2621 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 2622 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 2623 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 2624 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } 2625 2626 // Don't do this until *after* we've set rr->resrec.rdlength 2627 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) 2628 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 2629 2630 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 2631 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u); 2632 2633 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 2634 { 2635 // If this is supposed to be unique, make sure we don't have any name conflicts 2636 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2637 { 2638 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; 2639 for (r = m->ResourceRecords; r; r=r->next) 2640 { 2641 const AuthRecord *s2 = r->RRSet ? r->RRSet : r; 2642 if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec)) 2643 break; 2644 } 2645 if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback 2646 { 2647 debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2648 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 2649 rr->resrec.rroriginalttl = 0; 2650 rr->ImmedAnswer = mDNSInterfaceMark; 2651 m->NextScheduledResponse = m->timenow; 2652 } 2653 } 2654 } 2655 2656 // Now that we've finished building our new record, make sure it's not identical to one we already have 2657 for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break; 2658 2659 if (r) 2660 { 2661 debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr)); 2662 *d = rr; 2663 // If the previous copy of this record is already verified unique, 2664 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. 2665 // Setting ProbeCount to zero will cause SendQueries() to advance this record to 2666 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. 2667 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) 2668 rr->ProbeCount = 0; 2669 } 2670 else 2671 { 2672 debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr)); 2673 if (!m->NewLocalRecords) m->NewLocalRecords = rr; 2674 *p = rr; 2675 } 2676 2677 // For records that are not going to probe, acknowledge them right away 2678 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) 2679 AcknowledgeRecord(m, rr); 2680 2681 return(mStatus_NoError); 2682 } 2683 2684 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) 2685 { 2686 m->ProbeFailTime = m->timenow; 2687 m->NumFailedProbes++; 2688 // If we've had fifteen or more probe failures, rate-limit to one every five seconds. 2689 // If a bunch of hosts have all been configured with the same name, then they'll all 2690 // conflict and run through the same series of names: name-2, name-3, name-4, etc., 2691 // up to name-10. After that they'll start adding random increments in the range 1-100, 2692 // so they're more likely to branch out in the available namespace and settle on a set of 2693 // unique names quickly. If after five more tries the host is still conflicting, then we 2694 // may have a serious problem, so we start rate-limiting so we don't melt down the network. 2695 if (m->NumFailedProbes >= 15) 2696 { 2697 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 2698 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", 2699 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2700 } 2701 } 2702 2703 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) 2704 { 2705 RData *OldRData = rr->resrec.rdata; 2706 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata 2707 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 2708 if (rr->UpdateCallback) 2709 rr->UpdateCallback(m, rr, OldRData); // ... and let the client know 2710 } 2711 2712 // mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal 2713 // mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict 2714 // mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered 2715 typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type; 2716 2717 // NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. 2718 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 2719 mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) 2720 { 2721 AuthRecord *r2; 2722 mDNSu8 RecordType = rr->resrec.RecordType; 2723 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 2724 2725 #ifndef UNICAST_DISABLED 2726 if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))) 2727 return uDNS_DeregisterRecord(m, rr); 2728 #endif 2729 2730 while (*p && *p != rr) p=&(*p)->next; 2731 2732 if (*p) 2733 { 2734 // We found our record on the main list. See if there are any duplicates that need special handling. 2735 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment 2736 { 2737 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished 2738 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. 2739 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; 2740 } 2741 else 2742 { 2743 // Before we delete the record (and potentially send a goodbye packet) 2744 // first see if we have a record on the duplicate list ready to take over from it. 2745 AuthRecord **d = &m->DuplicateRecords; 2746 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; 2747 if (*d) 2748 { 2749 AuthRecord *dup = *d; 2750 debugf("Duplicate record %p taking over from %p %##s (%s)", 2751 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2752 *d = dup->next; // Cut replacement record from DuplicateRecords list 2753 dup->next = rr->next; // And then... 2754 rr->next = dup; // ... splice it in right after the record we're about to delete 2755 dup->resrec.RecordType = rr->resrec.RecordType; 2756 dup->ProbeCount = rr->ProbeCount; 2757 dup->AnnounceCount = rr->AnnounceCount; 2758 dup->RequireGoodbye = rr->RequireGoodbye; 2759 dup->ImmedAnswer = rr->ImmedAnswer; 2760 dup->ImmedUnicast = rr->ImmedUnicast; 2761 dup->ImmedAdditional = rr->ImmedAdditional; 2762 dup->v4Requester = rr->v4Requester; 2763 dup->v6Requester = rr->v6Requester; 2764 dup->ThisAPInterval = rr->ThisAPInterval; 2765 dup->AnnounceUntil = rr->AnnounceUntil; 2766 dup->LastAPTime = rr->LastAPTime; 2767 dup->LastMCTime = rr->LastMCTime; 2768 dup->LastMCInterface = rr->LastMCInterface; 2769 rr->RequireGoodbye = mDNSfalse; 2770 } 2771 } 2772 } 2773 else 2774 { 2775 // We didn't find our record on the main list; try the DuplicateRecords list instead. 2776 p = &m->DuplicateRecords; 2777 while (*p && *p != rr) p=&(*p)->next; 2778 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it 2779 if (*p) rr->RequireGoodbye = mDNSfalse; 2780 if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", 2781 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2782 } 2783 2784 if (!*p) 2785 { 2786 // No need to log an error message if we already know this is a potentially repeated deregistration 2787 if (drt != mDNS_Dereg_repeat) 2788 LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", 2789 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2790 return(mStatus_BadReferenceErr); 2791 } 2792 2793 // If this is a shared record and we've announced it at least once, 2794 // we need to retract that announcement before we delete the record 2795 if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 2796 { 2797 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", 2798 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2799 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 2800 rr->resrec.rroriginalttl = 0; 2801 rr->ImmedAnswer = mDNSInterfaceMark; 2802 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) 2803 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); 2804 } 2805 else 2806 { 2807 *p = rr->next; // Cut this record from the list 2808 // If someone is about to look at this, bump the pointer forward 2809 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; 2810 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; 2811 rr->next = mDNSNULL; 2812 2813 if (RecordType == kDNSRecordTypeUnregistered) 2814 debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered", 2815 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2816 else if (RecordType == kDNSRecordTypeDeregistering) 2817 debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering", 2818 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2819 else 2820 { 2821 verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", 2822 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2823 rr->resrec.RecordType = kDNSRecordTypeUnregistered; 2824 } 2825 2826 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) 2827 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", 2828 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2829 2830 // If we have an update queued up which never executed, give the client a chance to free that memory 2831 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 2832 2833 if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse); 2834 2835 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 2836 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 2837 // In this case the likely client action to the mStatus_MemFree message is to free the memory, 2838 // so any attempt to touch rr after this is likely to lead to a crash. 2839 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 2840 if (drt != mDNS_Dereg_conflict) 2841 { 2842 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this 2843 } 2844 else 2845 { 2846 RecordProbeFailure(m, rr); 2847 if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this 2848 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. 2849 // Note that with all the client callbacks going on, by the time we get here all the 2850 // records we marked may have been explicitly deregistered by the client anyway. 2851 r2 = m->DuplicateRecords; 2852 while (r2) 2853 { 2854 if (r2->ProbeCount != 0xFF) r2 = r2->next; 2855 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } 2856 } 2857 } 2858 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 2859 } 2860 return(mStatus_NoError); 2861 } 2862 2863 // *************************************************************************** 2864 #if COMPILER_LIKES_PRAGMA_MARK 2865 #pragma mark - 2866 #pragma mark - 2867 #pragma mark - Packet Sending Functions 2868 #endif 2869 2870 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) 2871 { 2872 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) 2873 { 2874 **nrpp = rr; 2875 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) 2876 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does 2877 // The referenced record will definitely be acceptable (by recursive application of this rule) 2878 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; 2879 rr->NR_AdditionalTo = add; 2880 *nrpp = &rr->NextResponse; 2881 } 2882 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2883 } 2884 2885 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) 2886 { 2887 AuthRecord *rr, *rr2; 2888 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put 2889 { 2890 // (Note: This is an "if", not a "while". If we add a record, we'll find it again 2891 // later in the "for" loop, and we will follow further "additional" links then.) 2892 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) 2893 AddRecordToResponseList(nrpp, rr->Additional1, rr); 2894 2895 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) 2896 AddRecordToResponseList(nrpp, rr->Additional2, rr); 2897 2898 // For SRV records, automatically add the Address record(s) for the target host 2899 if (rr->resrec.rrtype == kDNSType_SRV) 2900 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 2901 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 2902 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 2903 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target 2904 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) 2905 AddRecordToResponseList(nrpp, rr2, rr); 2906 } 2907 } 2908 2909 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) 2910 { 2911 AuthRecord *rr; 2912 AuthRecord *ResponseRecords = mDNSNULL; 2913 AuthRecord **nrp = &ResponseRecords; 2914 2915 // Make a list of all our records that need to be unicast to this destination 2916 for (rr = m->ResourceRecords; rr; rr=rr->next) 2917 { 2918 // If we find we can no longer unicast this answer, clear ImmedUnicast 2919 if (rr->ImmedAnswer == mDNSInterfaceMark || 2920 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || 2921 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) 2922 rr->ImmedUnicast = mDNSfalse; 2923 2924 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) 2925 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || 2926 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) 2927 { 2928 rr->ImmedAnswer = mDNSNULL; // Clear the state fields 2929 rr->ImmedUnicast = mDNSfalse; 2930 rr->v4Requester = zerov4Addr; 2931 rr->v6Requester = zerov6Addr; 2932 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo 2933 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } 2934 } 2935 } 2936 2937 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 2938 2939 while (ResponseRecords) 2940 { 2941 mDNSu8 *responseptr = m->omsg.data; 2942 mDNSu8 *newptr; 2943 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 2944 2945 // Put answers in the packet 2946 while (ResponseRecords && ResponseRecords->NR_AnswerTo) 2947 { 2948 rr = ResponseRecords; 2949 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2950 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2951 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); 2952 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2953 if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now 2954 if (newptr) responseptr = newptr; 2955 ResponseRecords = rr->NextResponse; 2956 rr->NextResponse = mDNSNULL; 2957 rr->NR_AnswerTo = mDNSNULL; 2958 rr->NR_AdditionalTo = mDNSNULL; 2959 rr->RequireGoodbye = mDNStrue; 2960 } 2961 2962 // Add additionals, if there's space 2963 while (ResponseRecords && !ResponseRecords->NR_AnswerTo) 2964 { 2965 rr = ResponseRecords; 2966 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2967 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2968 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec); 2969 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2970 2971 if (newptr) responseptr = newptr; 2972 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue; 2973 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark; 2974 ResponseRecords = rr->NextResponse; 2975 rr->NextResponse = mDNSNULL; 2976 rr->NR_AnswerTo = mDNSNULL; 2977 rr->NR_AdditionalTo = mDNSNULL; 2978 } 2979 2980 if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL); 2981 } 2982 } 2983 2984 mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr) 2985 { 2986 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() 2987 // that it should go ahead and immediately dispose of this registration 2988 rr->resrec.RecordType = kDNSRecordTypeShared; 2989 rr->RequireGoodbye = mDNSfalse; 2990 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this 2991 } 2992 2993 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change 2994 // the record list and/or question list. 2995 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 2996 mDNSlocal void DiscardDeregistrations(mDNS *const m) 2997 { 2998 if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set"); 2999 m->CurrentRecord = m->ResourceRecords; 3000 3001 while (m->CurrentRecord) 3002 { 3003 AuthRecord *rr = m->CurrentRecord; 3004 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 3005 CompleteDeregistration(m, rr); // Don't touch rr after this 3006 else 3007 m->CurrentRecord = rr->next; 3008 } 3009 } 3010 3011 mDNSlocal void GrantUpdateCredit(AuthRecord *rr) 3012 { 3013 if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; 3014 else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval); 3015 } 3016 3017 // Note about acceleration of announcements to facilitate automatic coalescing of 3018 // multiple independent threads of announcements into a single synchronized thread: 3019 // The announcements in the packet may be at different stages of maturity; 3020 // One-second interval, two-second interval, four-second interval, and so on. 3021 // After we've put in all the announcements that are due, we then consider 3022 // whether there are other nearly-due announcements that are worth accelerating. 3023 // To be eligible for acceleration, a record MUST NOT be older (further along 3024 // its timeline) than the most mature record we've already put in the packet. 3025 // In other words, younger records can have their timelines accelerated to catch up 3026 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync. 3027 // Older records cannot have their timelines accelerated; this would just widen 3028 // the gap between them and their younger bretheren and get them even more out of sync. 3029 3030 // NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change 3031 // the record list and/or question list. 3032 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3033 mDNSlocal void SendResponses(mDNS *const m) 3034 { 3035 int pktcount = 0; 3036 AuthRecord *rr, *r2; 3037 mDNSs32 maxExistingAnnounceInterval = 0; 3038 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 3039 3040 m->NextScheduledResponse = m->timenow + 0x78000000; 3041 3042 for (rr = m->ResourceRecords; rr; rr=rr->next) 3043 if (rr->ImmedUnicast) 3044 { 3045 mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} }; 3046 mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} }; 3047 v4.ip.v4 = rr->v4Requester; 3048 v6.ip.v6 = rr->v6Requester; 3049 if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer); 3050 if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer); 3051 if (rr->ImmedUnicast) 3052 { 3053 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr)); 3054 rr->ImmedUnicast = mDNSfalse; 3055 } 3056 } 3057 3058 // *** 3059 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on 3060 // *** 3061 3062 // Run through our list of records, and decide which ones we're going to announce on all interfaces 3063 for (rr = m->ResourceRecords; rr; rr=rr->next) 3064 { 3065 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 3066 if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr)) 3067 { 3068 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 3069 if (maxExistingAnnounceInterval < rr->ThisAPInterval) 3070 maxExistingAnnounceInterval = rr->ThisAPInterval; 3071 if (rr->UpdateBlocked) rr->UpdateBlocked = 0; 3072 } 3073 } 3074 3075 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one) 3076 // Eligible records that are more than half-way to their announcement time are accelerated 3077 for (rr = m->ResourceRecords; rr; rr=rr->next) 3078 if ((rr->resrec.InterfaceID && rr->ImmedAnswer) || 3079 (rr->ThisAPInterval <= maxExistingAnnounceInterval && 3080 TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) && 3081 ResourceRecordIsValidAnswer(rr))) 3082 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 3083 3084 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals 3085 // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID, 3086 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen) 3087 // then all that means is that it won't get sent -- which would not be the end of the world. 3088 for (rr = m->ResourceRecords; rr; rr=rr->next) 3089 if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV) 3090 for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records 3091 if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ... 3092 ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ... 3093 rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ... 3094 rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target 3095 SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) && 3096 (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID)) 3097 r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too 3098 3099 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give 3100 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class 3101 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a 3102 // record, then other RRSet members that have not been sent recently will get flushed out of client caches. 3103 // -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface 3104 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces 3105 for (rr = m->ResourceRecords; rr; rr=rr->next) 3106 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 3107 { 3108 if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked 3109 { 3110 for (r2 = m->ResourceRecords; r2; r2=r2->next) 3111 if (ResourceRecordIsValidAnswer(r2)) 3112 if (r2->ImmedAnswer != mDNSInterfaceMark && 3113 r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec)) 3114 r2->ImmedAnswer = rr->ImmedAnswer; 3115 } 3116 else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked 3117 { 3118 for (r2 = m->ResourceRecords; r2; r2=r2->next) 3119 if (ResourceRecordIsValidAnswer(r2)) 3120 if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec)) 3121 r2->ImmedAdditional = rr->ImmedAdditional; 3122 } 3123 } 3124 3125 // Now set SendRNow state appropriately 3126 for (rr = m->ResourceRecords; rr; rr=rr->next) 3127 { 3128 if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces 3129 { 3130 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID; 3131 rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer 3132 rr->LastMCTime = m->timenow; 3133 rr->LastMCInterface = rr->ImmedAnswer; 3134 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done 3135 if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2)) 3136 { 3137 rr->AnnounceCount--; 3138 rr->ThisAPInterval *= 2; 3139 rr->LastAPTime = m->timenow; 3140 if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0; 3141 debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount); 3142 } 3143 } 3144 else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface: 3145 { 3146 rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface 3147 rr->ImmedAdditional = mDNSNULL; // No need to send as additional too 3148 rr->LastMCTime = m->timenow; 3149 rr->LastMCInterface = rr->ImmedAnswer; 3150 } 3151 SetNextAnnounceProbeTime(m, rr); 3152 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr)); 3153 } 3154 3155 // *** 3156 // *** 2. Loop through interface list, sending records as appropriate 3157 // *** 3158 3159 while (intf) 3160 { 3161 int numDereg = 0; 3162 int numAnnounce = 0; 3163 int numAnswer = 0; 3164 mDNSu8 *responseptr = m->omsg.data; 3165 mDNSu8 *newptr; 3166 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 3167 3168 // First Pass. Look for: 3169 // 1. Deregistering records that need to send their goodbye packet 3170 // 2. Updated records that need to retract their old data 3171 // 3. Answers and announcements we need to send 3172 // In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can 3173 // send this packet and then try again. 3174 // If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway, 3175 // because otherwise we'll end up in an infinite loop trying to send a record that will never fit. 3176 for (rr = m->ResourceRecords; rr; rr=rr->next) 3177 if (rr->SendRNow == intf->InterfaceID) 3178 { 3179 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 3180 { 3181 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 3182 if (!newptr && m->omsg.h.numAnswers) break; 3183 numDereg++; 3184 responseptr = newptr; 3185 } 3186 else if (rr->NewRData && !m->SleepState) // If we have new data for this record 3187 { 3188 RData *OldRData = rr->resrec.rdata; 3189 mDNSu16 oldrdlength = rr->resrec.rdlength; 3190 // See if we should send a courtesy "goodbye" for the old data before we replace it. 3191 if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye) 3192 { 3193 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 3194 if (!newptr && m->omsg.h.numAnswers) break; 3195 numDereg++; 3196 responseptr = newptr; 3197 rr->RequireGoodbye = mDNSfalse; 3198 } 3199 // Now try to see if we can fit the update in the same packet (not fatal if we can't) 3200 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); 3201 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 3202 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 3203 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); 3204 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 3205 if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; } 3206 SetNewRData(&rr->resrec, OldRData, oldrdlength); 3207 } 3208 else 3209 { 3210 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 3211 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 3212 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl); 3213 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 3214 if (!newptr && m->omsg.h.numAnswers) break; 3215 rr->RequireGoodbye = (mDNSu8) (!m->SleepState); 3216 if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; 3217 responseptr = newptr; 3218 } 3219 // If sending on all interfaces, go to next interface; else we're finished now 3220 if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) 3221 rr->SendRNow = GetNextActiveInterfaceID(intf); 3222 else 3223 rr->SendRNow = mDNSNULL; 3224 } 3225 3226 // Second Pass. Add additional records, if there's space. 3227 newptr = responseptr; 3228 for (rr = m->ResourceRecords; rr; rr=rr->next) 3229 if (rr->ImmedAdditional == intf->InterfaceID) 3230 if (ResourceRecordIsValidAnswer(rr)) 3231 { 3232 // If we have at least one answer already in the packet, then plan to add additionals too 3233 mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0); 3234 3235 // If we're not planning to send any additionals, but this record is a unique one, then 3236 // make sure we haven't already sent any other members of its RRSet -- if we have, then they 3237 // will have had the cache flush bit set, so now we need to finish the job and send the rest. 3238 if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)) 3239 { 3240 const AuthRecord *a; 3241 for (a = m->ResourceRecords; a; a=a->next) 3242 if (a->LastMCTime == m->timenow && 3243 a->LastMCInterface == intf->InterfaceID && 3244 SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; } 3245 } 3246 if (!SendAdditional) // If we don't want to send this after all, 3247 rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field 3248 else if (newptr) // Else, try to add it if we can 3249 { 3250 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 3251 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 3252 newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec); 3253 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 3254 if (newptr) 3255 { 3256 responseptr = newptr; 3257 rr->ImmedAdditional = mDNSNULL; 3258 rr->RequireGoodbye = mDNStrue; 3259 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface. 3260 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise, 3261 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get 3262 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches. 3263 rr->LastMCTime = m->timenow; 3264 rr->LastMCInterface = intf->InterfaceID; 3265 } 3266 } 3267 } 3268 3269 if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals) 3270 { 3271 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p", 3272 numDereg, numDereg == 1 ? "" : "s", 3273 numAnnounce, numAnnounce == 1 ? "" : "s", 3274 numAnswer, numAnswer == 1 ? "" : "s", 3275 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID); 3276 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL); 3277 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL); 3278 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 3279 if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; } 3280 // There might be more things to send on this interface, so go around one more time and try again. 3281 } 3282 else // Nothing more to send on this interface; go to next 3283 { 3284 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 3285 #if MDNS_DEBUGMSGS && 0 3286 const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p"; 3287 debugf(msg, intf, next); 3288 #endif 3289 intf = next; 3290 } 3291 } 3292 3293 // *** 3294 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables 3295 // *** 3296 3297 if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set"); 3298 m->CurrentRecord = m->ResourceRecords; 3299 while (m->CurrentRecord) 3300 { 3301 rr = m->CurrentRecord; 3302 m->CurrentRecord = rr->next; 3303 3304 if (rr->SendRNow) 3305 { 3306 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 3307 LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr)); 3308 rr->SendRNow = mDNSNULL; 3309 } 3310 3311 if (rr->ImmedAnswer) 3312 { 3313 if (rr->NewRData) CompleteRDataUpdate(m,rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 3314 3315 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 3316 CompleteDeregistration(m, rr); // Don't touch rr after this 3317 else 3318 { 3319 rr->ImmedAnswer = mDNSNULL; 3320 rr->ImmedUnicast = mDNSfalse; 3321 rr->v4Requester = zerov4Addr; 3322 rr->v6Requester = zerov6Addr; 3323 } 3324 } 3325 } 3326 verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow); 3327 } 3328 3329 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache, 3330 // so we want to be lazy about how frequently we do it. 3331 // 1. If a cache record is currently referenced by *no* active questions, 3332 // then we don't mind expiring it up to a minute late (who will know?) 3333 // 2. Else, if a cache record is due for some of its final expiration queries, 3334 // we'll allow them to be late by up to 2% of the TTL 3335 // 3. Else, if a cache record has completed all its final expiration queries without success, 3336 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late 3337 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets), 3338 // so allow at most 1/10 second lateness 3339 #define CacheCheckGracePeriod(RR) ( \ 3340 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \ 3341 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \ 3342 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \ 3343 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : (mDNSPlatformOneSecond/10)) 3344 3345 // Note: MUST call SetNextCacheCheckTime any time we change: 3346 // rr->TimeRcvd 3347 // rr->resrec.rroriginalttl 3348 // rr->UnansweredQueries 3349 // rr->CRActiveQuestion 3350 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary 3351 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime 3352 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr) 3353 { 3354 rr->NextRequiredQuery = RRExpireTime(rr); 3355 3356 // If we have an active question, then see if we want to schedule a refresher query for this record. 3357 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL. 3358 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 3359 { 3360 rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries); 3361 rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50); 3362 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks", 3363 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), 3364 (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr)); 3365 } 3366 3367 if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0) 3368 m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)); 3369 3370 if (rr->DelayDelivery) 3371 if (m->NextCacheCheck - rr->DelayDelivery > 0) 3372 m->NextCacheCheck = rr->DelayDelivery; 3373 } 3374 3375 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) 3376 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5) 3377 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 15) 3378 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30) 3379 3380 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval) 3381 { 3382 if (interval < kMinimumReconfirmTime) 3383 interval = kMinimumReconfirmTime; 3384 if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below 3385 interval = 0x10000000; 3386 3387 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration 3388 if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3)) 3389 { 3390 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts 3391 // For all the reconfirmations in a given batch, we want to use the same random value 3392 // so that the reconfirmation questions can be grouped into a single query packet 3393 if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF); 3394 interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3); 3395 rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; 3396 rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; 3397 SetNextCacheCheckTime(m, rr); 3398 } 3399 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr)); 3400 return(mStatus_NoError); 3401 } 3402 3403 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond) 3404 3405 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr. 3406 // It also appends to the list of known answer records that need to be included, 3407 // and updates the forcast for the size of the known answer section. 3408 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q, 3409 CacheRecord ***kalistptrptr, mDNSu32 *answerforecast) 3410 { 3411 mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353; 3412 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 3413 const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData; 3414 mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit)); 3415 if (!newptr) 3416 { 3417 debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c); 3418 return(mDNSfalse); 3419 } 3420 else if (newptr + *answerforecast >= limit) 3421 { 3422 verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d", 3423 q->qname.c, newptr + *answerforecast - query->data); 3424 query->h.numQuestions--; 3425 return(mDNSfalse); 3426 } 3427 else 3428 { 3429 mDNSu32 forecast = *answerforecast; 3430 const mDNSu32 slot = HashSlot(&q->qname); 3431 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 3432 CacheRecord *rr; 3433 CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update 3434 3435 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 3436 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 3437 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list 3438 rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 3439 ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 3440 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away 3441 mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1) 3442 { 3443 *ka = rr; // Link this record into our known answer chain 3444 ka = &rr->NextInKAList; 3445 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3446 forecast += 12 + rr->resrec.rdestimate; 3447 // If we're trying to put more than one question in this packet, and it doesn't fit 3448 // then undo that last question and try again next time 3449 if (query->h.numQuestions > 1 && newptr + forecast >= limit) 3450 { 3451 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d", 3452 q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data); 3453 query->h.numQuestions--; 3454 ka = *kalistptrptr; // Go back to where we started and retract these answer records 3455 while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; } 3456 return(mDNSfalse); // Return false, so we'll try again in the next packet 3457 } 3458 } 3459 3460 // Traffic reduction: 3461 // If we already have at least one unique answer in the cache, 3462 // OR we have so many shared answers that the KA list is too big to fit in one packet 3463 // The we suppress queries number 3 and 5: 3464 // Query 1 (immediately; ThisQInterval = 1 sec; request unicast replies) 3465 // Query 2 (after 1 second; ThisQInterval = 2 sec; send normally) 3466 // Query 3 (after 2 seconds; ThisQInterval = 4 sec; may suppress) 3467 // Query 4 (after 4 seconds; ThisQInterval = 8 sec; send normally) 3468 // Query 5 (after 8 seconds; ThisQInterval = 16 sec; may suppress) 3469 // Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally) 3470 if (q->UniqueAnswers || newptr + forecast >= limit) 3471 if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32) 3472 { 3473 query->h.numQuestions--; 3474 ka = *kalistptrptr; // Go back to where we started and retract these answer records 3475 while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; } 3476 return(mDNStrue); // Return true: pretend we succeeded, even though we actually suppressed this question 3477 } 3478 3479 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return 3480 *queryptr = newptr; // Update the packet pointer 3481 *answerforecast = forecast; // Update the forecast 3482 *kalistptrptr = ka; // Update the known answer list pointer 3483 if (ucast) m->ExpectUnicastResponse = m->timenow; 3484 3485 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache, 3486 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 3487 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list 3488 ResourceRecordAnswersQuestion(&rr->resrec, q)) // which answers our question 3489 { 3490 rr->UnansweredQueries++; // indicate that we're expecting a response 3491 rr->LastUnansweredTime = m->timenow; 3492 SetNextCacheCheckTime(m, rr); 3493 } 3494 3495 return(mDNStrue); 3496 } 3497 } 3498 3499 mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q) 3500 { 3501 mDNSu32 slot; 3502 CacheGroup *cg; 3503 CacheRecord *rr; 3504 domainname *target; 3505 FORALL_CACHERECORDS(slot, cg, rr) 3506 if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname)) 3507 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); 3508 } 3509 3510 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active 3511 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time) 3512 { 3513 int i; 3514 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 3515 } 3516 3517 mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID) 3518 { 3519 int i; 3520 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 3521 } 3522 3523 mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf) 3524 { 3525 int i; 3526 mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query 3527 mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query 3528 for (i=0; i<DupSuppressInfoSize; i++) 3529 if (ds[i].InterfaceID == intf->InterfaceID) 3530 { 3531 if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue; 3532 else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue; 3533 if (v4 && v6) return(mDNStrue); 3534 } 3535 return(mDNSfalse); 3536 } 3537 3538 mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type) 3539 { 3540 int i, j; 3541 3542 // See if we have this one in our list somewhere already 3543 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break; 3544 3545 // If not, find a slot we can re-use 3546 if (i >= DupSuppressInfoSize) 3547 { 3548 i = 0; 3549 for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++) 3550 if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0) 3551 i = j; 3552 } 3553 3554 // Record the info about this query we saw 3555 ds[i].Time = Time; 3556 ds[i].InterfaceID = InterfaceID; 3557 ds[i].Type = Type; 3558 3559 return(i); 3560 } 3561 3562 mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) 3563 { 3564 // If more than 90% of the way to the query time, we should unconditionally accelerate it 3565 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10)) 3566 return(mDNStrue); 3567 3568 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet 3569 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2)) 3570 { 3571 // We forecast: qname (n) type (2) class (2) 3572 mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4; 3573 const mDNSu32 slot = HashSlot(&q->qname); 3574 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 3575 CacheRecord *rr; 3576 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 3577 if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 3578 ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 3579 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry 3580 rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery 3581 { 3582 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3583 forecast += 12 + rr->resrec.rdestimate; 3584 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate 3585 } 3586 return(mDNStrue); 3587 } 3588 3589 return(mDNSfalse); 3590 } 3591 3592 // How Standard Queries are generated: 3593 // 1. The Question Section contains the question 3594 // 2. The Additional Section contains answers we already know, to suppress duplicate responses 3595 3596 // How Probe Queries are generated: 3597 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because 3598 // if some other host is already using *any* records with this name, we want to know about it. 3599 // 2. The Authority Section contains the proposed values we intend to use for one or more 3600 // of our records with that name (analogous to the Update section of DNS Update packets) 3601 // because if some other host is probing at the same time, we each want to know what the other is 3602 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't. 3603 3604 mDNSlocal void SendQueries(mDNS *const m) 3605 { 3606 mDNSu32 slot; 3607 CacheGroup *cg; 3608 CacheRecord *cr; 3609 AuthRecord *ar; 3610 int pktcount = 0; 3611 DNSQuestion *q; 3612 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval 3613 mDNSs32 maxExistingQuestionInterval = 0; 3614 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 3615 CacheRecord *KnownAnswerList = mDNSNULL; 3616 3617 // 1. If time for a query, work out what we need to do 3618 if (m->timenow - m->NextScheduledQuery >= 0) 3619 { 3620 CacheRecord *rr; 3621 m->NextScheduledQuery = m->timenow + 0x78000000; 3622 3623 // We're expecting to send a query anyway, so see if any expiring cache records are close enough 3624 // to their NextRequiredQuery to be worth batching them together with this one 3625 FORALL_CACHERECORDS(slot, cg, rr) 3626 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 3627 if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0) 3628 { 3629 q = rr->CRActiveQuestion; 3630 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID); 3631 if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If unicast query, mark it 3632 else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID; 3633 else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark; 3634 } 3635 3636 // Scan our list of questions to see which *unicast* queries need to be sent 3637 for (q = m->Questions; q; q=q->next) 3638 if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow))) 3639 { 3640 mDNSu8 *qptr = m->omsg.data; 3641 const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data); 3642 InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags); 3643 qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass); 3644 mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL); 3645 q->ThisQInterval *= 2; 3646 if (q->ThisQInterval > MaxQuestionInterval) 3647 q->ThisQInterval = MaxQuestionInterval; 3648 q->LastQTime = m->timenow; 3649 q->LastQTxTime = m->timenow; 3650 q->RecentAnswerPkts = 0; 3651 q->SendQNow = mDNSNULL; 3652 m->ExpectUnicastResponse = m->timenow; 3653 } 3654 3655 // Scan our list of questions to see which *multicast* queries we're definitely going to send 3656 for (q = m->Questions; q; q=q->next) 3657 if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow)) 3658 { 3659 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 3660 if (maxExistingQuestionInterval < q->ThisQInterval) 3661 maxExistingQuestionInterval = q->ThisQInterval; 3662 } 3663 3664 // Scan our list of questions 3665 // (a) to see if there are any more that are worth accelerating, and 3666 // (b) to update the state variables for *all* the questions we're going to send 3667 for (q = m->Questions; q; q=q->next) 3668 { 3669 if (q->SendQNow || 3670 (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))) 3671 { 3672 // If at least halfway to next query time, advance to next interval 3673 // If less than halfway to next query time, then 3674 // treat this as logically a repeat of the last transmission, without advancing the interval 3675 if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0) 3676 { 3677 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 3678 q->ThisQInterval *= 2; 3679 if (q->ThisQInterval > MaxQuestionInterval) 3680 q->ThisQInterval = MaxQuestionInterval; 3681 else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8) 3682 { 3683 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", 3684 q->qname.c, DNSTypeName(q->qtype)); 3685 ReconfirmAntecedents(m, q); // Sending third query, and no answers yet; time to begin doubting the source 3686 } 3687 } 3688 3689 // Mark for sending. (If no active interfaces, then don't even try.) 3690 q->SendOnAll = (q->SendQNow == mDNSInterfaceMark); 3691 if (q->SendOnAll) 3692 { 3693 q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID; 3694 q->LastQTime = m->timenow; 3695 } 3696 3697 // If we recorded a duplicate suppression for this question less than half an interval ago, 3698 // then we consider it recent enough that we don't need to do an identical query ourselves. 3699 ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2); 3700 3701 q->LastQTxTime = m->timenow; 3702 q->RecentAnswerPkts = 0; 3703 if (q->RequestUnicast) q->RequestUnicast--; 3704 } 3705 // For all questions (not just the ones we're sending) check what the next scheduled event will be 3706 SetNextQueryTime(m,q); 3707 } 3708 } 3709 3710 // 2. Scan our authoritative RR list to see what probes we might need to send 3711 if (m->timenow - m->NextScheduledProbe >= 0) 3712 { 3713 m->NextScheduledProbe = m->timenow + 0x78000000; 3714 3715 if (m->CurrentRecord) LogMsg("SendQueries: ERROR m->CurrentRecord already set"); 3716 m->CurrentRecord = m->ResourceRecords; 3717 while (m->CurrentRecord) 3718 { 3719 AuthRecord *rr = m->CurrentRecord; 3720 m->CurrentRecord = rr->next; 3721 if (rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing... 3722 { 3723 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly 3724 if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0) 3725 { 3726 SetNextAnnounceProbeTime(m, rr); 3727 } 3728 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly 3729 else if (rr->ProbeCount) 3730 { 3731 // Mark for sending. (If no active interfaces, then don't even try.) 3732 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID; 3733 rr->LastAPTime = m->timenow; 3734 rr->ProbeCount--; 3735 SetNextAnnounceProbeTime(m, rr); 3736 } 3737 // else, if it has now finished probing, move it to state Verified, 3738 // and update m->NextScheduledResponse so it will be announced 3739 else 3740 { 3741 AuthRecord *r2; 3742 rr->resrec.RecordType = kDNSRecordTypeVerified; 3743 rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique; 3744 rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique; 3745 SetNextAnnounceProbeTime(m, rr); 3746 // If we have any records on our duplicate list that match this one, they have now also completed probing 3747 for (r2 = m->DuplicateRecords; r2; r2=r2->next) 3748 if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr)) 3749 r2->ProbeCount = 0; 3750 AcknowledgeRecord(m, rr); 3751 } 3752 } 3753 } 3754 m->CurrentRecord = m->DuplicateRecords; 3755 while (m->CurrentRecord) 3756 { 3757 AuthRecord *rr = m->CurrentRecord; 3758 m->CurrentRecord = rr->next; 3759 if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0) 3760 AcknowledgeRecord(m, rr); 3761 } 3762 } 3763 3764 // 3. Now we know which queries and probes we're sending, 3765 // go through our interface list sending the appropriate queries on each interface 3766 while (intf) 3767 { 3768 AuthRecord *rr; 3769 mDNSu8 *queryptr = m->omsg.data; 3770 InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags); 3771 if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet"); 3772 if (!KnownAnswerList) 3773 { 3774 // Start a new known-answer list 3775 CacheRecord **kalistptr = &KnownAnswerList; 3776 mDNSu32 answerforecast = 0; 3777 3778 // Put query questions in this packet 3779 for (q = m->Questions; q; q=q->next) 3780 if (q->SendQNow == intf->InterfaceID) 3781 { 3782 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d", 3783 SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ", 3784 q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data); 3785 // If we're suppressing this question, or we successfully put it, update its SendQNow state 3786 if (SuppressOnThisInterface(q->DupSuppress, intf) || 3787 BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) 3788 q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); 3789 } 3790 3791 // Put probe questions in this packet 3792 for (rr = m->ResourceRecords; rr; rr=rr->next) 3793 if (rr->SendRNow == intf->InterfaceID) 3794 { 3795 mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353; 3796 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 3797 const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData); 3798 mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit)); 3799 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3800 mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate; 3801 if (newptr && newptr + forecast < limit) 3802 { 3803 queryptr = newptr; 3804 answerforecast = forecast; 3805 rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); 3806 rr->IncludeInProbe = mDNStrue; 3807 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", 3808 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount); 3809 } 3810 else 3811 { 3812 verbosedebugf("SendQueries: Retracting Question %##s (%s)", 3813 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 3814 m->omsg.h.numQuestions--; 3815 } 3816 } 3817 } 3818 3819 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) 3820 while (KnownAnswerList) 3821 { 3822 CacheRecord *rr = KnownAnswerList; 3823 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; 3824 mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd); 3825 if (newptr) 3826 { 3827 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", 3828 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); 3829 queryptr = newptr; 3830 KnownAnswerList = rr->NextInKAList; 3831 rr->NextInKAList = mDNSNULL; 3832 } 3833 else 3834 { 3835 // If we ran out of space and we have more than one question in the packet, that's an error -- 3836 // we shouldn't have put more than one question if there was a risk of us running out of space. 3837 if (m->omsg.h.numQuestions > 1) 3838 LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers); 3839 m->omsg.h.flags.b[0] |= kDNSFlag0_TC; 3840 break; 3841 } 3842 } 3843 3844 for (rr = m->ResourceRecords; rr; rr=rr->next) 3845 if (rr->IncludeInProbe) 3846 { 3847 mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec); 3848 rr->IncludeInProbe = mDNSfalse; 3849 if (newptr) queryptr = newptr; 3850 else LogMsg("SendQueries: How did we fail to have space for the Update record %##s (%s)?", 3851 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 3852 } 3853 3854 if (queryptr > m->omsg.data) 3855 { 3856 if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1) 3857 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions); 3858 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p", 3859 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 3860 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 3861 m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID); 3862 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL); 3863 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL); 3864 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 3865 if (++pktcount >= 1000) 3866 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; } 3867 // There might be more records left in the known answer list, or more questions to send 3868 // on this interface, so go around one more time and try again. 3869 } 3870 else // Nothing more to send on this interface; go to next 3871 { 3872 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 3873 #if MDNS_DEBUGMSGS && 0 3874 const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p"; 3875 debugf(msg, intf, next); 3876 #endif 3877 intf = next; 3878 } 3879 } 3880 3881 // 4. Final housekeeping 3882 3883 // 4a. Debugging check: Make sure we announced all our records 3884 for (ar = m->ResourceRecords; ar; ar=ar->next) 3885 if (ar->SendRNow) 3886 { 3887 if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) 3888 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar)); 3889 ar->SendRNow = mDNSNULL; 3890 } 3891 3892 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope 3893 // that their interface which went away might come back again, the logic will want to send queries 3894 // for those records, but we can't because their interface isn't here any more, so to keep the 3895 // state machine ticking over we just pretend we did so. 3896 // If the interface does not come back in time, the cache record will expire naturally 3897 FORALL_CACHERECORDS(slot, cg, cr) 3898 if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0) 3899 { 3900 cr->UnansweredQueries++; 3901 cr->CRActiveQuestion->SendQNow = mDNSNULL; 3902 SetNextCacheCheckTime(m, cr); 3903 } 3904 3905 // 4c. Debugging check: Make sure we sent all our planned questions 3906 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions 3907 // we legitimately couldn't send because the interface is no longer available 3908 for (q = m->Questions; q; q=q->next) 3909 if (q->SendQNow) 3910 { 3911 LogMsg("SendQueries: No active interface to send: %##s %s", q->qname.c, DNSTypeName(q->qtype)); 3912 q->SendQNow = mDNSNULL; 3913 } 3914 } 3915 3916 // *************************************************************************** 3917 #if COMPILER_LIKES_PRAGMA_MARK 3918 #pragma mark - 3919 #pragma mark - RR List Management & Task Management 3920 #endif 3921 3922 // NOTE: AnswerQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. 3923 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3924 mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord) 3925 { 3926 verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)", 3927 q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 3928 3929 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue) 3930 // may be called twice, once when the record is received, and again when it's time to notify local clients. 3931 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this. 3932 3933 rr->LastUsed = m->timenow; 3934 if (ActiveQuestion(q) && rr->CRActiveQuestion != q) 3935 { 3936 if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count 3937 rr->CRActiveQuestion = q; // We know q is non-null 3938 SetNextCacheCheckTime(m, rr); 3939 } 3940 3941 // If this is: 3942 // (a) a no-cache add, where we've already done at least one 'QM' query, or 3943 // (b) a normal add, where we have at least one unique-type answer, 3944 // then there's no need to keep polling the network. 3945 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.) 3946 if ((AddRecord == 2 && !q->RequestUnicast) || 3947 (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) 3948 if (ActiveQuestion(q)) 3949 { 3950 q->LastQTime = m->timenow; 3951 q->LastQTxTime = m->timenow; 3952 q->RecentAnswerPkts = 0; 3953 q->ThisQInterval = MaxQuestionInterval; 3954 q->RequestUnicast = mDNSfalse; 3955 } 3956 3957 if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us 3958 3959 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 3960 if (q->QuestionCallback) 3961 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 3962 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 3963 // CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function 3964 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 3965 // Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv() 3966 // and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions 3967 // being deleted out from under them. 3968 } 3969 3970 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) 3971 { 3972 rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared 3973 if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set"); 3974 m->CurrentQuestion = m->Questions; 3975 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3976 { 3977 DNSQuestion *q = m->CurrentQuestion; 3978 m->CurrentQuestion = q->next; 3979 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3980 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); 3981 } 3982 m->CurrentQuestion = mDNSNULL; 3983 } 3984 3985 mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot) 3986 { 3987 const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second 3988 const mDNSs32 start = m->timenow - 0x10000000; 3989 mDNSs32 delay = start; 3990 CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); 3991 CacheRecord *rr; 3992 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 3993 if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name)) 3994 if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second 3995 if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted 3996 delay = RRExpireTime(rr); 3997 if (delay - start > 0) return(NonZeroTime(delay)); 3998 else return(0); 3999 } 4000 4001 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 4002 // If new questions are created as a result of invoking client callbacks, they will be added to 4003 // the end of the question list, and m->NewQuestions will be set to indicate the first new question. 4004 // rr is a new CacheRecord just received into our cache 4005 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 4006 // NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback, 4007 // which may change the record list and/or question list. 4008 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4009 mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) 4010 { 4011 if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set"); 4012 m->CurrentQuestion = m->Questions; 4013 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 4014 { 4015 DNSQuestion *q = m->CurrentQuestion; 4016 m->CurrentQuestion = q->next; 4017 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4018 { 4019 // If this question is one that's actively sending queries, and it's received ten answers within one 4020 // second of sending the last query packet, then that indicates some radical network topology change, 4021 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval 4022 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating 4023 // because we will anyway send another query within a few seconds. The first reset query is sent out 4024 // randomized over the next four seconds to reduce possible synchronization between machines. 4025 if (q->LastAnswerPktNum != m->PktNum) 4026 { 4027 q->LastAnswerPktNum = m->PktNum; 4028 if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && 4029 q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) 4030 { 4031 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence", 4032 q->qname.c, DNSTypeName(q->qtype)); 4033 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); 4034 q->ThisQInterval = InitialQuestionInterval; 4035 SetNextQueryTime(m,q); 4036 } 4037 } 4038 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", 4039 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl); 4040 q->CurrentAnswers++; 4041 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 4042 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 4043 if (q->CurrentAnswers > 4000) 4044 { 4045 static int msgcount = 0; 4046 if (msgcount++ < 10) 4047 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", 4048 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); 4049 rr->resrec.rroriginalttl = 1; 4050 rr->UnansweredQueries = MaxUnansweredQueries; 4051 } 4052 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); 4053 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() 4054 } 4055 } 4056 m->CurrentQuestion = mDNSNULL; 4057 SetNextCacheCheckTime(m, rr); 4058 } 4059 4060 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 4061 // If new questions are created as a result of invoking client callbacks, they will be added to 4062 // the end of the question list, and m->NewQuestions will be set to indicate the first new question. 4063 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) 4064 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any 4065 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, 4066 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. 4067 // NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback, 4068 // which may change the record list and/or question list. 4069 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4070 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) 4071 { 4072 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); 4073 if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set"); 4074 m->CurrentQuestion = m->Questions; 4075 while (m->CurrentQuestion) 4076 { 4077 DNSQuestion *q = m->CurrentQuestion; 4078 m->CurrentQuestion = q->next; 4079 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4080 AnswerQuestionWithResourceRecord(m, q, rr, 2); // Value '2' indicates "don't expect 'remove' events for this" 4081 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() 4082 } 4083 m->CurrentQuestion = mDNSNULL; 4084 } 4085 4086 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute 4087 // If new questions are created as a result of invoking client callbacks, they will be added to 4088 // the end of the question list, and m->NewQuestions will be set to indicate the first new question. 4089 // rr is an existing cache CacheRecord that just expired and is being deleted 4090 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 4091 // NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback, 4092 // which may change the record list and/or question list. 4093 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4094 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) 4095 { 4096 if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set"); 4097 m->CurrentQuestion = m->Questions; 4098 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 4099 { 4100 DNSQuestion *q = m->CurrentQuestion; 4101 m->CurrentQuestion = q->next; 4102 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4103 { 4104 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); 4105 if (q->CurrentAnswers == 0) 4106 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", 4107 q, q->qname.c, DNSTypeName(q->qtype)); 4108 else 4109 { 4110 q->CurrentAnswers--; 4111 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; 4112 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; 4113 } 4114 if (q->CurrentAnswers == 0) 4115 { 4116 debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents", 4117 q->qname.c, DNSTypeName(q->qtype)); 4118 ReconfirmAntecedents(m, q); 4119 } 4120 q->FlappingInterface = mDNSNULL; 4121 AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse); 4122 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() 4123 } 4124 } 4125 m->CurrentQuestion = mDNSNULL; 4126 } 4127 4128 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) 4129 { 4130 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1 4131 unsigned int i; 4132 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 4133 #endif 4134 e->next = m->rrcache_free; 4135 m->rrcache_free = e; 4136 m->rrcache_totalused--; 4137 } 4138 4139 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) 4140 { 4141 CacheEntity *e = (CacheEntity *)(*cp); 4142 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); 4143 if ((*cp)->rrcache_tail != &(*cp)->members) 4144 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); 4145 //if ((*cp)->name != (domainname*)((*cp)->namestorage)) 4146 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); 4147 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 4148 (*cp)->name = mDNSNULL; 4149 *cp = (*cp)->next; // Cut record from list 4150 ReleaseCacheEntity(m, e); 4151 } 4152 4153 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) 4154 { 4155 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata); 4156 r->resrec.rdata = mDNSNULL; 4157 ReleaseCacheEntity(m, (CacheEntity *)r); 4158 } 4159 4160 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering 4161 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all 4162 // callbacks for old records are delivered before callbacks for newer records. 4163 mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg) 4164 { 4165 CacheRecord **rp = &cg->members; 4166 4167 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } 4168 m->lock_rrcache = 1; 4169 4170 while (*rp) 4171 { 4172 CacheRecord *const rr = *rp; 4173 mDNSs32 event = RRExpireTime(rr); 4174 if (m->timenow - event >= 0) // If expired, delete it 4175 { 4176 *rp = rr->next; // Cut it from the list 4177 verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr)); 4178 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away 4179 { 4180 CacheRecordRmv(m, rr); 4181 m->rrcache_active--; 4182 } 4183 ReleaseCacheRecord(m, rr); 4184 } 4185 else // else, not expired; see if we need to query 4186 { 4187 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) 4188 event = rr->DelayDelivery; 4189 else 4190 { 4191 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); 4192 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 4193 { 4194 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query 4195 event = rr->NextRequiredQuery; // then just record when we want the next query 4196 else // else trigger our question to go out now 4197 { 4198 // Set NextScheduledQuery to timenow so that SendQueries() will run. 4199 // SendQueries() will see that we have records close to expiration, and send FEQs for them. 4200 m->NextScheduledQuery = m->timenow; 4201 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(), 4202 // which will correctly update m->NextCacheCheck for us. 4203 event = m->timenow + 0x3FFFFFFF; 4204 } 4205 } 4206 } 4207 verbosedebugf("CheckCacheExpiration:%6d %5d %s", 4208 (event-m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); 4209 if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0) 4210 m->NextCacheCheck = (event + CacheCheckGracePeriod(rr)); 4211 rp = &rr->next; 4212 } 4213 } 4214 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); 4215 cg->rrcache_tail = rp; 4216 m->lock_rrcache = 0; 4217 } 4218 4219 mDNSlocal void AnswerNewQuestion(mDNS *const m) 4220 { 4221 mDNSBool ShouldQueryImmediately = mDNStrue; 4222 CacheRecord *rr; 4223 DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer 4224 const mDNSu32 slot = HashSlot(&q->qname); 4225 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 4226 4227 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4228 4229 if (cg) CheckCacheExpiration(m, cg); 4230 m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration(); 4231 4232 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); 4233 // This should be safe, because calling the client's question callback may cause the 4234 // question list to be modified, but should not ever cause the rrcache list to be modified. 4235 // If the client's question callback deletes the question, then m->CurrentQuestion will 4236 // be advanced, and we'll exit out of the loop 4237 m->lock_rrcache = 1; 4238 if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set"); 4239 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 4240 4241 if (q->InterfaceID == mDNSInterface_Any) // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records 4242 { 4243 if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set"); 4244 m->CurrentRecord = m->ResourceRecords; 4245 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 4246 { 4247 AuthRecord *rr = m->CurrentRecord; 4248 m->CurrentRecord = rr->next; 4249 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 4250 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4251 { 4252 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); 4253 // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord() 4254 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4255 } 4256 } 4257 m->CurrentRecord = mDNSNULL; 4258 } 4259 4260 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 4261 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4262 { 4263 // SecsSinceRcvd is whole number of elapsed seconds, rounded down 4264 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; 4265 if (rr->resrec.rroriginalttl <= SecsSinceRcvd) 4266 { 4267 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)", 4268 rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 4269 continue; // Go to next one in loop 4270 } 4271 4272 // If this record set is marked unique, then that means we can reasonably assume we have the whole set 4273 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there 4274 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) 4275 ShouldQueryImmediately = mDNSfalse; 4276 q->CurrentAnswers++; 4277 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 4278 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 4279 AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); 4280 // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() 4281 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4282 } 4283 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) 4284 if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname)) 4285 ShouldQueryImmediately = mDNSfalse; 4286 4287 if (ShouldQueryImmediately && m->CurrentQuestion == q) 4288 { 4289 q->ThisQInterval = InitialQuestionInterval; 4290 q->LastQTime = m->timenow - q->ThisQInterval; 4291 m->NextScheduledQuery = m->timenow; 4292 } 4293 m->CurrentQuestion = mDNSNULL; 4294 m->lock_rrcache = 0; 4295 } 4296 4297 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any 4298 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions 4299 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) 4300 { 4301 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer 4302 m->NewLocalOnlyQuestions = q->next; // Advance NewQuestions to the next (if any) 4303 4304 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4305 4306 if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set"); 4307 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 4308 4309 if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set"); 4310 m->CurrentRecord = m->ResourceRecords; 4311 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 4312 { 4313 AuthRecord *rr = m->CurrentRecord; 4314 m->CurrentRecord = rr->next; 4315 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4316 { 4317 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); 4318 // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord() 4319 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4320 } 4321 } 4322 4323 m->CurrentQuestion = mDNSNULL; 4324 m->CurrentRecord = mDNSNULL; 4325 } 4326 4327 mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) 4328 { 4329 CacheEntity *e = mDNSNULL; 4330 4331 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 4332 m->lock_rrcache = 1; 4333 4334 // If we have no free records, ask the client layer to give us some more memory 4335 if (!m->rrcache_free && m->MainCallback) 4336 { 4337 if (m->rrcache_totalused != m->rrcache_size) 4338 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", 4339 m->rrcache_totalused, m->rrcache_size); 4340 4341 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite 4342 // number of bogus records so that we keep growing our cache until the machine runs out of memory. 4343 // To guard against this, if we're actively using less than 1/32 of our cache, then we 4344 // purge all the unused records and recycle them, instead of allocating more memory. 4345 if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active) 4346 debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", 4347 m->rrcache_size, m->rrcache_active); 4348 else 4349 { 4350 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 4351 m->MainCallback(m, mStatus_GrowCache); 4352 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 4353 } 4354 } 4355 4356 // If we still have no free records, recycle all the records we can. 4357 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 4358 if (!m->rrcache_free) 4359 { 4360 #if MDNS_DEBUGMSGS 4361 mDNSu32 oldtotalused = m->rrcache_totalused; 4362 #endif 4363 mDNSu32 slot; 4364 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4365 { 4366 CacheGroup **cp = &m->rrcache_hash[slot]; 4367 while (*cp) 4368 { 4369 CacheRecord **rp = &(*cp)->members; 4370 while (*rp) 4371 { 4372 // Records that answer still-active questions are not candidates for recycling 4373 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash 4374 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) 4375 rp=&(*rp)->next; 4376 else 4377 { 4378 CacheRecord *rr = *rp; 4379 *rp = (*rp)->next; // Cut record from list 4380 ReleaseCacheRecord(m, rr); 4381 } 4382 } 4383 if ((*cp)->rrcache_tail != rp) 4384 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); 4385 (*cp)->rrcache_tail = rp; 4386 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; 4387 else ReleaseCacheGroup(m, cp); 4388 } 4389 } 4390 #if MDNS_DEBUGMSGS 4391 debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused); 4392 #endif 4393 } 4394 4395 if (m->rrcache_free) // If there are records in the free list, take one 4396 { 4397 e = m->rrcache_free; 4398 m->rrcache_free = e->next; 4399 if (++m->rrcache_totalused >= m->rrcache_report) 4400 { 4401 debugf("RR Cache now using %ld objects", m->rrcache_totalused); 4402 if (m->rrcache_report < 100) m->rrcache_report += 10; 4403 else m->rrcache_report += 100; 4404 } 4405 mDNSPlatformMemZero(e, sizeof(*e)); 4406 } 4407 4408 m->lock_rrcache = 0; 4409 4410 return(e); 4411 } 4412 4413 mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) 4414 { 4415 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); 4416 if (r) 4417 { 4418 r->resrec.rdata = (RData*)&r->rdatastorage; // By default, assume we're usually going to be using local storage 4419 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage 4420 { 4421 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); 4422 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; 4423 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } 4424 } 4425 } 4426 return(r); 4427 } 4428 4429 mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 4430 { 4431 mDNSu16 namelen = DomainNameLength(rr->name); 4432 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); 4433 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 4434 cg->next = m->rrcache_hash[slot]; 4435 cg->namehash = rr->namehash; 4436 cg->members = mDNSNULL; 4437 cg->rrcache_tail = &cg->members; 4438 cg->name = (domainname*)cg->namestorage; 4439 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", 4440 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); 4441 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); 4442 if (!cg->name) 4443 { 4444 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); 4445 ReleaseCacheEntity(m, (CacheEntity*)cg); 4446 return(mDNSNULL); 4447 } 4448 AssignDomainName(cg->name, rr->name); 4449 4450 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); 4451 m->rrcache_hash[slot] = cg; 4452 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); 4453 4454 return(cg); 4455 } 4456 4457 mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) 4458 { 4459 // Make sure we mark this record as thoroughly expired -- we don't ever want to give 4460 // a positive answer using an expired record (e.g. from an interface that has gone away). 4461 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to 4462 // summary deletion without giving the proper callback to any questions that are monitoring it. 4463 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. 4464 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; 4465 rr->UnansweredQueries = MaxUnansweredQueries; 4466 rr->resrec.rroriginalttl = 0; 4467 SetNextCacheCheckTime(m, rr); 4468 } 4469 4470 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) 4471 { 4472 mDNSs32 time; 4473 mDNSPlatformLock(m); 4474 if (m->mDNS_busy) 4475 { 4476 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); 4477 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); 4478 } 4479 4480 if (m->timenow) time = m->timenow; 4481 else time = mDNS_TimeNow_NoLock(m); 4482 mDNSPlatformUnlock(m); 4483 return(time); 4484 } 4485 4486 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) 4487 { 4488 mDNS_Lock(m); // Must grab lock before trying to read m->timenow 4489 4490 if (m->timenow - m->NextScheduledEvent >= 0) 4491 { 4492 int i; 4493 4494 verbosedebugf("mDNS_Execute"); 4495 if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set"); 4496 4497 // 1. If we're past the probe suppression time, we can clear it 4498 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; 4499 4500 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter 4501 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; 4502 4503 // 3. Purge our cache of stale old records 4504 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) 4505 { 4506 mDNSu32 slot; 4507 m->NextCacheCheck = m->timenow + 0x3FFFFFFF; 4508 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4509 { 4510 CacheGroup **cp = &m->rrcache_hash[slot]; 4511 while (*cp) 4512 { 4513 CheckCacheExpiration(m, *cp); 4514 if ((*cp)->members) cp=&(*cp)->next; 4515 else ReleaseCacheGroup(m, cp); 4516 } 4517 } 4518 LogOperation("Cache checked. Next in %ld ticks", m->NextCacheCheck - m->timenow); 4519 } 4520 4521 // 4. See if we can answer any of our new local questions from the cache 4522 for (i=0; m->NewQuestions && i<1000; i++) 4523 { 4524 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; 4525 AnswerNewQuestion(m); 4526 } 4527 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); 4528 4529 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); 4530 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); 4531 4532 for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++) 4533 { 4534 AuthRecord *rr = m->NewLocalRecords; 4535 m->NewLocalRecords = m->NewLocalRecords->next; 4536 AnswerLocalQuestions(m, rr, mDNStrue); 4537 } 4538 if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit"); 4539 4540 // 5. See what packets we need to send 4541 if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m); 4542 else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0) 4543 { 4544 // If the platform code is ready, and we're not suppressing packet generation right now 4545 // then send our responses, probes, and questions. 4546 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. 4547 // We send queries next, because there might be final-stage probes that complete their probing here, causing 4548 // them to advance to announcing state, and we want those to be included in any announcements we send out. 4549 // Finally, we send responses, including the previously mentioned records that just completed probing. 4550 m->SuppressSending = 0; 4551 4552 // 6. Send Query packets. This may cause some probing records to advance to announcing state 4553 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); 4554 if (m->timenow - m->NextScheduledQuery >= 0) 4555 { 4556 LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second"); 4557 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; 4558 } 4559 if (m->timenow - m->NextScheduledProbe >= 0) 4560 { 4561 LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second"); 4562 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; 4563 } 4564 4565 // 7. Send Response packets, including probing records just advanced to announcing state 4566 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); 4567 if (m->timenow - m->NextScheduledResponse >= 0) 4568 { 4569 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); 4570 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; 4571 } 4572 } 4573 4574 // Clear RandomDelay values, ready to pick a new different value next time 4575 m->RandomQueryDelay = 0; 4576 m->RandomReconfirmDelay = 0; 4577 } 4578 4579 // Note about multi-threaded systems: 4580 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), 4581 // performing mDNS API operations that change our next scheduled event time. 4582 // 4583 // On multi-threaded systems (like the current Windows implementation) that have a single main thread 4584 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility 4585 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will 4586 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one 4587 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful 4588 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it 4589 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately 4590 // without blocking. This avoids the race condition between the signal from the other thread arriving 4591 // just *before* or just *after* the main thread enters the blocking primitive. 4592 // 4593 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, 4594 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to 4595 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer 4596 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale 4597 // by the time it gets to the timer callback function). 4598 4599 #ifndef UNICAST_DISABLED 4600 uDNS_Execute(m); 4601 #endif 4602 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value 4603 return(m->NextScheduledEvent); 4604 } 4605 4606 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. 4607 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. 4608 // Normally, the platform support layer below mDNSCore should call this, not the client layer above. 4609 // Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call 4610 // mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just 4611 // found itself in a new network environment. For example, if the Ethernet hardware indicates that the 4612 // cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse) 4613 // to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc. 4614 // While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network 4615 // traffic, so it should only be called when there is legitimate reason to believe the machine 4616 // may have become attached to a new network. 4617 mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) 4618 { 4619 AuthRecord *rr; 4620 4621 mDNS_Lock(m); 4622 4623 m->SleepState = sleepstate; 4624 LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow); 4625 4626 if (sleepstate) 4627 { 4628 #ifndef UNICAST_DISABLED 4629 uDNS_Sleep(m); 4630 #endif 4631 // Mark all the records we need to deregister and send them 4632 for (rr = m->ResourceRecords; rr; rr=rr->next) 4633 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 4634 rr->ImmedAnswer = mDNSInterfaceMark; 4635 SendResponses(m); 4636 } 4637 else 4638 { 4639 DNSQuestion *q; 4640 mDNSu32 slot; 4641 CacheGroup *cg; 4642 CacheRecord *cr; 4643 4644 #ifndef UNICAST_DISABLED 4645 uDNS_Wake(m); 4646 #endif 4647 // 1. Retrigger all our questions 4648 for (q = m->Questions; q; q=q->next) // Scan our list of questions 4649 if (ActiveQuestion(q)) 4650 { 4651 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 4652 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 4653 q->LastQTime = m->timenow - q->ThisQInterval; 4654 q->RecentAnswerPkts = 0; 4655 ExpireDupSuppressInfo(q->DupSuppress, m->timenow); 4656 m->NextScheduledQuery = m->timenow; 4657 } 4658 4659 // 2. Re-validate our cache records 4660 m->NextCacheCheck = m->timenow; 4661 FORALL_CACHERECORDS(slot, cg, cr) 4662 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); 4663 4664 // 3. Retrigger probing and announcing for all our authoritative records 4665 for (rr = m->ResourceRecords; rr; rr=rr->next) 4666 { 4667 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 4668 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 4669 rr->AnnounceCount = InitialAnnounceCount; 4670 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); 4671 InitializeLastAPTime(m, rr); 4672 } 4673 } 4674 4675 mDNS_Unlock(m); 4676 } 4677 4678 // *************************************************************************** 4679 #if COMPILER_LIKES_PRAGMA_MARK 4680 #pragma mark - 4681 #pragma mark - Packet Reception Functions 4682 #endif 4683 4684 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) 4685 4686 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, 4687 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) 4688 { 4689 mDNSu8 *responseptr = response->data; 4690 const mDNSu8 *const limit = response->data + sizeof(response->data); 4691 const mDNSu8 *ptr = query->data; 4692 AuthRecord *rr; 4693 mDNSu32 maxttl = 0x70000000; 4694 int i; 4695 4696 // Initialize the response fields so we can answer the questions 4697 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); 4698 4699 // *** 4700 // *** 1. Write out the list of questions we are actually going to answer with this packet 4701 // *** 4702 if (LegacyQuery) 4703 { 4704 maxttl = 10; 4705 for (i=0; i<query->h.numQuestions; i++) // For each question... 4706 { 4707 DNSQuestion q; 4708 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... 4709 if (!ptr) return(mDNSNULL); 4710 4711 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers 4712 { 4713 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question 4714 { // then put the question in the question section 4715 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); 4716 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } 4717 break; // break out of the ResponseRecords loop, and go on to the next question 4718 } 4719 } 4720 } 4721 4722 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } 4723 } 4724 4725 // *** 4726 // *** 2. Write Answers 4727 // *** 4728 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 4729 if (rr->NR_AnswerTo) 4730 { 4731 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl); 4732 if (p) responseptr = p; 4733 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } 4734 } 4735 4736 // *** 4737 // *** 3. Write Additionals 4738 // *** 4739 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 4740 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) 4741 { 4742 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl); 4743 if (p) responseptr = p; 4744 else debugf("GenerateUnicastResponse: No more space for additionals"); 4745 } 4746 4747 return(responseptr); 4748 } 4749 4750 // AuthRecord *our is our Resource Record 4751 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network 4752 // Returns 0 if there is no conflict 4753 // Returns +1 if there was a conflict and we won 4754 // Returns -1 if there was a conflict and we lost and have to rename 4755 mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt) 4756 { 4757 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; 4758 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; 4759 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } 4760 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } 4761 4762 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); 4763 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); 4764 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } 4765 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict 4766 4767 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost 4768 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won 4769 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost 4770 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won 4771 4772 LogMsg("CompareRData ERROR: Invalid state"); 4773 return(-1); 4774 } 4775 4776 // See if we have an authoritative record that's identical to this packet record, 4777 // whose canonical DependentOn record is the specified master record. 4778 // The DependentOn pointer is typically used for the TXT record of service registrations 4779 // It indicates that there is no inherent conflict detection for the TXT record 4780 // -- it depends on the SRV record to resolve name conflicts 4781 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn 4782 // pointer chain (if any) to make sure we reach the canonical DependentOn record 4783 // If the record has no DependentOn, then just return that record's pointer 4784 // Returns NULL if we don't have any local RRs that are identical to the one from the packet 4785 mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master) 4786 { 4787 const AuthRecord *r1; 4788 for (r1 = m->ResourceRecords; r1; r1=r1->next) 4789 { 4790 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 4791 { 4792 const AuthRecord *r2 = r1; 4793 while (r2->DependentOn) r2 = r2->DependentOn; 4794 if (r2 == master) return(mDNStrue); 4795 } 4796 } 4797 for (r1 = m->DuplicateRecords; r1; r1=r1->next) 4798 { 4799 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 4800 { 4801 const AuthRecord *r2 = r1; 4802 while (r2->DependentOn) r2 = r2->DependentOn; 4803 if (r2 == master) return(mDNStrue); 4804 } 4805 } 4806 return(mDNSfalse); 4807 } 4808 4809 // Find the canonical RRSet pointer for this RR received in a packet. 4810 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet 4811 // pointers (if any) to make sure we return the canonical member of this name/type/class 4812 // Returns NULL if we don't have any local RRs that are identical to the one from the packet 4813 mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr) 4814 { 4815 const AuthRecord *rr; 4816 for (rr = m->ResourceRecords; rr; rr=rr->next) 4817 { 4818 if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec)) 4819 { 4820 while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet; 4821 return(rr); 4822 } 4823 } 4824 return(mDNSNULL); 4825 } 4826 4827 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name 4828 // as one of our records (our) but different rdata. 4829 // 1. If our record is not a type that's supposed to be unique, we don't care. 4830 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one. 4831 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer 4832 // points to our record, ignore this conflict (e.g. the packet record matches one of our 4833 // TXT records, and that record is marked as dependent on 'our', its SRV record). 4834 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record 4835 // are members of the same RRSet, then this is not a conflict. 4836 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr) 4837 { 4838 const AuthRecord *ourset = our->RRSet ? our->RRSet : our; 4839 4840 // If not supposed to be unique, not a conflict 4841 if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse); 4842 4843 // If a dependent record, not a conflict 4844 if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse); 4845 4846 // If the pktrr matches a member of ourset, not a conflict 4847 if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse); 4848 4849 // Okay, this is a conflict 4850 return(mDNStrue); 4851 } 4852 4853 // NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change 4854 // the record list and/or question list. 4855 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4856 mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 4857 DNSQuestion *q, AuthRecord *our) 4858 { 4859 int i; 4860 const mDNSu8 *ptr = LocateAuthorities(query, end); 4861 mDNSBool FoundUpdate = mDNSfalse; 4862 4863 for (i = 0; i < query->h.numAuthorities; i++) 4864 { 4865 ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 4866 if (!ptr) break; 4867 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 4868 { 4869 FoundUpdate = mDNStrue; 4870 if (PacketRRConflict(m, our, &m->rec.r)) 4871 { 4872 int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass; 4873 if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; 4874 if (!result) result = CompareRData(our, &m->rec.r); 4875 if (result > 0) 4876 debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); 4877 else if (result < 0) 4878 { 4879 debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); 4880 mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict); 4881 goto exit; 4882 } 4883 } 4884 } 4885 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 4886 } 4887 if (!FoundUpdate) 4888 debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); 4889 exit: 4890 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 4891 } 4892 4893 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr) 4894 { 4895 mDNSu32 slot = HashSlot(pktrr->name); 4896 CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); 4897 CacheRecord *rr; 4898 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 4899 if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break; 4900 return(rr); 4901 } 4902 4903 // ProcessQuery examines a received query to see if we have any answers to give 4904 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 4905 const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, 4906 mDNSBool QueryWasLocalUnicast, DNSMessage *const response) 4907 { 4908 mDNSBool FromLocalSubnet = AddressIsLocalSubnet(m, InterfaceID, srcaddr); 4909 AuthRecord *ResponseRecords = mDNSNULL; 4910 AuthRecord **nrp = &ResponseRecords; 4911 CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated 4912 CacheRecord **eap = &ExpectedAnswers; 4913 DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet 4914 DNSQuestion **dqp = &DupQuestions; 4915 mDNSs32 delayresponse = 0; 4916 mDNSBool SendLegacyResponse = mDNSfalse; 4917 const mDNSu8 *ptr = query->data; 4918 mDNSu8 *responseptr = mDNSNULL; 4919 AuthRecord *rr; 4920 int i; 4921 4922 // *** 4923 // *** 1. Parse Question Section and mark potential answers 4924 // *** 4925 for (i=0; i<query->h.numQuestions; i++) // For each question... 4926 { 4927 mDNSBool QuestionNeedsMulticastResponse; 4928 int NumAnswersForThisQuestion = 0; 4929 DNSQuestion pktq, *q; 4930 ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question... 4931 if (!ptr) goto exit; 4932 4933 // The only queries that *need* a multicast response are: 4934 // * Queries sent via multicast 4935 // * from port 5353 4936 // * that don't have the kDNSQClass_UnicastResponse bit set 4937 // These queries need multicast responses because other clients will: 4938 // * suppress their own identical questions when they see these questions, and 4939 // * expire their cache records if they don't see the expected responses 4940 // For other queries, we may still choose to send the occasional multicast response anyway, 4941 // to keep our neighbours caches warm, and for ongoing conflict detection. 4942 QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse); 4943 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later 4944 pktq.qclass &= ~kDNSQClass_UnicastResponse; 4945 4946 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe 4947 // can result in user callbacks which may change the record list and/or question list. 4948 // Also note: we just mark potential answer records here, without trying to build the 4949 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records 4950 // from that list while we're in the middle of trying to build it. 4951 if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set"); 4952 m->CurrentRecord = m->ResourceRecords; 4953 while (m->CurrentRecord) 4954 { 4955 rr = m->CurrentRecord; 4956 m->CurrentRecord = rr->next; 4957 if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery)) 4958 { 4959 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 4960 ResolveSimultaneousProbe(m, query, end, &pktq, rr); 4961 else if (ResourceRecordIsValidAnswer(rr)) 4962 { 4963 NumAnswersForThisQuestion++; 4964 // Notes: 4965 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast) 4966 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead) 4967 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later) 4968 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set, 4969 // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link) 4970 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source) 4971 if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery)) 4972 { 4973 // We only mark this question for sending if it is at least one second since the last time we multicast it 4974 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. 4975 // This is to guard against the case where someone blasts us with queries as fast as they can. 4976 if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || 4977 (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) 4978 rr->NR_AnswerTo = (mDNSu8*)~0; 4979 } 4980 else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1; 4981 } 4982 } 4983 } 4984 4985 // If we couldn't answer this question, someone else might be able to, 4986 // so use random delay on response to reduce collisions 4987 if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 4988 4989 // We only do the following accelerated cache expiration processing and duplicate question suppression processing 4990 // for multicast queries with multicast responses. 4991 // For any query generating a unicast response we don't do this because we can't assume we will see the response 4992 if (QuestionNeedsMulticastResponse) 4993 { 4994 const mDNSu32 slot = HashSlot(&pktq.qname); 4995 CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); 4996 CacheRecord *rr; 4997 4998 // Make a list indicating which of our own cache records we expect to see updated as a result of this query 4999 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated 5000 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 5001 if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit) 5002 if (!rr->NextInKAList && eap != &rr->NextInKAList) 5003 { 5004 *eap = rr; 5005 eap = &rr->NextInKAList; 5006 if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond) 5007 { 5008 // Although MPUnansweredQ is only really used for multi-packet query processing, 5009 // we increment it for both single-packet and multi-packet queries, so that it stays in sync 5010 // with the MPUnansweredKA value, which by necessity is incremented for both query types. 5011 rr->MPUnansweredQ++; 5012 rr->MPLastUnansweredQT = m->timenow; 5013 rr->MPExpectingKA = mDNStrue; 5014 } 5015 } 5016 5017 // Check if this question is the same as any of mine. 5018 // We only do this for non-truncated queries. Right now it would be too complicated to try 5019 // to keep track of duplicate suppression state between multiple packets, especially when we 5020 // can't guarantee to receive all of the Known Answer packets that go with a particular query. 5021 if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 5022 for (q = m->Questions; q; q=q->next) 5023 if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4) 5024 if (!q->InterfaceID || q->InterfaceID == InterfaceID) 5025 if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList) 5026 if (q->qtype == pktq.qtype && 5027 q->qclass == pktq.qclass && 5028 q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname)) 5029 { *dqp = q; dqp = &q->NextInDQList; } 5030 } 5031 } 5032 5033 // *** 5034 // *** 2. Now we can safely build the list of marked answers 5035 // *** 5036 for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers 5037 if (rr->NR_AnswerTo) // If we marked the record... 5038 AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list 5039 5040 // *** 5041 // *** 3. Add additional records 5042 // *** 5043 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 5044 5045 // *** 5046 // *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list 5047 // *** 5048 for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section... 5049 { 5050 // Get the record... 5051 AuthRecord *rr; 5052 CacheRecord *ourcacherr; 5053 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec); 5054 if (!ptr) goto exit; 5055 5056 // See if this Known-Answer suppresses any of our currently planned answers 5057 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5058 if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 5059 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 5060 5061 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression) 5062 for (rr=m->ResourceRecords; rr; rr=rr->next) 5063 { 5064 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression 5065 if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 5066 { 5067 if (srcaddr->type == mDNSAddrType_IPv4) 5068 { 5069 if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr; 5070 } 5071 else if (srcaddr->type == mDNSAddrType_IPv6) 5072 { 5073 if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr; 5074 } 5075 if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester)) 5076 { 5077 rr->ImmedAnswer = mDNSNULL; 5078 rr->ImmedUnicast = mDNSfalse; 5079 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5080 LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr)); 5081 #endif 5082 } 5083 } 5084 } 5085 5086 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always, 5087 // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list). 5088 ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); 5089 if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond) 5090 { 5091 ourcacherr->MPUnansweredKA++; 5092 ourcacherr->MPExpectingKA = mDNSfalse; 5093 } 5094 5095 // Having built our ExpectedAnswers list from the questions in this packet, we can definitively 5096 // remove from our ExpectedAnswers list any records that are suppressed in the very same packet. 5097 // For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them. 5098 eap = &ExpectedAnswers; 5099 while (*eap) 5100 { 5101 CacheRecord *rr = *eap; 5102 if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec)) 5103 { *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; } 5104 else eap = &rr->NextInKAList; 5105 } 5106 5107 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query. 5108 if (!ourcacherr) 5109 { 5110 dqp = &DupQuestions; 5111 while (*dqp) 5112 { 5113 DNSQuestion *q = *dqp; 5114 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 5115 { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; } 5116 else dqp = &q->NextInDQList; 5117 } 5118 } 5119 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5120 } 5121 5122 // *** 5123 // *** 5. Cancel any additionals that were added because of now-deleted records 5124 // *** 5125 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5126 if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo)) 5127 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 5128 5129 // *** 5130 // *** 6. Mark the send flags on the records we plan to send 5131 // *** 5132 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5133 { 5134 if (rr->NR_AnswerTo) 5135 { 5136 mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response 5137 mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response) 5138 5139 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc. 5140 if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) 5141 { 5142 SendMulticastResponse = mDNStrue; 5143 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to 5144 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below). 5145 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value. 5146 if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0; 5147 } 5148 5149 // If the client insists on a multicast response, then we'd better send one 5150 if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue; 5151 else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue; 5152 else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue; 5153 5154 if (SendMulticastResponse || SendUnicastResponse) 5155 { 5156 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5157 rr->ImmedAnswerMarkTime = m->timenow; 5158 #endif 5159 m->NextScheduledResponse = m->timenow; 5160 // If we're already planning to send this on another interface, just send it on all interfaces 5161 if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID) 5162 rr->ImmedAnswer = mDNSInterfaceMark; 5163 else 5164 { 5165 rr->ImmedAnswer = InterfaceID; // Record interface to send it on 5166 if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue; 5167 if (srcaddr->type == mDNSAddrType_IPv4) 5168 { 5169 if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4; 5170 else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr; 5171 } 5172 else if (srcaddr->type == mDNSAddrType_IPv6) 5173 { 5174 if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6; 5175 else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr; 5176 } 5177 } 5178 } 5179 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet, 5180 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11) 5181 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses 5182 // else, for a simple unique record reply, we can reply immediately; no need for delay 5183 if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms 5184 else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 5185 } 5186 else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0) 5187 { 5188 // Since additional records are an optimization anyway, we only ever send them on one interface at a time 5189 // If two clients on different interfaces do queries that invoke the same optional additional answer, 5190 // then the earlier client is out of luck 5191 rr->ImmedAdditional = InterfaceID; 5192 // No need to set m->NextScheduledResponse here 5193 // We'll send these additional records when we send them, or not, as the case may be 5194 } 5195 } 5196 5197 // *** 5198 // *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer 5199 // *** 5200 if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50)) 5201 { 5202 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5203 mDNSs32 oldss = m->SuppressSending; 5204 if (oldss && delayresponse) 5205 LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50); 5206 #endif 5207 // Pick a random delay: 5208 // We start with the base delay chosen above (typically either 1 second or 20 seconds), 5209 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds). 5210 // This is an integer value, with resolution determined by the platform clock rate. 5211 // We then divide that by 50 to get the delay value in ticks. We defer the division until last 5212 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second). 5213 // The +49 before dividing is to ensure we round up, not down, to ensure that even 5214 // on platforms where the native clock rate is less than fifty ticks per second, 5215 // we still guarantee that the final calculated delay is at least one platform tick. 5216 // We want to make sure we don't ever allow the delay to be zero ticks, 5217 // because if that happens we'll fail the Bonjour Conformance Test. 5218 // Our final computed delay is 20-120ms for normal delayed replies, 5219 // or 400-500ms in the case of multi-packet known-answer lists. 5220 m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50; 5221 if (m->SuppressSending == 0) m->SuppressSending = 1; 5222 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5223 if (oldss && delayresponse) 5224 LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow); 5225 #endif 5226 } 5227 5228 // *** 5229 // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too 5230 // *** 5231 if (SendLegacyResponse) 5232 responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords); 5233 5234 exit: 5235 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5236 5237 // *** 5238 // *** 9. Finally, clear our link chains ready for use next time 5239 // *** 5240 while (ResponseRecords) 5241 { 5242 rr = ResponseRecords; 5243 ResponseRecords = rr->NextResponse; 5244 rr->NextResponse = mDNSNULL; 5245 rr->NR_AnswerTo = mDNSNULL; 5246 rr->NR_AdditionalTo = mDNSNULL; 5247 } 5248 5249 while (ExpectedAnswers) 5250 { 5251 CacheRecord *rr; 5252 rr = ExpectedAnswers; 5253 ExpectedAnswers = rr->NextInKAList; 5254 rr->NextInKAList = mDNSNULL; 5255 5256 // For non-truncated queries, we can definitively say that we should expect 5257 // to be seeing a response for any records still left in the ExpectedAnswers list 5258 if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 5259 if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond) 5260 { 5261 rr->UnansweredQueries++; 5262 rr->LastUnansweredTime = m->timenow; 5263 if (rr->UnansweredQueries > 1) 5264 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", 5265 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); 5266 SetNextCacheCheckTime(m, rr); 5267 } 5268 5269 // If we've seen multiple unanswered queries for this record, 5270 // then mark it to expire in five seconds if we don't get a response by then. 5271 if (rr->UnansweredQueries >= MaxUnansweredQueries) 5272 { 5273 // Only show debugging message if this record was not about to expire anyway 5274 if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond) 5275 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 5276 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); 5277 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); 5278 } 5279 // Make a guess, based on the multi-packet query / known answer counts, whether we think we 5280 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for 5281 // possible packet loss of up to 20% of the additional KA packets.) 5282 else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8) 5283 { 5284 // We want to do this conservatively. 5285 // If there are so many machines on the network that they have to use multi-packet known-answer lists, 5286 // then we don't want them to all hit the network simultaneously with their final expiration queries. 5287 // By setting the record to expire in four minutes, we achieve two things: 5288 // (a) the 90-95% final expiration queries will be less bunched together 5289 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own 5290 mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4; 5291 if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond) 5292 remain = 240 * (mDNSu32)mDNSPlatformOneSecond; 5293 5294 // Only show debugging message if this record was not about to expire anyway 5295 if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond) 5296 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 5297 rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr)); 5298 5299 if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond) 5300 rr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query 5301 rr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics 5302 rr->MPUnansweredKA = 0; 5303 rr->MPExpectingKA = mDNSfalse; 5304 5305 if (remain < kDefaultReconfirmTimeForNoAnswer) 5306 remain = kDefaultReconfirmTimeForNoAnswer; 5307 mDNS_Reconfirm_internal(m, rr, remain); 5308 } 5309 } 5310 5311 while (DupQuestions) 5312 { 5313 int i; 5314 DNSQuestion *q = DupQuestions; 5315 DupQuestions = q->NextInDQList; 5316 q->NextInDQList = mDNSNULL; 5317 i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type); 5318 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID, 5319 srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i); 5320 } 5321 5322 return(responseptr); 5323 } 5324 5325 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, 5326 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 5327 const mDNSInterfaceID InterfaceID) 5328 { 5329 mDNSu8 *responseend = mDNSNULL; 5330 mDNSBool QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr); 5331 5332 if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr)) 5333 { 5334 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 5335 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)", 5336 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 5337 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 5338 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 5339 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 5340 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); 5341 return; 5342 } 5343 5344 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 5345 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", 5346 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 5347 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 5348 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 5349 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 5350 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); 5351 5352 responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID, 5353 (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg); 5354 5355 if (responseend) // If responseend is non-null, that means we built a unicast response packet 5356 { 5357 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld", 5358 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 5359 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 5360 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", 5361 srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type); 5362 mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL); 5363 } 5364 } 5365 5366 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change 5367 // the record list and/or question list. 5368 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 5369 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, 5370 const DNSMessage *const response, const mDNSu8 *end, 5371 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 5372 const mDNSInterfaceID InterfaceID) 5373 { 5374 int i; 5375 5376 // We ignore questions (if any) in a DNS response packet 5377 const mDNSu8 *ptr = LocateAnswers(response, end); 5378 5379 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker 5380 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList 5381 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling. 5382 CacheRecord *CacheFlushRecords = (CacheRecord*)1; 5383 CacheRecord **cfp = &CacheFlushRecords; 5384 5385 // All records in a DNS response packet are treated as equally valid statements of truth. If we want 5386 // to guard against spoof responses, then the only credible protection against that is cryptographic 5387 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record 5388 int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals; 5389 5390 (void)srcaddr; // Currently used only for display in debugging message 5391 (void)srcport; 5392 (void)dstport; 5393 5394 verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with " 5395 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", 5396 srcaddr, dstaddr, InterfaceID, 5397 response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,", 5398 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", 5399 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", 5400 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s"); 5401 5402 // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us 5403 if (!mDNSAddrIsDNSMulticast(dstaddr)) 5404 { 5405 if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2)) 5406 return; 5407 // For now we don't put standard wide-area unicast responses in our main cache 5408 // (Later we should fix this and cache all known results in a unified manner.) 5409 if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger) 5410 return; 5411 } 5412 5413 for (i = 0; i < totalrecords && ptr && ptr < end; i++) 5414 { 5415 const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd); 5416 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec); 5417 if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting 5418 5419 // 1. Check that this packet resource record does not conflict with any of ours 5420 if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set"); 5421 m->CurrentRecord = m->ResourceRecords; 5422 while (m->CurrentRecord) 5423 { 5424 AuthRecord *rr = m->CurrentRecord; 5425 m->CurrentRecord = rr->next; 5426 if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match... 5427 { 5428 // ... check to see if type and rdata are identical 5429 if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec)) 5430 { 5431 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us 5432 if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState) 5433 { 5434 // If we were planning to send on this -- and only this -- interface, then we don't need to any more 5435 if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; } 5436 } 5437 else 5438 { 5439 if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; } 5440 else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 5441 } 5442 } 5443 // else, the packet RR has different type or different rdata -- check to see if this is a conflict 5444 else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r)) 5445 { 5446 debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); 5447 debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 5448 5449 // If this record is marked DependentOn another record for conflict detection purposes, 5450 // then *that* record has to be bumped back to probing state to resolve the conflict 5451 while (rr->DependentOn) rr = rr->DependentOn; 5452 5453 // If we've just whacked this record's ProbeCount, don't need to do it again 5454 if (rr->ProbeCount <= DefaultProbeCountForTypeUnique) 5455 { 5456 // If we'd previously verified this record, put it back to probing state and try again 5457 if (rr->resrec.RecordType == kDNSRecordTypeVerified) 5458 { 5459 debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 5460 rr->resrec.RecordType = kDNSRecordTypeUnique; 5461 rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; 5462 rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique); 5463 InitializeLastAPTime(m, rr); 5464 RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate 5465 } 5466 // If we're probing for this record, we just failed 5467 else if (rr->resrec.RecordType == kDNSRecordTypeUnique) 5468 { 5469 debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 5470 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 5471 } 5472 // We assumed this record must be unique, but we were wrong. 5473 // (e.g. There are two mDNSResponders on the same machine giving 5474 // different answers for the reverse mapping record.) 5475 // This is simply a misconfiguration, and we don't try to recover from it. 5476 else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) 5477 { 5478 debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record", 5479 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 5480 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 5481 } 5482 else 5483 debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)", 5484 rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 5485 } 5486 } 5487 // Else, matching signature, different type or rdata, but not a considered a conflict. 5488 // If the packet record has the cache-flush bit set, then we check to see if we 5489 // have any record(s) of the same type that we should re-assert to rescue them 5490 // (see note about "multi-homing and bridged networks" at the end of this function). 5491 else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype) 5492 if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2) 5493 { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 5494 } 5495 } 5496 5497 // 2. See if we want to add this packet resource record to our cache 5498 if (m->rrcache_size) // Only try to cache answers if we have a cache to put them in 5499 { 5500 const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); 5501 CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); 5502 CacheRecord *rr; 5503 // 2a. Check if this packet resource record is already in our cache 5504 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 5505 { 5506 // If we found this exact resource record, refresh its TTL 5507 if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec)) 5508 { 5509 if (m->rec.r.resrec.rdlength > InlineCacheRDSize) 5510 verbosedebugf("Found record size %5d interface %p already in cache: %s", 5511 m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r)); 5512 rr->TimeRcvd = m->timenow; 5513 5514 if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) 5515 { 5516 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list 5517 if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList) 5518 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 5519 5520 // If this packet record is marked unique, and our previous cached copy was not, then fix it 5521 if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) 5522 { 5523 DNSQuestion *q; 5524 for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++; 5525 rr->resrec.RecordType = m->rec.r.resrec.RecordType; 5526 } 5527 } 5528 5529 if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength)) 5530 { 5531 // If the rdata of the packet record differs in name capitalization from the record in our cache 5532 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get 5533 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one. 5534 rr->resrec.rroriginalttl = 0; 5535 rr->UnansweredQueries = MaxUnansweredQueries; 5536 SetNextCacheCheckTime(m, rr); 5537 // DO NOT break out here -- we want to continue as if we never found it 5538 } 5539 else if (m->rec.r.resrec.rroriginalttl > 0) 5540 { 5541 rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl; 5542 rr->UnansweredQueries = 0; 5543 rr->MPUnansweredQ = 0; 5544 rr->MPUnansweredKA = 0; 5545 rr->MPExpectingKA = mDNSfalse; 5546 SetNextCacheCheckTime(m, rr); 5547 break; 5548 } 5549 else 5550 { 5551 // If the packet TTL is zero, that means we're deleting this record. 5552 // To give other hosts on the network a chance to protest, we push the deletion 5553 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries. 5554 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent 5555 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth. 5556 rr->resrec.rroriginalttl = 1; 5557 rr->UnansweredQueries = MaxUnansweredQueries; 5558 SetNextCacheCheckTime(m, rr); 5559 break; 5560 } 5561 } 5562 } 5563 5564 // If packet resource record not in our cache, add it now 5565 // (unless it is just a deletion of a record we never had, in which case we don't care) 5566 if (!rr && m->rec.r.resrec.rroriginalttl > 0) 5567 { 5568 // If we don't have a CacheGroup for this name, make one now 5569 if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); 5570 if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength); // Make a cache record, being careful not to recycle cg 5571 if (!rr) NoCacheAnswer(m, &m->rec.r); 5572 else 5573 { 5574 RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer 5575 *rr = m->rec.r; // Block copy the CacheRecord object 5576 rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment 5577 rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header 5578 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) 5579 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 5580 // If this is an oversized record with external storage allocated, copy rdata to external storage 5581 if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize)) 5582 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c); 5583 if (m->rec.r.resrec.rdlength > InlineCacheRDSize) 5584 mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength); 5585 rr->next = mDNSNULL; // Clear 'next' pointer 5586 *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list 5587 cg->rrcache_tail = &(rr->next); // Advance tail pointer 5588 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) // If marked unique, assume we may have 5589 rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event 5590 else 5591 rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); 5592 CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us 5593 } 5594 } 5595 } 5596 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5597 } 5598 5599 exit: 5600 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5601 5602 // If we've just received one or more records with their cache flush bits set, 5603 // then scan that cache slot to see if there are any old stale records we need to flush 5604 while (CacheFlushRecords != (CacheRecord*)1) 5605 { 5606 CacheRecord *r1 = CacheFlushRecords, *r2; 5607 const mDNSu32 slot = HashSlot(r1->resrec.name); 5608 CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); 5609 CacheFlushRecords = CacheFlushRecords->NextInCFList; 5610 r1->NextInCFList = mDNSNULL; 5611 for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) 5612 if (SameResourceRecordSignature(&r1->resrec, &r2->resrec)) 5613 { 5614 // If record was recently positively received 5615 // (i.e. not counting goodbye packets or cache flush events that set the TTL to 1) 5616 // then we need to ensure the whole RRSet has the same TTL (as required by DNS semantics) 5617 if (r2->resrec.rroriginalttl > 1 && m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond) 5618 { 5619 if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl) 5620 LogMsg("Correcting TTL from %4d to %4d for %s", 5621 r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); 5622 r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; 5623 r2->TimeRcvd = m->timenow; 5624 } 5625 else // else, if record is old, mark it to be flushed 5626 { 5627 verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2)); 5628 // We set stale records to expire in one second. 5629 // This gives the owner a chance to rescue it if necessary. 5630 // This is important in the case of multi-homing and bridged networks: 5631 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be 5632 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit 5633 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet 5634 // will promptly delete their cached copies of the (still valid) Ethernet IP address record. 5635 // By delaying the deletion by one second, we give X a change to notice that this bridging has 5636 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches. 5637 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary 5638 // final expiration queries for this record. 5639 r2->resrec.rroriginalttl = 1; 5640 r2->TimeRcvd = m->timenow; 5641 r2->UnansweredQueries = MaxUnansweredQueries; 5642 } 5643 SetNextCacheCheckTime(m, r2); 5644 } 5645 if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to 5646 { 5647 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared 5648 r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot); 5649 if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); 5650 } 5651 } 5652 } 5653 5654 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, 5655 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport, 5656 const mDNSInterfaceID InterfaceID) 5657 { 5658 DNSMessage *msg = (DNSMessage *)pkt; 5659 const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery; 5660 const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; 5661 mDNSu8 QR_OP; 5662 mDNSu8 *ptr = mDNSNULL; 5663 const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; 5664 5665 #ifndef UNICAST_DISABLED 5666 if (srcport.NotAnInteger == NATPMPPort.NotAnInteger) 5667 { 5668 mDNS_Lock(m); 5669 uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); 5670 mDNS_Unlock(m); 5671 return; 5672 } 5673 #endif 5674 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; } 5675 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); 5676 // Read the integer parts which are in IETF byte-order (MSB first, LSB second) 5677 ptr = (mDNSu8 *)&msg->h.numQuestions; 5678 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 5679 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 5680 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 5681 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); 5682 5683 if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; } 5684 5685 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address" 5686 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up 5687 if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; } 5688 5689 mDNS_Lock(m); 5690 m->PktNum++; 5691 #ifndef UNICAST_DISABLED 5692 if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR)) 5693 uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); 5694 // Note: mDNSCore also needs to get access to received unicast responses 5695 #endif 5696 if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); 5697 else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); 5698 else if (QR_OP != UpdateR) 5699 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)", 5700 msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID); 5701 5702 // Packet reception often causes a change to the task list: 5703 // 1. Inbound queries can cause us to need to send responses 5704 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses 5705 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records 5706 // 4. Response packets that answer questions may cause our client to issue new questions 5707 mDNS_Unlock(m); 5708 } 5709 5710 // *************************************************************************** 5711 #if COMPILER_LIKES_PRAGMA_MARK 5712 #pragma mark - 5713 #pragma mark - 5714 #pragma mark - Searcher Functions 5715 #endif 5716 5717 #define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger) 5718 5719 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question) 5720 { 5721 DNSQuestion *q; 5722 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list. 5723 // This prevents circular references, where two questions are each marked as a duplicate of the other. 5724 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching 5725 // further in the list. 5726 for (q = m->Questions; q && q != question; q=q->next) // Scan our list of questions 5727 if (q->InterfaceID == question->InterfaceID && // for another question with the same InterfaceID, 5728 SameQTarget(q, question) && // and same unicast/multicast target settings 5729 q->qtype == question->qtype && // type, 5730 q->qclass == question->qclass && // class, 5731 q->qnamehash == question->qnamehash && 5732 SameDomainName(&q->qname, &question->qname)) // and name 5733 return(q); 5734 return(mDNSNULL); 5735 } 5736 5737 // This is called after a question is deleted, in case other identical questions were being 5738 // suppressed as duplicates 5739 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question) 5740 { 5741 DNSQuestion *q; 5742 for (q = m->Questions; q; q=q->next) // Scan our list of questions 5743 if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate 5744 { 5745 q->ThisQInterval = question->ThisQInterval; 5746 q->RequestUnicast = question->RequestUnicast; 5747 q->LastQTime = question->LastQTime; 5748 q->RecentAnswerPkts = 0; 5749 q->DuplicateOf = FindDuplicateQuestion(m, q); 5750 q->LastQTxTime = question->LastQTxTime; 5751 SetNextQueryTime(m,q); 5752 } 5753 } 5754 5755 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \ 5756 ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger)) 5757 5758 mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question) 5759 { 5760 if (question->Target.type && !ValidQuestionTarget(question)) 5761 { 5762 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)", 5763 question->Target.type, mDNSVal16(question->TargetPort)); 5764 question->Target.type = mDNSAddrType_None; 5765 } 5766 5767 if (!question->Target.type) // No question->Target specified, so clear TargetPort and TargetQID 5768 { 5769 question->TargetPort = zeroIPPort; 5770 question->TargetQID = zeroID; 5771 } 5772 5773 #ifndef UNICAST_DISABLED 5774 // If the client has specified 'kDNSServiceFlagsForceMulticast' 5775 // then we do a multicast query on that interface, even for unicast domains. 5776 if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname)) 5777 question->uDNS_info.id = zeroID; 5778 else return uDNS_StartQuery(m, question); 5779 #else 5780 question->uDNS_info.id = zeroID; 5781 #endif // UNICAST_DISABLED 5782 5783 //LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 5784 5785 if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated 5786 return(mStatus_NoCache); 5787 else 5788 { 5789 int i; 5790 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start 5791 DNSQuestion **q = &m->Questions; 5792 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; 5793 while (*q && *q != question) q=&(*q)->next; 5794 5795 if (*q) 5796 { 5797 LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list", 5798 question->qname.c, DNSTypeName(question->qtype)); 5799 return(mStatus_AlreadyRegistered); 5800 } 5801 5802 // If this question is referencing a specific interface, verify it exists 5803 if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly) 5804 { 5805 NetworkInterfaceInfo *intf; 5806 for (intf = m->HostInterfaces; intf; intf = intf->next) 5807 if (intf->InterfaceID == question->InterfaceID) break; 5808 if (!intf) 5809 LogMsg("Note: InterfaceID %p for question %##s not currently found in active interface list", 5810 question->InterfaceID, question->qname.c); 5811 } 5812 5813 if (!ValidateDomainName(&question->qname)) 5814 { 5815 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 5816 return(mStatus_Invalid); 5817 } 5818 5819 // Note: In the case where we already have the answer to this question in our cache, that may be all the client 5820 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would 5821 // be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds 5822 // that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately. 5823 if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); 5824 5825 question->next = mDNSNULL; 5826 question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion() 5827 question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname)); 5828 question->ThisQInterval = InitialQuestionInterval * 2; // MUST be > zero for an active question 5829 question->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 5830 question->LastQTime = m->timenow - m->RandomQueryDelay; // Avoid inter-machine synchronization 5831 question->LastAnswerPktNum = m->PktNum; 5832 question->RecentAnswerPkts = 0; 5833 question->CurrentAnswers = 0; 5834 question->LargeAnswers = 0; 5835 question->UniqueAnswers = 0; 5836 question->FlappingInterface = mDNSNULL; 5837 question->DuplicateOf = FindDuplicateQuestion(m, question); 5838 question->NextInDQList = mDNSNULL; 5839 for (i=0; i<DupSuppressInfoSize; i++) 5840 question->DupSuppress[i].InterfaceID = mDNSNULL; 5841 // question->InterfaceID must be already set by caller 5842 question->SendQNow = mDNSNULL; 5843 question->SendOnAll = mDNSfalse; 5844 question->LastQTxTime = m->timenow; 5845 5846 if (!question->DuplicateOf) 5847 verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started", 5848 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, 5849 question->LastQTime + question->ThisQInterval - m->timenow, question); 5850 else 5851 verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)", 5852 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, 5853 question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf); 5854 5855 *q = question; 5856 if (question->InterfaceID == mDNSInterface_LocalOnly) 5857 { 5858 if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question; 5859 } 5860 else 5861 { 5862 if (!m->NewQuestions) m->NewQuestions = question; 5863 SetNextQueryTime(m,question); 5864 } 5865 5866 return(mStatus_NoError); 5867 } 5868 } 5869 5870 mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question) 5871 { 5872 const mDNSu32 slot = HashSlot(&question->qname); 5873 CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); 5874 CacheRecord *rr; 5875 DNSQuestion **q = &m->Questions; 5876 5877 if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question); 5878 5879 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; 5880 while (*q && *q != question) q=&(*q)->next; 5881 if (*q) *q = (*q)->next; 5882 else 5883 { 5884 if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active 5885 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list", 5886 question->qname.c, DNSTypeName(question->qtype)); 5887 return(mStatus_BadReferenceErr); 5888 } 5889 5890 // Take care to cut question from list *before* calling UpdateQuestionDuplicates 5891 UpdateQuestionDuplicates(m, question); 5892 // But don't trash ThisQInterval until afterwards. 5893 question->ThisQInterval = -1; 5894 5895 // If there are any cache records referencing this as their active question, then see if any other 5896 // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL. 5897 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 5898 { 5899 if (rr->CRActiveQuestion == question) 5900 { 5901 DNSQuestion *q; 5902 for (q = m->Questions; q; q=q->next) // Scan our list of questions 5903 if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 5904 break; 5905 verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", 5906 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q); 5907 rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null 5908 if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count 5909 } 5910 } 5911 5912 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at, 5913 // bump its pointer forward one question. 5914 if (m->CurrentQuestion == question) 5915 { 5916 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)", 5917 question->qname.c, DNSTypeName(question->qtype)); 5918 m->CurrentQuestion = question->next; 5919 } 5920 5921 if (m->NewQuestions == question) 5922 { 5923 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)", 5924 question->qname.c, DNSTypeName(question->qtype)); 5925 m->NewQuestions = question->next; 5926 } 5927 5928 if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next; 5929 5930 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions 5931 question->next = mDNSNULL; 5932 return(mStatus_NoError); 5933 } 5934 5935 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question) 5936 { 5937 mStatus status; 5938 mDNS_Lock(m); 5939 status = mDNS_StartQuery_internal(m, question); 5940 mDNS_Unlock(m); 5941 return(status); 5942 } 5943 5944 mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) 5945 { 5946 mStatus status; 5947 mDNS_Lock(m); 5948 status = mDNS_StopQuery_internal(m, question); 5949 mDNS_Unlock(m); 5950 return(status); 5951 } 5952 5953 mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr) 5954 { 5955 mStatus status; 5956 mDNS_Lock(m); 5957 status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); 5958 mDNS_Unlock(m); 5959 return(status); 5960 } 5961 5962 mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr) 5963 { 5964 mStatus status = mStatus_BadReferenceErr; 5965 CacheRecord *cr; 5966 mDNS_Lock(m); 5967 cr = FindIdenticalRecordInCache(m, rr); 5968 if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 5969 mDNS_Unlock(m); 5970 return(status); 5971 } 5972 5973 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, 5974 const domainname *const srv, const domainname *const domain, 5975 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) 5976 { 5977 question->InterfaceID = InterfaceID; 5978 question->Target = zeroAddr; 5979 question->qtype = kDNSType_PTR; 5980 question->qclass = kDNSClass_IN; 5981 question->LongLived = mDNSfalse; 5982 question->ExpectUnique = mDNSfalse; 5983 question->ForceMCast = ForceMCast; 5984 question->QuestionCallback = Callback; 5985 question->QuestionContext = Context; 5986 if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr); 5987 5988 #ifndef UNICAST_DISABLED 5989 if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname)) 5990 { 5991 question->LongLived = mDNSfalse; 5992 question->uDNS_info.id = zeroID; 5993 return(mDNS_StartQuery(m, question)); 5994 } 5995 else 5996 { 5997 mStatus status; 5998 // Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not 5999 mDNS_Lock(m); 6000 question->LongLived = mDNStrue; 6001 status = uDNS_StartQuery(m, question); 6002 mDNS_Unlock(m); 6003 return(status); 6004 } 6005 #else 6006 return(mDNS_StartQuery(m, question)); 6007 #endif // UNICAST_DISABLED 6008 } 6009 6010 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) 6011 { 6012 NetworkInterfaceInfo *intf; 6013 for (intf = m->HostInterfaces; intf; intf = intf->next) 6014 if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue); 6015 return(mDNSfalse); 6016 } 6017 6018 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) 6019 { 6020 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 6021 mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger); 6022 if (!AddRecord) return; 6023 if (answer->rrtype != kDNSType_SRV) return; 6024 6025 query->info->port = answer->rdata->u.srv.port; 6026 6027 // If this is our first answer, then set the GotSRV flag and start the address query 6028 if (!query->GotSRV) 6029 { 6030 query->GotSRV = mDNStrue; 6031 query->qAv4.InterfaceID = answer->InterfaceID; 6032 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 6033 query->qAv6.InterfaceID = answer->InterfaceID; 6034 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 6035 mDNS_StartQuery(m, &query->qAv4); 6036 // Only do the AAAA query if this machine actually has IPv6 active 6037 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 6038 } 6039 // If this is not our first answer, only re-issue the address query if the target host name has changed 6040 else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) || 6041 !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target)) 6042 { 6043 mDNS_StopQuery(m, &query->qAv4); 6044 if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6); 6045 if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged) 6046 { 6047 // If we get here, it means: 6048 // 1. This is not our first SRV answer 6049 // 2. The interface ID is different, but the target host and port are the same 6050 // This implies that we're seeing the exact same SRV record on more than one interface, so we should 6051 // make our address queries at least as broad as the original SRV query so that we catch all the answers. 6052 query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface 6053 query->qAv6.InterfaceID = query->qSRV.InterfaceID; 6054 } 6055 else 6056 { 6057 query->qAv4.InterfaceID = answer->InterfaceID; 6058 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 6059 query->qAv6.InterfaceID = answer->InterfaceID; 6060 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 6061 } 6062 debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c); 6063 mDNS_StartQuery(m, &query->qAv4); 6064 // Only do the AAAA query if this machine actually has IPv6 active 6065 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 6066 } 6067 else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged) 6068 { 6069 if (++query->Answers >= 100) 6070 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u", 6071 query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c, 6072 mDNSVal16(answer->rdata->u.srv.port)); 6073 query->ServiceInfoQueryCallback(m, query); 6074 } 6075 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 6076 // callback function is allowed to do anything, including deleting this query and freeing its memory. 6077 } 6078 6079 mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) 6080 { 6081 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 6082 if (!AddRecord) return; 6083 if (answer->rrtype != kDNSType_TXT) return; 6084 if (answer->rdlength > sizeof(query->info->TXTinfo)) return; 6085 6086 query->GotTXT = mDNStrue; 6087 query->info->TXTlen = answer->rdlength; 6088 query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero 6089 mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength); 6090 6091 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD); 6092 6093 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 6094 // callback function is allowed to do anything, including deleting this query and freeing its memory. 6095 if (query->ServiceInfoQueryCallback && query->GotADD) 6096 { 6097 if (++query->Answers >= 100) 6098 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...", 6099 query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c); 6100 query->ServiceInfoQueryCallback(m, query); 6101 } 6102 } 6103 6104 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) 6105 { 6106 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 6107 //LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); 6108 if (!AddRecord) return; 6109 6110 if (answer->rrtype == kDNSType_A) 6111 { 6112 query->info->ip.type = mDNSAddrType_IPv4; 6113 query->info->ip.ip.v4 = answer->rdata->u.ipv4; 6114 } 6115 else if (answer->rrtype == kDNSType_AAAA) 6116 { 6117 query->info->ip.type = mDNSAddrType_IPv6; 6118 query->info->ip.ip.v6 = answer->rdata->u.ipv6; 6119 } 6120 else 6121 { 6122 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype)); 6123 return; 6124 } 6125 6126 query->GotADD = mDNStrue; 6127 query->info->InterfaceID = answer->InterfaceID; 6128 6129 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT); 6130 6131 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 6132 // callback function is allowed to do anything, including deleting this query and freeing its memory. 6133 if (query->ServiceInfoQueryCallback && query->GotTXT) 6134 { 6135 if (++query->Answers >= 100) 6136 debugf(answer->rrtype == kDNSType_A ? 6137 "**** WARNING **** have given %lu answers for %##s (A) %.4a" : 6138 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", 6139 query->Answers, query->qSRV.qname.c, &answer->rdata->u.data); 6140 query->ServiceInfoQueryCallback(m, query); 6141 } 6142 } 6143 6144 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure 6145 // If the query is not interface-specific, then InterfaceID may be zero 6146 // Each time the Callback is invoked, the remainder of the fields will have been filled in 6147 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response 6148 mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, 6149 ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context) 6150 { 6151 mStatus status; 6152 mDNS_Lock(m); 6153 6154 query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 6155 query->qSRV.InterfaceID = info->InterfaceID; 6156 query->qSRV.Target = zeroAddr; 6157 AssignDomainName(&query->qSRV.qname, &info->name); 6158 query->qSRV.qtype = kDNSType_SRV; 6159 query->qSRV.qclass = kDNSClass_IN; 6160 query->qSRV.LongLived = mDNSfalse; 6161 query->qSRV.ExpectUnique = mDNStrue; 6162 query->qSRV.ForceMCast = mDNSfalse; 6163 query->qSRV.QuestionCallback = FoundServiceInfoSRV; 6164 query->qSRV.QuestionContext = query; 6165 6166 query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 6167 query->qTXT.InterfaceID = info->InterfaceID; 6168 query->qTXT.Target = zeroAddr; 6169 AssignDomainName(&query->qTXT.qname, &info->name); 6170 query->qTXT.qtype = kDNSType_TXT; 6171 query->qTXT.qclass = kDNSClass_IN; 6172 query->qTXT.LongLived = mDNSfalse; 6173 query->qTXT.ExpectUnique = mDNStrue; 6174 query->qTXT.ForceMCast = mDNSfalse; 6175 query->qTXT.QuestionCallback = FoundServiceInfoTXT; 6176 query->qTXT.QuestionContext = query; 6177 6178 query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 6179 query->qAv4.InterfaceID = info->InterfaceID; 6180 query->qAv4.Target = zeroAddr; 6181 query->qAv4.qname.c[0] = 0; 6182 query->qAv4.qtype = kDNSType_A; 6183 query->qAv4.qclass = kDNSClass_IN; 6184 query->qAv4.LongLived = mDNSfalse; 6185 query->qAv4.ExpectUnique = mDNStrue; 6186 query->qAv4.ForceMCast = mDNSfalse; 6187 query->qAv4.QuestionCallback = FoundServiceInfo; 6188 query->qAv4.QuestionContext = query; 6189 6190 query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 6191 query->qAv6.InterfaceID = info->InterfaceID; 6192 query->qAv6.Target = zeroAddr; 6193 query->qAv6.qname.c[0] = 0; 6194 query->qAv6.qtype = kDNSType_AAAA; 6195 query->qAv6.qclass = kDNSClass_IN; 6196 query->qAv6.LongLived = mDNSfalse; 6197 query->qAv6.ExpectUnique = mDNStrue; 6198 query->qAv6.ForceMCast = mDNSfalse; 6199 query->qAv6.QuestionCallback = FoundServiceInfo; 6200 query->qAv6.QuestionContext = query; 6201 6202 query->GotSRV = mDNSfalse; 6203 query->GotTXT = mDNSfalse; 6204 query->GotADD = mDNSfalse; 6205 query->Answers = 0; 6206 6207 query->info = info; 6208 query->ServiceInfoQueryCallback = Callback; 6209 query->ServiceInfoQueryContext = Context; 6210 6211 // info->name = Must already be set up by client 6212 // info->interface = Must already be set up by client 6213 info->ip = zeroAddr; 6214 info->port = zeroIPPort; 6215 info->TXTlen = 0; 6216 6217 // We use mDNS_StartQuery_internal here because we're already holding the lock 6218 status = mDNS_StartQuery_internal(m, &query->qSRV); 6219 if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT); 6220 if (status != mStatus_NoError) mDNS_StopResolveService(m, query); 6221 6222 mDNS_Unlock(m); 6223 return(status); 6224 } 6225 6226 mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q) 6227 { 6228 mDNS_Lock(m); 6229 // We use mDNS_StopQuery_internal here because we're already holding the lock 6230 if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV); 6231 if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT); 6232 if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4); 6233 if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6); 6234 mDNS_Unlock(m); 6235 } 6236 6237 mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom, 6238 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context) 6239 { 6240 question->InterfaceID = InterfaceID; 6241 question->Target = zeroAddr; 6242 question->qtype = kDNSType_PTR; 6243 question->qclass = kDNSClass_IN; 6244 question->LongLived = mDNSfalse; 6245 question->ExpectUnique = mDNSfalse; 6246 question->ForceMCast = mDNSfalse; 6247 question->QuestionCallback = Callback; 6248 question->QuestionContext = Context; 6249 if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); 6250 if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 6251 if (!dom) dom = &localdomain; 6252 if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr); 6253 return(mDNS_StartQuery(m, question)); 6254 } 6255 6256 // *************************************************************************** 6257 #if COMPILER_LIKES_PRAGMA_MARK 6258 #pragma mark - 6259 #pragma mark - Responder Functions 6260 #endif 6261 6262 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) 6263 { 6264 mStatus status; 6265 mDNS_Lock(m); 6266 status = mDNS_Register_internal(m, rr); 6267 mDNS_Unlock(m); 6268 return(status); 6269 } 6270 6271 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl, 6272 const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback) 6273 { 6274 #ifndef UNICAST_DISABLED 6275 mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name)); 6276 #else 6277 mDNSBool unicast = mDNSfalse; 6278 #endif 6279 6280 if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata)) 6281 { 6282 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); 6283 return(mStatus_Invalid); 6284 } 6285 6286 mDNS_Lock(m); 6287 6288 // If TTL is unspecified, leave TTL unchanged 6289 if (newttl == 0) newttl = rr->resrec.rroriginalttl; 6290 6291 // If we already have an update queued up which has not gone through yet, 6292 // give the client a chance to free that memory 6293 if (!unicast && rr->NewRData) 6294 { 6295 RData *n = rr->NewRData; 6296 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 6297 if (rr->UpdateCallback) 6298 rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary 6299 } 6300 6301 rr->NewRData = newrdata; 6302 rr->newrdlength = newrdlength; 6303 rr->UpdateCallback = Callback; 6304 6305 if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); } 6306 6307 if (rr->resrec.rroriginalttl == newttl && 6308 rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength)) 6309 CompleteRDataUpdate(m, rr); 6310 else 6311 { 6312 domainlabel name; 6313 domainname type, domain; 6314 DeconstructServiceName(rr->resrec.name, &name, &type, &domain); 6315 rr->AnnounceCount = InitialAnnounceCount; 6316 // iChat often does suprious record updates where no data has changed. For the _presence service type, using 6317 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful 6318 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data 6319 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us. 6320 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement. 6321 if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1; 6322 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); 6323 InitializeLastAPTime(m, rr); 6324 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 6325 if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--; 6326 if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval); 6327 if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1); 6328 if (rr->UpdateCredits <= 5) 6329 { 6330 mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum 6331 if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond); 6332 rr->ThisAPInterval *= 4; 6333 rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval; 6334 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", 6335 rr->resrec.name->c, delay, delay > 1 ? "s" : ""); 6336 } 6337 rr->resrec.rroriginalttl = newttl; 6338 } 6339 6340 mDNS_Unlock(m); 6341 return(mStatus_NoError); 6342 } 6343 6344 // NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change 6345 // the record list and/or question list. 6346 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 6347 mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) 6348 { 6349 mStatus status; 6350 mDNS_Lock(m); 6351 status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 6352 mDNS_Unlock(m); 6353 return(status); 6354 } 6355 6356 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); 6357 6358 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) 6359 { 6360 NetworkInterfaceInfo *intf; 6361 for (intf = m->HostInterfaces; intf; intf = intf->next) 6362 if (intf->Advertise) break; 6363 return(intf); 6364 } 6365 6366 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 6367 { 6368 char buffer[256]; 6369 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 6370 if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary 6371 6372 // Send dynamic update for non-linklocal IPv4 Addresses 6373 mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, mDNS_HostNameCallback, set); 6374 mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 6375 mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL); 6376 6377 #if ANSWER_REMOTE_HOSTNAME_QUERIES 6378 set->RR_A .AllowRemoteQuery = mDNStrue; 6379 set->RR_PTR .AllowRemoteQuery = mDNStrue; 6380 set->RR_HINFO.AllowRemoteQuery = mDNStrue; 6381 #endif 6382 // 1. Set up Address record to map from host name ("foo.local.") to IP address 6383 // 2. Set up reverse-lookup PTR record to map from our address back to our host name 6384 AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname); 6385 if (set->ip.type == mDNSAddrType_IPv4) 6386 { 6387 set->RR_A.resrec.rrtype = kDNSType_A; 6388 set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4; 6389 // Note: This is reverse order compared to a normal dotted-decimal IP address 6390 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", 6391 set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]); 6392 } 6393 else if (set->ip.type == mDNSAddrType_IPv6) 6394 { 6395 int i; 6396 set->RR_A.resrec.rrtype = kDNSType_AAAA; 6397 set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6; 6398 for (i = 0; i < 16; i++) 6399 { 6400 static const char hexValues[] = "0123456789ABCDEF"; 6401 buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F]; 6402 buffer[i * 4 + 1] = '.'; 6403 buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4]; 6404 buffer[i * 4 + 3] = '.'; 6405 } 6406 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); 6407 } 6408 6409 MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer); 6410 set->RR_PTR.HostTarget = mDNStrue; // Tell mDNS that the target of this PTR is to be kept in sync with our host name 6411 set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server 6412 6413 set->RR_A.RRSet = &primary->RR_A; // May refer to self 6414 6415 mDNS_Register_internal(m, &set->RR_A); 6416 mDNS_Register_internal(m, &set->RR_PTR); 6417 6418 if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254) 6419 { 6420 mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data; 6421 AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname); 6422 set->RR_HINFO.DependentOn = &set->RR_A; 6423 mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]); 6424 p += 1 + (int)p[0]; 6425 mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]); 6426 mDNS_Register_internal(m, &set->RR_HINFO); 6427 } 6428 else 6429 { 6430 debugf("Not creating HINFO record: platform support layer provided no information"); 6431 set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered; 6432 } 6433 } 6434 6435 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 6436 { 6437 NetworkInterfaceInfo *intf; 6438 6439 // If we still have address records referring to this one, update them 6440 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 6441 AuthRecord *A = primary ? &primary->RR_A : mDNSNULL; 6442 for (intf = m->HostInterfaces; intf; intf = intf->next) 6443 if (intf->RR_A.RRSet == &set->RR_A) 6444 intf->RR_A.RRSet = A; 6445 6446 // Unregister these records. 6447 // When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform 6448 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it. 6449 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered. 6450 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal(). 6451 if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal); 6452 if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal); 6453 if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal); 6454 } 6455 6456 mDNSexport void mDNS_SetFQDN(mDNS *const m) 6457 { 6458 domainname newmname; 6459 NetworkInterfaceInfo *intf; 6460 AuthRecord *rr; 6461 newmname.c[0] = 0; 6462 6463 if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 6464 if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 6465 if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; } 6466 6467 mDNS_Lock(m); 6468 AssignDomainName(&m->MulticastHostname, &newmname); 6469 6470 // 1. Stop advertising our address records on all interfaces 6471 for (intf = m->HostInterfaces; intf; intf = intf->next) 6472 if (intf->Advertise) DeadvertiseInterface(m, intf); 6473 6474 // 2. Start advertising our address records using the new name 6475 for (intf = m->HostInterfaces; intf; intf = intf->next) 6476 if (intf->Advertise) AdvertiseInterface(m, intf); 6477 6478 // 3. Make sure that any SRV records (and the like) that reference our 6479 // host name in their rdata get updated to reference this new host name 6480 for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr); 6481 for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr); 6482 6483 mDNS_Unlock(m); 6484 } 6485 6486 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 6487 { 6488 (void)rr; // Unused parameter 6489 6490 #if MDNS_DEBUGMSGS 6491 { 6492 char *msg = "Unknown result"; 6493 if (result == mStatus_NoError) msg = "Name registered"; 6494 else if (result == mStatus_NameConflict) msg = "Name conflict"; 6495 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 6496 } 6497 #endif 6498 6499 if (result == mStatus_NoError) 6500 { 6501 // Notify the client that the host name is successfully registered 6502 if (m->MainCallback) 6503 { 6504 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 6505 m->MainCallback(m, result); 6506 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 6507 } 6508 } 6509 else if (result == mStatus_NameConflict) 6510 { 6511 domainlabel oldlabel = m->hostlabel; 6512 6513 // 1. First give the client callback a chance to pick a new name 6514 if (m->MainCallback) 6515 { 6516 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 6517 m->MainCallback(m, mStatus_NameConflict); 6518 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 6519 } 6520 6521 // 2. If the client callback didn't do it, add (or increment) an index ourselves 6522 if (SameDomainLabel(m->hostlabel.c, oldlabel.c)) 6523 IncrementLabelSuffix(&m->hostlabel, mDNSfalse); 6524 6525 // 3. Generate the FQDNs from the hostlabel, 6526 // and make sure all SRV records, etc., are updated to reference our new hostname 6527 mDNS_SetFQDN(m); 6528 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c); 6529 } 6530 else if (result == mStatus_MemFree) 6531 { 6532 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by 6533 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface 6534 debugf("mDNS_HostNameCallback: MemFree (ignored)"); 6535 } 6536 else 6537 LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result, rr->resrec.name->c); 6538 } 6539 6540 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active) 6541 { 6542 NetworkInterfaceInfo *intf; 6543 active->IPv4Available = mDNSfalse; 6544 active->IPv6Available = mDNSfalse; 6545 for (intf = m->HostInterfaces; intf; intf = intf->next) 6546 if (intf->InterfaceID == active->InterfaceID) 6547 { 6548 if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue; 6549 if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue; 6550 } 6551 } 6552 6553 mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 6554 { 6555 mDNSBool FirstOfType = mDNStrue; 6556 NetworkInterfaceInfo **p = &m->HostInterfaces; 6557 6558 if (!set->InterfaceID) 6559 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); } 6560 6561 if (!mDNSAddressIsValidNonZero(&set->mask)) 6562 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); } 6563 6564 mDNS_Lock(m); 6565 6566 // Assume this interface will be active now, unless we find a duplicate already in the list 6567 set->InterfaceActive = mDNStrue; 6568 set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx); 6569 set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx); 6570 6571 // Scan list to see if this InterfaceID is already represented 6572 while (*p) 6573 { 6574 if (*p == set) 6575 { 6576 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list"); 6577 mDNS_Unlock(m); 6578 return(mStatus_AlreadyRegistered); 6579 } 6580 6581 if ((*p)->InterfaceID == set->InterfaceID) 6582 { 6583 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now 6584 set->InterfaceActive = mDNSfalse; 6585 if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse; 6586 if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue; 6587 if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue; 6588 } 6589 6590 p=&(*p)->next; 6591 } 6592 6593 set->next = mDNSNULL; 6594 *p = set; 6595 6596 if (set->Advertise) 6597 AdvertiseInterface(m, set); 6598 6599 LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip, 6600 set->InterfaceActive ? 6601 "not represented in list; marking active and retriggering queries" : 6602 "already represented in list; marking inactive for now"); 6603 6604 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 6605 // giving the false impression that there's an active representative of this interface when there really isn't. 6606 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records, 6607 // even if we believe that we previously had an active representative of this interface. 6608 if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive)) 6609 { 6610 DNSQuestion *q; 6611 AuthRecord *rr; 6612 // If flapping, delay between first and second queries is eight seconds instead of one 6613 mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0; 6614 mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount; 6615 6616 // Use a small amount of randomness: 6617 // In the case of a network administrator turning on an Ethernet hub so that all the 6618 // connected machines establish link at exactly the same time, we don't want them all 6619 // to go and hit the network with identical queries at exactly the same moment. 6620 if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); 6621 6622 if (flapping) 6623 { 6624 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip); 6625 if (!m->SuppressProbes || 6626 m->SuppressProbes - (m->timenow + delay) < 0) 6627 m->SuppressProbes = (m->timenow + delay); 6628 } 6629 6630 for (q = m->Questions; q; q=q->next) // Scan our list of questions 6631 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, 6632 { // then reactivate this question 6633 mDNSs32 initial = (flapping && q->FlappingInterface != set->InterfaceID) ? InitialQuestionInterval * 8 : InitialQuestionInterval; 6634 mDNSs32 qdelay = (flapping && q->FlappingInterface != set->InterfaceID) ? mDNSPlatformOneSecond * 5 : 0; 6635 if (flapping && q->FlappingInterface == set->InterfaceID) 6636 LogOperation("No cache records for %##s (%s) expired; no need for immediate question", q->qname.c, DNSTypeName(q->qtype)); 6637 6638 if (!q->ThisQInterval || q->ThisQInterval > initial) 6639 { 6640 q->ThisQInterval = initial; 6641 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 6642 } 6643 if (q->LastQTime - (m->timenow - q->ThisQInterval + qdelay) > 0) 6644 q->LastQTime = (m->timenow - q->ThisQInterval + qdelay); 6645 q->RecentAnswerPkts = 0; 6646 SetNextQueryTime(m,q); 6647 } 6648 6649 // For all our non-specific authoritative resource records (and any dormant records specific to this interface) 6650 // we now need them to re-probe if necessary, and then re-announce. 6651 for (rr = m->ResourceRecords; rr; rr=rr->next) 6652 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID) 6653 { 6654 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 6655 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 6656 if (rr->AnnounceCount < announce) rr->AnnounceCount = announce; 6657 rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); 6658 InitializeLastAPTime(m, rr); 6659 } 6660 } 6661 6662 mDNS_Unlock(m); 6663 return(mStatus_NoError); 6664 } 6665 6666 // NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change 6667 // the record list and/or question list. 6668 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 6669 mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 6670 { 6671 NetworkInterfaceInfo **p = &m->HostInterfaces; 6672 6673 mDNSBool revalidate = mDNSfalse; 6674 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every 6675 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it 6676 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion. 6677 if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue; 6678 6679 mDNS_Lock(m); 6680 6681 // Find this record in our list 6682 while (*p && *p != set) p=&(*p)->next; 6683 if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; } 6684 6685 // Unlink this record from our list 6686 *p = (*p)->next; 6687 set->next = mDNSNULL; 6688 6689 if (!set->InterfaceActive) 6690 { 6691 // If this interface not the active member of its set, update the v4/v6Available flags for the active member 6692 NetworkInterfaceInfo *intf; 6693 for (intf = m->HostInterfaces; intf; intf = intf->next) 6694 if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID) 6695 UpdateInterfaceProtocols(m, intf); 6696 } 6697 else 6698 { 6699 NetworkInterfaceInfo *intf; 6700 for (intf = m->HostInterfaces; intf; intf = intf->next) 6701 if (intf->InterfaceID == set->InterfaceID) 6702 break; 6703 if (intf) 6704 { 6705 LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" 6706 " making it active", set->InterfaceID, set->ifname, &set->ip); 6707 intf->InterfaceActive = mDNStrue; 6708 UpdateInterfaceProtocols(m, intf); 6709 6710 // See if another representative *of the same type* exists. If not, we mave have gone from 6711 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid. 6712 for (intf = m->HostInterfaces; intf; intf = intf->next) 6713 if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type) 6714 break; 6715 if (!intf) revalidate = mDNStrue; 6716 } 6717 else 6718 { 6719 mDNSu32 slot; 6720 CacheGroup *cg; 6721 CacheRecord *rr; 6722 DNSQuestion *q; 6723 LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" 6724 " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip); 6725 6726 if (flapping) 6727 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", 6728 set->ifname, &set->ip); 6729 6730 // 1. Deactivate any questions specific to this interface, and tag appropriate questions 6731 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them 6732 for (q = m->Questions; q; q=q->next) 6733 { 6734 if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0; 6735 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) 6736 q->FlappingInterface = set->InterfaceID; 6737 } 6738 6739 // 2. Flush any cache records received on this interface 6740 revalidate = mDNSfalse; // Don't revalidate if we're flushing the records 6741 FORALL_CACHERECORDS(slot, cg, rr) 6742 if (rr->resrec.InterfaceID == set->InterfaceID) 6743 { 6744 // If this interface is deemed flapping, 6745 // postpone deleting the cache records in case the interface comes back again 6746 if (!flapping) PurgeCacheResourceRecord(m, rr); 6747 else mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 6748 } 6749 } 6750 } 6751 6752 // If we were advertising on this interface, deregister those address and reverse-lookup records now 6753 if (set->Advertise) DeadvertiseInterface(m, set); 6754 6755 // If we have any cache records received on this interface that went away, then re-verify them. 6756 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 6757 // giving the false impression that there's an active representative of this interface when there really isn't. 6758 // Don't need to do this when shutting down, because *all* interfaces are about to go away 6759 if (revalidate && !m->mDNS_shutdown) 6760 { 6761 mDNSu32 slot; 6762 CacheGroup *cg; 6763 CacheRecord *rr; 6764 m->NextCacheCheck = m->timenow; 6765 FORALL_CACHERECORDS(slot, cg, rr) 6766 if (rr->resrec.InterfaceID == set->InterfaceID) 6767 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 6768 } 6769 6770 mDNS_Unlock(m); 6771 } 6772 6773 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 6774 { 6775 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 6776 (void)m; // Unused parameter 6777 6778 #if MDNS_DEBUGMSGS 6779 { 6780 char *msg = "Unknown result"; 6781 if (result == mStatus_NoError) msg = "Name Registered"; 6782 else if (result == mStatus_NameConflict) msg = "Name Conflict"; 6783 else if (result == mStatus_MemFree) msg = "Memory Free"; 6784 debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 6785 } 6786 #endif 6787 6788 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing) 6789 if (result == mStatus_NoError && rr != &sr->RR_SRV) return; 6790 6791 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that 6792 if (result == mStatus_NameConflict) 6793 { 6794 sr->Conflict = mDNStrue; // Record that this service set had a conflict 6795 mDNS_DeregisterService(m, sr); // Unlink the records from our list 6796 return; 6797 } 6798 6799 if (result == mStatus_MemFree) 6800 { 6801 // If the PTR record or any of the subtype PTR records are still in the process of deregistering, 6802 // don't pass on the NameConflict/MemFree message until every record is finished cleaning up. 6803 mDNSu32 i; 6804 if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return; 6805 for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return; 6806 6807 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse, 6808 // then we can now report the NameConflict to the client 6809 if (sr->Conflict) result = mStatus_NameConflict; 6810 } 6811 6812 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback 6813 // function is allowed to do anything, including deregistering this service and freeing its memory. 6814 if (sr->ServiceCallback) 6815 sr->ServiceCallback(m, sr, result); 6816 } 6817 6818 mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 6819 { 6820 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 6821 if (sr->ServiceCallback) 6822 sr->ServiceCallback(m, sr, result); 6823 } 6824 6825 // Note: 6826 // Name is first label of domain name (any dots in the name are actual dots, not label separators) 6827 // Type is service type (e.g. "_ipp._tcp.") 6828 // Domain is fully qualified domain name (i.e. ending with a null label) 6829 // We always register a TXT, even if it is empty (so that clients are not 6830 // left waiting forever looking for a nonexistent record.) 6831 // If the host parameter is mDNSNULL or the root domain (ASCII NUL), 6832 // then the default host name (m->MulticastHostname) is automatically used 6833 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, 6834 const domainlabel *const name, const domainname *const type, const domainname *const domain, 6835 const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, 6836 AuthRecord *SubTypes, mDNSu32 NumSubTypes, 6837 const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context) 6838 { 6839 mStatus err; 6840 mDNSu32 i; 6841 6842 sr->ServiceCallback = Callback; 6843 sr->ServiceContext = Context; 6844 sr->Extras = mDNSNULL; 6845 sr->NumSubTypes = NumSubTypes; 6846 sr->SubTypes = SubTypes; 6847 sr->Conflict = mDNSfalse; 6848 if (host && host->c[0]) sr->Host = *host; 6849 else sr->Host.c[0] = 0; 6850 6851 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService 6852 if (!port.NotAnInteger) 6853 return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr)); 6854 6855 // Initialize the AuthRecord objects to sane values 6856 mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr); 6857 mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); 6858 mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr); 6859 mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr); 6860 6861 // If the client is registering an oversized TXT record, 6862 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it 6863 if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen) 6864 sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen; 6865 6866 // Set up the record names 6867 // For now we only create an advisory record for the main type, not for subtypes 6868 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too 6869 if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL) 6870 return(mStatus_BadParamErr); 6871 if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 6872 if (ConstructServiceName(sr->RR_SRV.resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 6873 AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name); 6874 6875 // 1. Set up the ADV record rdata to advertise our service type 6876 AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name); 6877 6878 // 2. Set up the PTR record rdata to point to our service name 6879 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too 6880 AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name); 6881 sr->RR_PTR.Additional1 = &sr->RR_SRV; 6882 sr->RR_PTR.Additional2 = &sr->RR_TXT; 6883 6884 // 2a. Set up any subtype PTRs to point to our service name 6885 // If the client is using subtypes, it is the client's responsibility to have 6886 // already set the first label of the record name to the subtype being registered 6887 for (i=0; i<NumSubTypes; i++) 6888 { 6889 domainname st; 6890 AssignDomainName(&st, sr->SubTypes[i].resrec.name); 6891 st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService()) 6892 AppendDomainName(&st, type); 6893 mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); 6894 if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr); 6895 AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name); 6896 sr->SubTypes[i].Additional1 = &sr->RR_SRV; 6897 sr->SubTypes[i].Additional2 = &sr->RR_TXT; 6898 } 6899 6900 // 3. Set up the SRV record rdata. 6901 sr->RR_SRV.resrec.rdata->u.srv.priority = 0; 6902 sr->RR_SRV.resrec.rdata->u.srv.weight = 0; 6903 sr->RR_SRV.resrec.rdata->u.srv.port = port; 6904 6905 // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name 6906 if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host); 6907 else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; } 6908 6909 // 4. Set up the TXT record rdata, 6910 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us 6911 if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0; 6912 else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c) 6913 { 6914 sr->RR_TXT.resrec.rdlength = txtlen; 6915 if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr); 6916 mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen); 6917 } 6918 sr->RR_TXT.DependentOn = &sr->RR_SRV; 6919 6920 #ifndef UNICAST_DISABLED 6921 // If the client has specified an explicit InterfaceID, 6922 // then we do a multicast registration on that interface, even for unicast domains. 6923 if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) 6924 { 6925 mStatus status; 6926 mDNS_Lock(m); 6927 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 6928 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 6929 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 6930 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck) 6931 if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; } 6932 status = uDNS_RegisterService(m, sr); 6933 mDNS_Unlock(m); 6934 return(status); 6935 } 6936 #endif 6937 mDNS_Lock(m); 6938 err = mDNS_Register_internal(m, &sr->RR_SRV); 6939 if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT); 6940 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to 6941 // mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers 6942 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to 6943 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to 6944 // make sure we've deregistered all our records and done any other necessary cleanup before that happens. 6945 if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV); 6946 for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]); 6947 if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR); 6948 6949 mDNS_Unlock(m); 6950 6951 if (err) mDNS_DeregisterService(m, sr); 6952 return(err); 6953 } 6954 6955 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, 6956 ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl) 6957 { 6958 ExtraResourceRecord **e; 6959 mStatus status; 6960 6961 extra->next = mDNSNULL; 6962 mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, 6963 extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr); 6964 AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name); 6965 6966 #ifndef UNICAST_DISABLED 6967 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) 6968 { 6969 mDNS_Lock(m); 6970 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 6971 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 6972 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 6973 // (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck) 6974 if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0) 6975 { extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; } 6976 status = uDNS_AddRecordToService(m, sr, extra); 6977 mDNS_Unlock(m); 6978 return status; 6979 } 6980 #endif 6981 6982 mDNS_Lock(m); 6983 e = &sr->Extras; 6984 while (*e) e = &(*e)->next; 6985 6986 if (ttl == 0) ttl = kStandardTTL; 6987 6988 extra->r.DependentOn = &sr->RR_SRV; 6989 6990 debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c); 6991 6992 status = mDNS_Register_internal(m, &extra->r); 6993 if (status == mStatus_NoError) *e = extra; 6994 mDNS_Unlock(m); 6995 return(status); 6996 } 6997 6998 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, 6999 mDNSRecordCallback MemFreeCallback, void *Context) 7000 { 7001 ExtraResourceRecord **e; 7002 mStatus status; 7003 7004 mDNS_Lock(m); 7005 e = &sr->Extras; 7006 while (*e && *e != extra) e = &(*e)->next; 7007 if (!*e) 7008 { 7009 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c); 7010 status = mStatus_BadReferenceErr; 7011 } 7012 else 7013 { 7014 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c); 7015 extra->r.RecordCallback = MemFreeCallback; 7016 extra->r.RecordContext = Context; 7017 *e = (*e)->next; 7018 #ifndef UNICAST_DISABLED 7019 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) 7020 status = uDNS_DeregisterRecord(m, &extra->r); 7021 else 7022 #endif 7023 status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal); 7024 } 7025 mDNS_Unlock(m); 7026 return(status); 7027 } 7028 7029 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname) 7030 { 7031 // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines 7032 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally. 7033 domainlabel name1, name2; 7034 domainname type, domain; 7035 domainname *host = mDNSNULL; 7036 ExtraResourceRecord *extras = sr->Extras; 7037 mStatus err; 7038 7039 DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain); 7040 if (!newname) 7041 { 7042 name2 = name1; 7043 IncrementLabelSuffix(&name2, mDNStrue); 7044 newname = &name2; 7045 } 7046 7047 if (SameDomainName(&domain, &localdomain)) 7048 LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c); 7049 else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c); 7050 7051 if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host; 7052 7053 err = mDNS_RegisterService(m, sr, newname, &type, &domain, 7054 host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, 7055 sr->SubTypes, sr->NumSubTypes, 7056 sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext); 7057 7058 // mDNS_RegisterService() just reset sr->Extras to NULL. 7059 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run 7060 // through the old list of extra records, and re-add them to our freshly created service registration 7061 while (!err && extras) 7062 { 7063 ExtraResourceRecord *e = extras; 7064 extras = extras->next; 7065 err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl); 7066 } 7067 7068 return(err); 7069 } 7070 7071 // NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback, 7072 // which may change the record list and/or question list. 7073 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 7074 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) 7075 { 7076 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService() 7077 if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); 7078 7079 #ifndef UNICAST_DISABLED 7080 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) 7081 { 7082 mStatus status; 7083 mDNS_Lock(m); 7084 status = uDNS_DeregisterService(m, sr); 7085 mDNS_Unlock(m); 7086 return(status); 7087 } 7088 #endif 7089 if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered) 7090 { 7091 debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c); 7092 return(mStatus_BadReferenceErr); 7093 } 7094 else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering) 7095 { 7096 debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c); 7097 return(mStatus_NoError); 7098 } 7099 else 7100 { 7101 mDNSu32 i; 7102 mStatus status; 7103 ExtraResourceRecord *e; 7104 mDNS_Lock(m); 7105 e = sr->Extras; 7106 7107 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the 7108 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay 7109 mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat); 7110 mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat); 7111 7112 mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal); 7113 7114 // We deregister all of the extra records, but we leave the sr->Extras list intact 7115 // in case the client wants to do a RenameAndReregister and reinstate the registration 7116 while (e) 7117 { 7118 mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat); 7119 e = e->next; 7120 } 7121 7122 for (i=0; i<sr->NumSubTypes; i++) 7123 mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal); 7124 7125 // Be sure to deregister the PTR last! 7126 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback, 7127 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback, 7128 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure 7129 // we've deregistered all our records and done any other necessary cleanup before that happens. 7130 status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal); 7131 mDNS_Unlock(m); 7132 return(status); 7133 } 7134 } 7135 7136 // Create a registration that asserts that no such service exists with this name. 7137 // This can be useful where there is a given function is available through several protocols. 7138 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP" 7139 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an 7140 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing 7141 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users. 7142 mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr, 7143 const domainlabel *const name, const domainname *const type, const domainname *const domain, 7144 const domainname *const host, 7145 const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context) 7146 { 7147 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context); 7148 if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 7149 rr->resrec.rdata->u.srv.priority = 0; 7150 rr->resrec.rdata->u.srv.weight = 0; 7151 rr->resrec.rdata->u.srv.port = zeroIPPort; 7152 if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host); 7153 else rr->HostTarget = mDNStrue; 7154 return(mDNS_Register(m, rr)); 7155 } 7156 7157 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, 7158 mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname) 7159 { 7160 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL); 7161 if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 7162 if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr); 7163 return(mDNS_Register(m, rr)); 7164 } 7165 7166 // *************************************************************************** 7167 #if COMPILER_LIKES_PRAGMA_MARK 7168 #pragma mark - 7169 #pragma mark - 7170 #pragma mark - Startup and Shutdown 7171 #endif 7172 7173 mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 7174 { 7175 if (storage && numrecords) 7176 { 7177 mDNSu32 i; 7178 debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity)); 7179 for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1]; 7180 storage[numrecords-1].next = m->rrcache_free; 7181 m->rrcache_free = storage; 7182 m->rrcache_size += numrecords; 7183 } 7184 } 7185 7186 mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 7187 { 7188 mDNS_Lock(m); 7189 mDNS_GrowCache_internal(m, storage, numrecords); 7190 mDNS_Unlock(m); 7191 } 7192 7193 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, 7194 CacheEntity *rrcachestorage, mDNSu32 rrcachesize, 7195 mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) 7196 { 7197 mDNSu32 slot; 7198 mDNSs32 timenow; 7199 mStatus result; 7200 7201 if (!rrcachestorage) rrcachesize = 0; 7202 7203 m->p = p; 7204 m->KnownBugs = 0; 7205 m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise 7206 m->AdvertiseLocalAddresses = AdvertiseLocalAddresses; 7207 m->mDNSPlatformStatus = mStatus_Waiting; 7208 m->UnicastPort4 = zeroIPPort; 7209 m->UnicastPort6 = zeroIPPort; 7210 m->MainCallback = Callback; 7211 m->MainContext = Context; 7212 m->rec.r.resrec.RecordType = 0; 7213 7214 // For debugging: To catch and report locking failures 7215 m->mDNS_busy = 0; 7216 m->mDNS_reentrancy = 0; 7217 m->mDNS_shutdown = mDNSfalse; 7218 m->lock_rrcache = 0; 7219 m->lock_Questions = 0; 7220 m->lock_Records = 0; 7221 7222 // Task Scheduling variables 7223 result = mDNSPlatformTimeInit(); 7224 if (result != mStatus_NoError) return(result); 7225 m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF); 7226 timenow = mDNS_TimeNow_NoLock(m); 7227 7228 m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section 7229 m->timenow_last = timenow; 7230 m->NextScheduledEvent = timenow; 7231 m->SuppressSending = timenow; 7232 m->NextCacheCheck = timenow + 0x78000000; 7233 m->NextScheduledQuery = timenow + 0x78000000; 7234 m->NextScheduledProbe = timenow + 0x78000000; 7235 m->NextScheduledResponse = timenow + 0x78000000; 7236 m->ExpectUnicastResponse = timenow + 0x78000000; 7237 m->RandomQueryDelay = 0; 7238 m->RandomReconfirmDelay = 0; 7239 m->PktNum = 0; 7240 m->SendDeregistrations = mDNSfalse; 7241 m->SendImmediateAnswers = mDNSfalse; 7242 m->SleepState = mDNSfalse; 7243 7244 // These fields only required for mDNS Searcher... 7245 m->Questions = mDNSNULL; 7246 m->NewQuestions = mDNSNULL; 7247 m->CurrentQuestion = mDNSNULL; 7248 m->LocalOnlyQuestions = mDNSNULL; 7249 m->NewLocalOnlyQuestions = mDNSNULL; 7250 m->rrcache_size = 0; 7251 m->rrcache_totalused = 0; 7252 m->rrcache_active = 0; 7253 m->rrcache_report = 10; 7254 m->rrcache_free = mDNSNULL; 7255 7256 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL; 7257 7258 mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize); 7259 7260 // Fields below only required for mDNS Responder... 7261 m->hostlabel.c[0] = 0; 7262 m->nicelabel.c[0] = 0; 7263 m->MulticastHostname.c[0] = 0; 7264 m->HIHardware.c[0] = 0; 7265 m->HISoftware.c[0] = 0; 7266 m->ResourceRecords = mDNSNULL; 7267 m->DuplicateRecords = mDNSNULL; 7268 m->NewLocalRecords = mDNSNULL; 7269 m->CurrentRecord = mDNSNULL; 7270 m->HostInterfaces = mDNSNULL; 7271 m->ProbeFailTime = 0; 7272 m->NumFailedProbes = 0; 7273 m->SuppressProbes = 0; 7274 7275 #ifndef UNICAST_DISABLED 7276 uDNS_Init(m); 7277 m->SuppressStdPort53Queries = 0; 7278 #endif 7279 result = mDNSPlatformInit(m); 7280 7281 return(result); 7282 } 7283 7284 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) 7285 { 7286 m->mDNSPlatformStatus = result; 7287 if (m->MainCallback) 7288 { 7289 mDNS_Lock(m); 7290 m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback 7291 m->MainCallback(m, mStatus_NoError); 7292 m->mDNS_reentrancy--; // Decrement to block mDNS API calls again 7293 mDNS_Unlock(m); 7294 } 7295 } 7296 7297 mDNSexport void mDNS_Close(mDNS *const m) 7298 { 7299 mDNSu32 rrcache_active = 0; 7300 mDNSu32 rrcache_totalused = 0; 7301 mDNSu32 slot; 7302 NetworkInterfaceInfo *intf; 7303 mDNS_Lock(m); 7304 7305 m->mDNS_shutdown = mDNStrue; 7306 7307 #ifndef UNICAST_DISABLED 7308 uDNS_Close(m); 7309 #endif 7310 rrcache_totalused = m->rrcache_totalused; 7311 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 7312 { 7313 while(m->rrcache_hash[slot]) 7314 { 7315 CacheGroup *cg = m->rrcache_hash[slot]; 7316 while (cg->members) 7317 { 7318 CacheRecord *rr = cg->members; 7319 cg->members = cg->members->next; 7320 if (rr->CRActiveQuestion) rrcache_active++; 7321 ReleaseCacheRecord(m, rr); 7322 } 7323 cg->rrcache_tail = &cg->members; 7324 ReleaseCacheGroup(m, &m->rrcache_hash[slot]); 7325 } 7326 } 7327 debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); 7328 if (rrcache_active != m->rrcache_active) 7329 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); 7330 7331 for (intf = m->HostInterfaces; intf; intf = intf->next) 7332 if (intf->Advertise) 7333 DeadvertiseInterface(m, intf); 7334 7335 // Make sure there are nothing but deregistering records remaining in the list 7336 if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set"); 7337 m->CurrentRecord = m->ResourceRecords; 7338 while (m->CurrentRecord) 7339 { 7340 AuthRecord *rr = m->CurrentRecord; 7341 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) 7342 { 7343 debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c); 7344 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 7345 } 7346 else 7347 m->CurrentRecord = rr->next; 7348 } 7349 7350 if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records"); 7351 else debugf("mDNS_Close: No deregistering records remain"); 7352 7353 // If any deregistering records remain, send their deregistration announcements before we exit 7354 if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); 7355 else if (m->ResourceRecords) SendResponses(m); 7356 if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords)); 7357 7358 mDNS_Unlock(m); 7359 debugf("mDNS_Close: mDNSPlatformClose"); 7360 mDNSPlatformClose(m); 7361 debugf("mDNS_Close: done"); 7362 } 7363