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 compile 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 40Log: mDNS.c,v $ 41Revision 1.969.2.1 2009/07/23 23:41:25 cheshire 42<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity 43 44Revision 1.969 2009/06/30 21:18:19 cheshire 45<rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event 46Additional fixes: 471. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters 482. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations 49 50Revision 1.968 2009/06/29 23:51:09 cheshire 51<rdar://problem/6690034> Can't bind to Active Directory 52 53Revision 1.967 2009/06/27 00:25:27 cheshire 54<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests 55Removed overly-complicate and ineffective multi-packet known-answer snooping code 56(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later) 57 58Revision 1.966 2009/06/26 01:55:55 cheshire 59<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour 60Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own), 61add additional NSEC records only when there's space to do that without having to generate an additional packet 62 63Revision 1.965 2009/06/24 22:14:21 cheshire 64<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event 65 66Revision 1.964 2009/06/03 23:07:13 cheshire 67<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour 68Large records were not being added in cases where an NSEC record was also required 69 70Revision 1.963 2009/05/28 00:39:19 cheshire 71<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on 72After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet 73 74Revision 1.962 2009/05/19 23:40:37 cheshire 75<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks 76Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries 77 78Revision 1.961 2009/05/19 23:00:43 cheshire 79Improved comments and debugging messages 80 81Revision 1.960 2009/05/13 17:25:33 mkrochma 82<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services 83Sleep proxy client should only look for services being advertised via Multicast 84 85Revision 1.959 2009/05/12 23:10:31 cheshire 86<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services 87Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake 88 89Revision 1.958 2009/05/12 19:19:20 cheshire 90<rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN 91 92Revision 1.957 2009/05/07 23:56:25 cheshire 93<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests 94To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question 95 96Revision 1.956 2009/05/07 23:46:27 cheshire 97<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests 98 99Revision 1.955 2009/05/07 23:40:54 cheshire 100Minor code rearrangement in preparation for upcoming changes 101 102Revision 1.954 2009/05/01 21:28:34 cheshire 103<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds 104No longer suspend network operations after we've acknowledged that the machine is going to sleep, 105because other software may not have yet acknowledged the sleep event, and may be still trying 106to do unicast DNS queries or other Bonjour operations. 107 108Revision 1.953 2009/05/01 19:17:35 cheshire 109<rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power 110 111Revision 1.952 2009/05/01 19:16:45 mcguire 112<rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844 113 114Revision 1.951 2009/04/28 23:48:19 jessic2 115<rdar://problem/6830541> regservice_callback: instance->request is NULL 0 116 117Revision 1.950 2009/04/25 01:17:10 mcguire 118Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep 119 120Revision 1.949 2009/04/25 01:11:02 mcguire 121Refactor: create separate function: RestartRecordGetZoneData 122 123Revision 1.948 2009/04/24 21:25:16 cheshire 124<rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network 125 126Revision 1.947 2009/04/24 19:41:12 mcguire 127<rdar://problem/6791775> 4 second delay in DNS response 128 129Revision 1.946 2009/04/24 19:28:39 mcguire 130<rdar://problem/6791775> 4 second delay in DNS response 131 132Revision 1.945 2009/04/24 00:30:30 cheshire 133<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists 134Added code to generate and process NSEC records 135 136Revision 1.944 2009/04/23 22:06:29 cheshire 137Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for: 138<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists 139 140Revision 1.943 2009/04/22 01:19:56 jessic2 141<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 142 143Revision 1.942 2009/04/21 02:13:29 cheshire 144<rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict 145Made code less susceptible to being tricked by stale packets echoed back from the network. 146 147Revision 1.941 2009/04/15 22:22:23 mcguire 148<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures 149Additional fix: protect against deref of NULL 150 151Revision 1.940 2009/04/15 20:42:51 mcguire 152<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures 153 154Revision 1.939 2009/04/11 00:19:32 jessic2 155<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically 156 157Revision 1.938 2009/04/06 23:44:57 cheshire 158<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance 159 160Revision 1.937 2009/04/04 00:14:49 mcguire 161fix logging in BeginSleepProcessing 162 163Revision 1.936 2009/04/04 00:10:59 mcguire 164don't ignore m->SystemWakeOnLANEnabled when going to sleep 165 166Revision 1.935 2009/04/01 17:50:11 mcguire 167cleanup mDNSRandom 168 169Revision 1.934 2009/03/27 17:17:58 cheshire 170Improved "Ignoring suspect uDNS response" debugging message 171 172Revision 1.933 2009/03/21 02:40:21 cheshire 173<rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA 174 175Revision 1.932 2009/03/20 23:53:03 jessic2 176<rdar://problem/6646228> SIGHUP should restart all in-progress queries 177 178Revision 1.931 2009/03/18 19:08:15 cheshire 179Show old/new sleep sequence numbers in logical order 180 181Revision 1.930 2009/03/17 23:40:45 cheshire 182For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings 183 184Revision 1.929 2009/03/17 21:55:56 cheshire 185Fixed mistake in logic for decided when we're ready to go to sleep 186 187Revision 1.928 2009/03/17 19:48:12 cheshire 188<rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names 189 190Revision 1.927 2009/03/17 01:22:56 cheshire 191<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests 192Initial support for resolving up to three Sleep Proxies in parallel 193 194Revision 1.926 2009/03/17 01:05:07 mcguire 195<rdar://problem/6657640> Reachability fixes on DNS config change 196 197Revision 1.925 2009/03/13 01:35:36 mcguire 198<rdar://problem/6657640> Reachability fixes on DNS config change 199 200Revision 1.924 2009/03/10 23:45:20 cheshire 201Added comments explaining usage of SetSPSProxyListChanged() 202 203Revision 1.923 2009/03/09 21:53:02 cheshire 204<rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client 205 206Revision 1.922 2009/03/09 21:30:17 cheshire 207Improved some LogSPS messages; made RestartProbing() subroutine 208 209Revision 1.921 2009/03/06 22:53:31 cheshire 210Don't bother registering with Sleep Proxy if we have no advertised services 211 212Revision 1.920 2009/03/06 20:08:55 cheshire 213<rdar://problem/6601429> Sleep Proxy: Return error responses to clients 214 215Revision 1.919 2009/03/05 21:54:43 cheshire 216Improved "Sleep Proxy Server started / stopped" message 217 218Revision 1.918 2009/03/04 01:37:14 cheshire 219<rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept 220 221Revision 1.917 2009/03/03 23:14:25 cheshire 222Got rid of code duplication by making subroutine "SetupOwnerOpt" 223 224Revision 1.916 2009/03/03 23:04:43 cheshire 225For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC) 226 227Revision 1.915 2009/03/03 22:51:53 cheshire 228<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts 229 230Revision 1.914 2009/03/03 00:46:09 cheshire 231Additional debugging information in ResolveSimultaneousProbe 232 233Revision 1.913 2009/02/27 03:08:47 cheshire 234<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist 235 236Revision 1.912 2009/02/27 02:31:28 cheshire 237Improved "Record not found in list" debugging message 238 239Revision 1.911 2009/02/21 01:42:11 cheshire 240Updated log messages 241 242Revision 1.910 2009/02/19 01:50:53 cheshire 243Converted some LogInfo messages to LogSPS 244 245Revision 1.909 2009/02/14 00:04:59 cheshire 246Left-justify interface names 247 248Revision 1.908 2009/02/13 19:40:07 cheshire 249Improved alignment of LogSPS messages 250 251Revision 1.907 2009/02/13 18:16:05 cheshire 252Fixed some compile warnings 253 254Revision 1.906 2009/02/13 06:10:17 cheshire 255Convert LogOperation messages to LogInfo 256 257Revision 1.905 2009/02/12 20:57:24 cheshire 258Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch 259 260Revision 1.904 2009/02/11 02:37:29 cheshire 261m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled 262Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing, 263so that it happens correctly even when we delay re-sleep due to a very short wakeup. 264 265Revision 1.903 2009/02/09 23:34:31 cheshire 266Additional logging for debugging unknown packets 267 268Revision 1.902 2009/02/07 05:57:01 cheshire 269Fixed debugging log message 270 271Revision 1.901 2009/02/07 02:57:31 cheshire 272<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection 273 274Revision 1.900 2009/02/02 21:29:24 cheshire 275<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast 276If Negative response for our special Microsoft Active Directory "local SOA" check has no 277SOA record in the authority section, assume we should cache the negative result for 24 hours 278 279Revision 1.899 2009/01/31 00:37:50 cheshire 280When marking cache records for deletion in response to a uDNS response, 281make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record) 282 283Revision 1.898 2009/01/30 23:49:20 cheshire 284Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test 285 286Revision 1.897 2009/01/30 22:04:49 cheshire 287Workaround to reduce load on root name servers when caching the SOA record for "." 288 289Revision 1.896 2009/01/30 22:00:05 cheshire 290Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast 291 292Revision 1.895 2009/01/30 17:46:39 cheshire 293Improved debugging messages for working out why spurious name conflicts are happening 294 295Revision 1.894 2009/01/30 00:22:09 cheshire 296<rdar://problem/6540743> No announcement after probing & no conflict notice 297 298Revision 1.893 2009/01/29 22:27:03 mcguire 299<rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450 300 301Revision 1.892 2009/01/24 01:38:23 cheshire 302Fixed error in logic for targeted queries 303 304Revision 1.891 2009/01/22 02:14:25 cheshire 305<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes 306 307Revision 1.890 2009/01/22 00:45:02 cheshire 308Improved SPS debugging log messages; we are eligible to start answering ARP requests 309after we send our first announcement, not after we send our last probe 310 311Revision 1.889 2009/01/21 03:43:56 mcguire 312<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore 313 314Revision 1.888 2009/01/20 00:27:43 mcguire 315<rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it 316 317Revision 1.887 2009/01/17 05:14:37 cheshire 318Convert SendQueries Probe messages to LogSPS messages 319 320Revision 1.886 2009/01/17 03:43:09 cheshire 321Added SPSLogging switch to facilitate Sleep Proxy Server debugging 322 323Revision 1.885 2009/01/16 22:44:18 cheshire 324<rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner 325 326Revision 1.884 2009/01/16 21:43:52 cheshire 327Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter 328 329Revision 1.883 2009/01/16 21:11:18 cheshire 330When purging expired Sleep Proxy records, need to check DuplicateRecords list too 331 332Revision 1.882 2009/01/16 19:54:28 cheshire 333Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings 334 335Revision 1.881 2009/01/14 01:38:38 mcguire 336<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info 337 338Revision 1.880 2009/01/10 01:51:19 cheshire 339q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord 340 341Revision 1.879 2009/01/10 01:43:52 cheshire 342Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ' 343 344Revision 1.878 2009/01/10 01:38:10 cheshire 345Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord' 346 347Revision 1.877 2009/01/10 01:36:08 cheshire 348Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord' 349 350Revision 1.876 2009/01/09 22:56:06 cheshire 351Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd 352 353Revision 1.875 2009/01/09 22:54:46 cheshire 354When tranferring record from DuplicateRecords list to ResourceRecords list, 355need to copy across state of 'Answered Local-Only-Questions' flag 356 357Revision 1.874 2009/01/07 23:07:24 cheshire 358<rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping 359 360Revision 1.873 2008/12/17 00:18:59 mkrochma 361Change some LogMsg to LogOperation before submitting 362 363Revision 1.872 2008/12/12 01:30:40 cheshire 364Update platform-layer BPF filters when we add or remove AddressProxy records 365 366Revision 1.871 2008/12/10 02:25:31 cheshire 367Minor fixes to use of LogClientOperations symbol 368 369Revision 1.870 2008/12/10 02:11:41 cheshire 370ARMv5 compiler doesn't like uncommented stuff after #endif 371 372Revision 1.869 2008/12/05 02:35:24 mcguire 373<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network 374 375Revision 1.868 2008/12/04 21:08:51 mcguire 376<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements 377 378Revision 1.867 2008/11/26 21:19:36 cheshire 379<rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics 380 381Revision 1.866 2008/11/26 20:32:46 cheshire 382<rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name 383Update advertised name when Sleep Proxy "intent" metric changes 384 385Revision 1.865 2008/11/26 19:49:25 cheshire 386Record originally-requested port in sr->NATinfo.IntPort 387 388Revision 1.864 2008/11/26 19:02:37 cheshire 389Don't answer ARP Probes from owner machine as it wakes up and rejoins the network 390 391Revision 1.863 2008/11/26 03:59:03 cheshire 392Wait 30 seconds before starting ARP Announcements 393 394Revision 1.862 2008/11/25 23:43:07 cheshire 395<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397 396Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object 397 398Revision 1.861 2008/11/25 22:46:30 cheshire 399For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta" 400 401Revision 1.860 2008/11/25 05:07:15 cheshire 402<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name 403 404Revision 1.859 2008/11/20 02:07:56 cheshire 405<rdar://problem/6387470> Refresh our NAT mappings on wake from sleep 406 407Revision 1.858 2008/11/20 01:38:36 cheshire 408For consistency with other parts of the code, changed code to only check 409that the first 4 bytes of MAC address are zero, not the whole 6 bytes. 410 411Revision 1.857 2008/11/14 22:55:18 cheshire 412Fixed log messages 413 414Revision 1.856 2008/11/14 21:08:28 cheshire 415Only put owner option in query packet if we have a non-zero MAC address to put 416Only process owner options in received query packets if the MAC address in the option is non-zero 417 418Revision 1.855 2008/11/14 02:29:54 cheshire 419If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list 420 421Revision 1.854 2008/11/14 00:00:53 cheshire 422After client machine wakes up, Sleep Proxy machine need to remove any records 423it was temporarily holding as proxy for that client 424 425Revision 1.853 2008/11/13 19:07:30 cheshire 426Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet 427 428Revision 1.852 2008/11/12 23:23:11 cheshire 429Before waking a host, check to see if it has an SRV record advertising 430a service on the port in question, and if not, don't bother waking it. 431 432Revision 1.851 2008/11/12 01:54:15 cheshire 433<rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records 434It turns out it is beneficial to have the domain on the end, because it allows better name compression 435 436Revision 1.850 2008/11/11 01:56:57 cheshire 437Improved name conflict log messages 438 439Revision 1.849 2008/11/06 23:50:43 cheshire 440Allow plain (non-SYN) ssh data packets to wake sleeping host 441 442Revision 1.848 2008/11/05 02:40:28 mkrochma 443Change mDNS_SetFQDN syslog mesage to debugf 444 445Revision 1.847 2008/11/04 23:06:50 cheshire 446Split RDataBody union definition into RDataBody and RDataBody2, and removed 447SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord 448 449Revision 1.846 2008/11/04 22:21:44 cheshire 450Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord 451 452Revision 1.845 2008/11/03 23:52:05 cheshire 453Improved ARP debugging messages to differentiate ARP Announcements from Requests 454 455Revision 1.844 2008/10/31 23:43:51 cheshire 456Fixed compile error in Posix build 457 458Revision 1.843 2008/10/31 22:55:04 cheshire 459Initial support for structured SPS names 460 461Revision 1.842 2008/10/30 00:12:07 cheshire 462Fixed spin when PutSPSRec fails to put a record because it's too big to fit 463 464Revision 1.841 2008/10/29 23:23:38 cheshire 465Refined cache size reporting to go in steps of 1000 when number is above 1000 466 467Revision 1.840 2008/10/29 21:34:10 cheshire 468Removed some old debugging messages 469 470Revision 1.839 2008/10/29 21:31:32 cheshire 471Five seconds not always enough time for machine to go to sleep -- increased to ten seconds 472 473Revision 1.838 2008/10/28 18:30:37 cheshire 474Added debugging message in mDNSCoreReceiveRawPacket 475 476Revision 1.837 2008/10/24 23:58:05 cheshire 477Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets 478 479Revision 1.836 2008/10/24 23:18:18 cheshire 480If we have a Sleep Proxy Server, don't remove service registrations from the DNS server 481 482Revision 1.835 2008/10/24 23:07:59 cheshire 483Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata) 484 485Revision 1.834 2008/10/24 23:03:24 cheshire 486Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address) 487 488Revision 1.833 2008/10/24 23:01:26 cheshire 489To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets 490 491Revision 1.832 2008/10/24 22:58:24 cheshire 492For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients 493 494Revision 1.831 2008/10/24 22:50:41 cheshire 495When waking SPS client, include interface name in syslog message 496 497Revision 1.830 2008/10/24 20:50:34 cheshire 498Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)" 499 500Revision 1.829 2008/10/23 23:55:57 cheshire 501Fixed some missing "const" declarations 502 503Revision 1.828 2008/10/23 22:25:56 cheshire 504Renamed field "id" to more descriptive "updateid" 505 506Revision 1.827 2008/10/23 03:06:25 cheshire 507Fixed "Waking host" log message 508 509Revision 1.826 2008/10/22 23:21:30 cheshire 510Make sure we have enough bytes before reading into the transport-level header 511 512Revision 1.825 2008/10/22 22:31:53 cheshire 513Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST 514 515Revision 1.824 2008/10/22 20:00:31 cheshire 516If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up 517 518Revision 1.823 2008/10/22 19:55:35 cheshire 519Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache 520 521Revision 1.822 2008/10/22 01:41:39 cheshire 522Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve 523 524Revision 1.821 2008/10/22 01:12:53 cheshire 525Answer ARP Requests for any IP address we're proxying for 526 527Revision 1.820 2008/10/21 01:11:11 cheshire 528Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer 529 530Revision 1.819 2008/10/20 22:16:27 cheshire 531Updated comments; increased cache shedding threshold from 3000 to 4000 532 533Revision 1.818 2008/10/16 22:01:54 cheshire 534Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data" 535 536Revision 1.817 2008/10/16 21:40:49 cheshire 537Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal() 538 539Revision 1.816 2008/10/15 23:12:36 cheshire 540On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address 541 542Revision 1.815 2008/10/15 20:46:38 cheshire 543When transferring records to SPS, include Lease Option 544 545Revision 1.814 2008/10/15 19:51:27 cheshire 546Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu 547 548Revision 1.813 2008/10/15 00:09:23 cheshire 549When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network 550 551Revision 1.812 2008/10/15 00:01:40 cheshire 552When going to sleep, discover and resolve SPS, and if successful, transfer records to it 553 554Revision 1.811 2008/10/14 23:51:57 cheshire 555Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata 556 557Revision 1.810 2008/10/14 21:37:55 cheshire 558Removed unnecessary m->BeSleepProxyServer variable 559 560Revision 1.809 2008/10/10 23:45:48 cheshire 561For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname, 562not a wide-area unicast hostname 563 564Revision 1.808 2008/10/09 18:59:19 cheshire 565Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers 566 567Revision 1.807 2008/10/07 15:56:58 cheshire 568Fixed "unused variable" warnings in non-debug builds 569 570Revision 1.806 2008/10/04 00:53:37 cheshire 571On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers 572 573Revision 1.805 2008/10/03 18:17:28 cheshire 574<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service 575Update advertised Sleep Proxy Server name if user changes computer name 576 577Revision 1.804 2008/10/03 01:26:06 mcguire 578<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records 579Put back Duplicate Record check 580 581Revision 1.803 2008/10/02 23:38:56 mcguire 582<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records 583 584Revision 1.802 2008/10/02 23:13:48 cheshire 585<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service 586Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);" 587 588Revision 1.801 2008/10/02 22:51:04 cheshire 589<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service 590Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service 591 592Revision 1.800 2008/10/02 22:13:15 cheshire 593<rdar://problem/6230680> 100ms delay on shutdown 594Additional refinement: Also need to clear m->SuppressSending 595 596Revision 1.799 2008/09/29 20:12:37 cheshire 597Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ' 598 599Revision 1.798 2008/09/26 19:53:14 cheshire 600Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section 601 602Revision 1.797 2008/09/25 20:40:59 cheshire 603<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list 604In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed 605 606Revision 1.796 2008/09/25 20:17:10 cheshire 607<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list 608Added defensive code to make sure *all* records of a ServiceRecordSet have 609completed deregistering before we pass on the mStatus_MemFree message 610 611Revision 1.795 2008/09/25 00:30:11 cheshire 612<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list 613 614Revision 1.794 2008/09/24 23:48:05 cheshire 615Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; 616it only needs to access the embedded SRV member of the set 617 618Revision 1.793 2008/09/23 04:11:53 cheshire 619<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records 620 621Revision 1.792 2008/09/23 02:30:07 cheshire 622Get rid of PutResourceRecordCappedTTL() 623 624Revision 1.791 2008/09/20 00:34:21 mcguire 625<rdar://problem/6129039> BTMM: Add support for WANPPPConnection 626 627Revision 1.790 2008/09/18 22:46:34 cheshire 628<rdar://problem/6230680> 100ms delay on shutdown 629 630Revision 1.789 2008/09/18 06:15:06 mkrochma 631<rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console 632 633Revision 1.788 2008/09/16 21:11:41 cheshire 634<rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote 635 636Revision 1.787 2008/09/05 22:53:24 cheshire 637Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message 638 639Revision 1.786 2008/09/05 22:23:28 cheshire 640Moved initialization of "question->LocalSocket" to more logical place 641 642Revision 1.785 2008/08/14 19:20:55 cheshire 643<rdar://problem/6143846> Negative responses over TCP incorrectly rejected 644 645Revision 1.784 2008/08/13 00:47:53 mcguire 646Handle failures when packet logging 647 648Revision 1.783 2008/07/25 07:09:51 mcguire 649<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning 650 651Revision 1.782 2008/07/24 20:23:03 cheshire 652<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning 653 654Revision 1.781 2008/07/18 21:37:35 mcguire 655<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast 656 657Revision 1.780 2008/07/18 02:24:36 cheshire 658<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response 659Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates 660we're still on our first or second query after an interface registration or wake from sleep). 661 662Revision 1.779 2008/07/18 01:05:23 cheshire 663<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response 664 665Revision 1.778 2008/06/26 17:24:11 mkrochma 666<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements 667 668Revision 1.777 2008/06/19 01:20:48 mcguire 669<rdar://problem/4206534> Use all configured DNS servers 670 671Revision 1.776 2008/04/17 20:14:14 cheshire 672<rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch 673 674Revision 1.775 2008/03/26 01:53:34 mcguire 675<rdar://problem/5820489> Can't resolve via uDNS when an interface is specified 676 677Revision 1.774 2008/03/17 17:46:08 mcguire 678When activating an LLQ, reset all the important state and destroy any tcp connection, 679so that everything will be restarted as if the question had just been asked. 680Also reset servPort, so that the SOA query will be re-issued. 681 682Revision 1.773 2008/03/14 22:52:36 mcguire 683<rdar://problem/5321824> write status to the DS 684Update status when any unicast LLQ is started 685 686Revision 1.772 2008/03/06 02:48:34 mcguire 687<rdar://problem/5321824> write status to the DS 688 689Revision 1.771 2008/02/26 22:04:44 cheshire 690<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries 691Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a 692question while it's still in our 'm->NewQuestions' section of the list 693 694Revision 1.770 2008/02/22 23:09:02 cheshire 695<rdar://problem/5338420> BTMM: Not processing additional records 696Refinements: 6971. Check rdatahash == namehash, to skip expensive SameDomainName check when possible 6982. Once we decide a record is acceptable, we can break out of the loop 699 700Revision 1.769 2008/02/22 00:00:19 cheshire 701<rdar://problem/5338420> BTMM: Not processing additional records 702 703Revision 1.768 2008/02/19 23:26:50 cheshire 704<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries 705 706Revision 1.767 2007/12/22 02:25:29 cheshire 707<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep 708 709Revision 1.766 2007/12/15 01:12:27 cheshire 710<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown 711 712Revision 1.765 2007/12/15 00:18:51 cheshire 713Renamed question->origLease to question->ReqLease 714 715Revision 1.764 2007/12/14 00:49:53 cheshire 716Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use 717the CurrentServiceRecordSet mechanism to guard against services being deleted, 718just like the record deregistration loop uses m->CurrentRecord. 719 720Revision 1.763 2007/12/13 20:20:17 cheshire 721Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and 722SameRData from functions to macros, which allows the code to be inlined (the compiler can't 723inline a function defined in a different compilation unit) and therefore optimized better. 724 725Revision 1.762 2007/12/13 00:13:03 cheshire 726Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody 727 728Revision 1.761 2007/12/13 00:03:31 cheshire 729Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check 730 731Revision 1.760 2007/12/08 00:36:19 cheshire 732<rdar://problem/5636422> Updating TXT records is too slow 733Remove unnecessary delays on announcing record updates, and on processing them on reception 734 735Revision 1.759 2007/12/07 22:41:29 cheshire 736<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown 737Further refinements -- records on the DuplicateRecords list were getting missed on shutdown 738 739Revision 1.758 2007/12/07 00:45:57 cheshire 740<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown 741 742Revision 1.757 2007/12/06 00:22:27 mcguire 743<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp) 744 745Revision 1.756 2007/12/05 01:52:30 cheshire 746<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname 747Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to) 748 749Revision 1.755 2007/12/03 23:36:45 cheshire 750<rdar://problem/5623140> mDNSResponder unicast DNS improvements 751Need to check GetServerForName() result is non-null before dereferencing pointer 752 753Revision 1.754 2007/12/01 01:21:27 jgraessley 754<rdar://problem/5623140> mDNSResponder unicast DNS improvements 755 756Revision 1.753 2007/12/01 00:44:15 cheshire 757Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local 758 759Revision 1.752 2007/11/14 01:10:51 cheshire 760Fixed LogOperation() message wording 761 762Revision 1.751 2007/10/30 23:49:41 cheshire 763<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep 764LLQ state was not being transferred properly between duplicate questions 765 766Revision 1.750 2007/10/29 23:58:52 cheshire 767<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events 768Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet 769 770Revision 1.749 2007/10/29 21:28:36 cheshire 771Change "Correcting TTL" log message to LogOperation to suppress it in customer build 772 773Revision 1.748 2007/10/29 20:02:50 cheshire 774<rdar://problem/5526813> BTMM: Wide-area records being announced via multicast 775 776Revision 1.747 2007/10/26 22:53:50 cheshire 777Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro 778instead of replicating the logic in both places 779 780Revision 1.746 2007/10/25 22:48:50 cheshire 781Added LogOperation message saying when we restart GetZoneData for record and service registrations 782 783Revision 1.745 2007/10/25 20:48:47 cheshire 784For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer' 785 786Revision 1.744 2007/10/25 20:06:14 cheshire 787Don't try to do SOA queries using private DNS (TLS over TCP) queries 788 789Revision 1.743 2007/10/25 00:12:46 cheshire 790<rdar://problem/5496734> BTMM: Need to retry registrations after failures 791Retrigger service registrations whenever a new network interface is added 792 793Revision 1.742 2007/10/24 22:40:06 cheshire 794Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData 795Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData 796 797Revision 1.741 2007/10/24 00:50:29 cheshire 798<rdar://problem/5496734> BTMM: Need to retry registrations after failures 799Retrigger record registrations whenever a new network interface is added 800 801Revision 1.740 2007/10/23 00:38:03 cheshire 802When sending uDNS cache expiration query, need to increment rr->UnansweredQueries 803or code will spin sending the same cache expiration query repeatedly 804 805Revision 1.739 2007/10/22 23:46:41 cheshire 806<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep 807Need to clear question->nta pointer after calling CancelGetZoneData() 808 809Revision 1.738 2007/10/19 22:08:49 cheshire 810<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep 811Additional fixes and refinements 812 813Revision 1.737 2007/10/18 23:06:42 cheshire 814<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep 815Additional fixes and refinements 816 817Revision 1.736 2007/10/18 20:23:17 cheshire 818Moved SuspendLLQs into mDNS.c, since it's only called from one place 819 820Revision 1.735 2007/10/18 00:12:34 cheshire 821Fixed "unused variable" compiler warning 822 823Revision 1.734 2007/10/17 22:49:54 cheshire 824<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep 825 826Revision 1.733 2007/10/17 22:37:23 cheshire 827<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events 828 829Revision 1.732 2007/10/17 21:53:51 cheshire 830Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData 831 832Revision 1.731 2007/10/17 18:37:50 cheshire 833<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown 834Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal() 835 836Revision 1.730 2007/10/16 21:16:07 cheshire 837<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown 838 839Revision 1.729 2007/10/05 17:56:10 cheshire 840Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files 841 842Revision 1.728 2007/10/04 23:18:14 cheshire 843<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level 844 845Revision 1.727 2007/10/04 22:51:57 cheshire 846Added debugging LogOperation message to show when we're sending cache expiration queries 847 848Revision 1.726 2007/10/03 00:14:24 cheshire 849Removed write to null to generate stack trace for SetNextQueryTime locking failure 850 851Revision 1.725 2007/10/02 21:11:08 cheshire 852<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing 853 854Revision 1.724 2007/10/02 20:10:23 cheshire 855Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one 856 857Revision 1.723 2007/10/02 19:56:54 cheshire 858<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname 859 860Revision 1.722 2007/10/01 22:59:46 cheshire 861<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds 862Need to shut down NATTraversals on exit 863 864Revision 1.721 2007/10/01 18:42:07 cheshire 865To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after 866 867Revision 1.720 2007/09/29 20:40:19 cheshire 868<rdar://problem/5513378> Crash in ReissueBlockedQuestions 869 870Revision 1.719 2007/09/27 22:23:56 cheshire 871<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers 872Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec 873 874Revision 1.718 2007/09/27 22:02:33 cheshire 875<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord 876 877Revision 1.717 2007/09/27 21:21:39 cheshire 878Export CompleteDeregistration so it's callable from other files 879 880Revision 1.716 2007/09/27 02:12:21 cheshire 881Updated GrantCacheExtensions degugging message to show new record lifetime 882 883Revision 1.715 2007/09/27 01:20:06 cheshire 884<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response 885 886Revision 1.714 2007/09/27 00:37:01 cheshire 887<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers 888 889Revision 1.713 2007/09/27 00:25:39 cheshire 890Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for: 891<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers 892 893Revision 1.712 2007/09/26 23:16:58 cheshire 894<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac 895 896Revision 1.711 2007/09/26 22:06:02 cheshire 897<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names 898 899Revision 1.710 2007/09/26 00:49:46 cheshire 900Improve packet logging to show sent and received packets, 901transport protocol (UDP/TCP/TLS) and source/destination address:port 902 903Revision 1.709 2007/09/21 21:12:36 cheshire 904<rdar://problem/5498009> BTMM: Need to log updates and query packet contents 905 906Revision 1.708 2007/09/20 23:13:37 cheshire 907<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network 908Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs) 909 910Revision 1.707 2007/09/20 02:29:37 cheshire 911<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network 912 913Revision 1.706 2007/09/20 01:13:19 cheshire 914Export CacheGroupForName so it's callable from other files 915 916Revision 1.705 2007/09/20 01:12:06 cheshire 917Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files 918 919Revision 1.704 2007/09/19 22:47:25 cheshire 920<rdar://problem/5490182> Memory corruption freeing a "no such service" service record 921 922Revision 1.703 2007/09/14 01:46:59 cheshire 923Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have) 924 925Revision 1.702 2007/09/13 22:06:46 cheshire 926<rdar://problem/5480643> Tully's Free WiFi: DNS fails 927Need to accept DNS responses where the query ID field matches, even if the source address does not 928 929Revision 1.701 2007/09/12 23:22:32 cheshire 930<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway 931 932Revision 1.700 2007/09/12 23:03:08 cheshire 933<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index 934 935Revision 1.699 2007/09/12 22:19:28 cheshire 936<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements 937 938Revision 1.698 2007/09/12 22:13:27 cheshire 939Remove DynDNSHostNames cleanly on shutdown 940 941Revision 1.697 2007/09/12 01:44:47 cheshire 942<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records 943 944Revision 1.696 2007/09/12 01:26:08 cheshire 945Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably 946 947Revision 1.695 2007/09/11 19:19:16 cheshire 948Correct capitalization of "uPNP" to "UPnP" 949 950Revision 1.694 2007/09/10 22:06:51 cheshire 951Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds 952 953Revision 1.693 2007/09/07 22:24:36 vazquez 954<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs 955 956Revision 1.692 2007/09/07 00:12:09 cheshire 957<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456 958 959Revision 1.691 2007/09/05 22:25:01 vazquez 960<rdar://problem/5400521> update_record mDNSResponder leak 961 962Revision 1.690 2007/09/05 21:48:01 cheshire 963<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone. 964Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs 965to update the cache lifetimes of all relevant records every time it successfully renews an LLQ, 966otherwise those records will expire and vanish from the cache. 967 968Revision 1.689 2007/09/05 02:29:06 cheshire 969<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions 970Additional fixes to code implementing "NoAnswer" logic 971 972Revision 1.688 2007/08/31 22:56:39 cheshire 973<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records 974 975Revision 1.687 2007/08/31 19:53:14 cheshire 976<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup 977If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist 978 979Revision 1.686 2007/08/30 00:01:56 cheshire 980Added comment about SetTargetToHostName() 981 982Revision 1.685 2007/08/29 01:19:24 cheshire 983<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings 984Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services 985 986Revision 1.684 2007/08/28 23:58:42 cheshire 987Rename HostTarget -> AutoTarget 988 989Revision 1.683 2007/08/28 23:53:21 cheshire 990Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete 991 992Revision 1.682 2007/08/27 20:28:19 cheshire 993Improve "suspect uDNS response" log message 994 995Revision 1.681 2007/08/24 23:37:23 cheshire 996Added debugging message to show when ExtraResourceRecord callback gets invoked 997 998Revision 1.680 2007/08/24 00:15:19 cheshire 999Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held 1000 1001Revision 1.679 2007/08/23 21:47:09 vazquez 1002<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network 1003make sure we clean up port mappings on base stations by sending a lease value of 0, 1004and only send NAT-PMP packets on private networks; also save some memory by 1005not using packet structs in NATTraversals. 1006 1007Revision 1.678 2007/08/01 16:09:13 cheshire 1008Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly 1009 1010Revision 1.677 2007/08/01 01:58:24 cheshire 1011Added RecordType sanity check in mDNS_Register_internal 1012 1013Revision 1.676 2007/08/01 00:04:13 cheshire 1014<rdar://problem/5261696> Crash in tcpKQSocketCallback 1015Half-open TCP connections were not being cancelled properly 1016 1017Revision 1.675 2007/07/31 02:28:35 vazquez 1018<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot 1019 1020Revision 1.674 2007/07/31 01:57:23 cheshire 1021Adding code to respect TTL received in uDNS responses turned out to 1022expose other problems; backing out change for now. 1023 1024Revision 1.673 2007/07/30 23:31:26 cheshire 1025Code for respecting TTL received in uDNS responses should exclude LLQ-type responses 1026 1027Revision 1.672 2007/07/28 01:25:56 cheshire 1028<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT 1029 1030Revision 1.671 2007/07/27 22:32:54 cheshire 1031When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL 1032of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry). 1033 1034Revision 1.670 2007/07/27 20:54:43 cheshire 1035Fixed code to respect real record TTL received in uDNS responses 1036 1037Revision 1.669 2007/07/27 20:09:32 cheshire 1038Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor 1039 1040Revision 1.668 2007/07/27 19:58:47 cheshire 1041Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse 1042 1043Revision 1.667 2007/07/27 19:52:10 cheshire 1044Don't increment m->rrcache_active for no-cache add events 1045 1046Revision 1.666 2007/07/27 19:30:39 cheshire 1047Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, 1048to properly reflect tri-state nature of the possible responses 1049 1050Revision 1.665 2007/07/27 18:44:01 cheshire 1051Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord" 1052 1053Revision 1.664 2007/07/27 18:38:56 cheshire 1054Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" 1055 1056Revision 1.663 2007/07/25 03:05:02 vazquez 1057Fixes for: 1058<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow 1059<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow 1060and a myriad of other security problems 1061 1062Revision 1.662 2007/07/24 20:22:46 cheshire 1063Make sure all fields of main mDNS object are initialized correctly 1064 1065Revision 1.661 2007/07/21 00:54:45 cheshire 1066<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured 1067 1068Revision 1.660 2007/07/20 20:00:45 cheshire 1069"Legacy Browse" is better called "Automatic Browse" 1070 1071Revision 1.659 2007/07/20 00:54:18 cheshire 1072<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings 1073 1074Revision 1.658 2007/07/18 02:28:57 cheshire 1075Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget 1076 1077Revision 1.657 2007/07/18 00:57:10 cheshire 1078<rdar://problem/5303834> Automatically configure IPSec policy when resolving services 1079Only need to call AddNewClientTunnel() for IPv6 addresses 1080 1081Revision 1.656 2007/07/16 23:54:48 cheshire 1082<rdar://problem/5338850> Crash when removing or changing DNS keys 1083 1084Revision 1.655 2007/07/16 20:11:37 vazquez 1085<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite 1086Init LNT stuff and handle SSDP packets 1087 1088Revision 1.654 2007/07/12 23:30:23 cheshire 1089Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog 1090 1091Revision 1.653 2007/07/12 02:51:27 cheshire 1092<rdar://problem/5303834> Automatically configure IPSec policy when resolving services 1093 1094Revision 1.652 2007/07/11 23:43:42 cheshire 1095Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord 1096 1097Revision 1.651 2007/07/11 22:44:40 cheshire 1098<rdar://problem/5328801> SIGHUP should purge the cache 1099 1100Revision 1.650 2007/07/11 21:34:09 cheshire 1101<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings 1102Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName 1103 1104Revision 1.649 2007/07/11 02:52:52 cheshire 1105<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services 1106In uDNS_RegisterService, set HostTarget for AutoTunnel services 1107 1108Revision 1.648 2007/07/09 23:48:12 cheshire 1109Add parentheses around bitwise operation for clarity 1110 1111Revision 1.647 2007/07/06 21:17:55 cheshire 1112Initialize m->retryGetAddr to timenow + 0x78000000; 1113 1114Revision 1.646 2007/07/06 18:55:49 cheshire 1115Initialize m->NextScheduledNATOp 1116 1117Revision 1.645 2007/06/29 22:55:54 cheshire 1118Move declaration of DNSServer *s; Fixed incomplete comment. 1119 1120Revision 1.644 2007/06/29 00:07:29 vazquez 1121<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes) 1122 1123Revision 1.643 2007/06/20 01:10:12 cheshire 1124<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code 1125 1126Revision 1.642 2007/06/15 21:54:50 cheshire 1127<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS 1128 1129Revision 1.641 2007/05/25 00:30:24 cheshire 1130When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not) 1131status matches. This is particularly important when doing a private query for an SOA record, 1132which will result in a call StartGetZoneData which does a non-private query for the same SOA record. 1133If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete. 1134 1135Revision 1.640 2007/05/25 00:25:44 cheshire 1136<rdar://problem/5227737> Need to enhance putRData to output all current known types 1137 1138Revision 1.639 2007/05/23 00:51:33 cheshire 1139Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when 1140each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these 1141days, and there are more services being advertised using DNS-SD, so it makes sense to cache more. 1142 1143Revision 1.638 2007/05/23 00:43:16 cheshire 1144If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet 1145 1146Revision 1.637 2007/05/14 23:53:00 cheshire 1147Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c 1148 1149Revision 1.636 2007/05/10 23:27:15 cheshire 1150Update mDNS_Deregister_internal debugging messages 1151 1152Revision 1.635 2007/05/07 20:43:45 cheshire 1153<rdar://problem/4241419> Reduce the number of queries and announcements 1154 1155Revision 1.634 2007/05/04 22:09:08 cheshire 1156Only do "restarting exponential backoff sequence" for mDNS questions 1157In mDNS_RegisterInterface, only retrigger mDNS questions 1158In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly 1159 1160Revision 1.633 2007/05/04 21:45:12 cheshire 1161Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep) 1162 1163Revision 1.632 2007/05/04 20:20:50 cheshire 1164<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData 1165Need to set srs->nta = mDNSNULL; when regState_NoTarget 1166 1167Revision 1.631 2007/05/04 00:39:42 cheshire 1168<rdar://problem/4410011> Eliminate looping SOA lookups 1169When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated 1170each time round the loop to reference the right CacheGroup for each newly fabricated SOA name 1171 1172Revision 1.630 2007/05/03 22:40:38 cheshire 1173<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record 1174 1175Revision 1.629 2007/05/03 00:15:51 cheshire 1176<rdar://problem/4410011> Eliminate looping SOA lookups 1177 1178Revision 1.628 2007/05/02 22:21:33 cheshire 1179<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData 1180 1181Revision 1.627 2007/04/30 19:29:13 cheshire 1182Fix display of port number in "Updating DNS Server" message 1183 1184Revision 1.626 2007/04/30 04:21:13 cheshire 1185Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time 1186 1187Revision 1.625 2007/04/28 01:34:21 cheshire 1188Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions 1189(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes) 1190 1191Revision 1.624 2007/04/27 21:04:30 cheshire 1192On network configuration change, need to call uDNS_RegisterSearchDomains 1193 1194Revision 1.623 2007/04/27 19:28:01 cheshire 1195Any code that calls StartGetZoneData needs to keep a handle to the structure, so 1196it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop 1197-- it would start a query and then quickly cancel it, and then when 1198StartGetZoneData completed, it had a dangling pointer and crashed.) 1199 1200Revision 1.622 2007/04/26 16:09:22 cheshire 1201mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records 1202 1203Revision 1.621 2007/04/26 15:43:22 cheshire 1204Make sure DNSServer *s is non-null before using value in LogOperation 1205 1206Revision 1.620 2007/04/26 13:11:05 cheshire 1207Fixed crash when logging out of VPN 1208 1209Revision 1.619 2007/04/26 00:35:15 cheshire 1210<rdar://problem/5140339> uDNS: Domain discovery not working over VPN 1211Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server 1212inside the firewall may give answers where a public one gives none, and vice versa.) 1213 1214Revision 1.618 2007/04/25 19:26:01 cheshire 1215m->NextScheduledQuery was getting set too early in SendQueries() 1216Improved "SendQueries didn't send all its queries" debugging message 1217 1218Revision 1.617 2007/04/25 17:48:22 cheshire 1219Update debugging message 1220 1221Revision 1.616 2007/04/25 16:38:32 cheshire 1222If negative cache entry already exists, reactivate it instead of creating a new one 1223 1224Revision 1.615 2007/04/25 02:14:38 cheshire 1225<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query 1226Additional fixes to make LLQs work properly 1227 1228Revision 1.614 2007/04/23 21:52:45 cheshire 1229<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour 1230 1231Revision 1.613 2007/04/23 04:58:20 cheshire 1232<rdar://problem/5072548> Crash when setting extremely large TXT records 1233 1234Revision 1.612 2007/04/22 20:39:38 cheshire 1235<rdar://problem/4633194> Add 20 to 120ms random delay to browses 1236 1237Revision 1.611 2007/04/22 18:16:29 cheshire 1238Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated 1239 1240Revision 1.610 2007/04/22 06:02:02 cheshire 1241<rdar://problem/4615977> Query should immediately return failure when no server 1242 1243Revision 1.609 2007/04/20 21:17:24 cheshire 1244For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative 1245 1246Revision 1.608 2007/04/20 19:45:31 cheshire 1247In LogClientOperations mode, dump out unknown DNS packets in their entirety 1248 1249Revision 1.607 2007/04/19 23:56:25 cheshire 1250Don't do cache-flush processing for LLQ answers 1251 1252Revision 1.606 2007/04/19 22:50:53 cheshire 1253<rdar://problem/4246187> Identical client queries should reference a single shared core query 1254 1255Revision 1.605 2007/04/19 20:06:41 cheshire 1256Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer) 1257 1258Revision 1.604 2007/04/19 18:03:04 cheshire 1259Add "const" declaration 1260 1261Revision 1.603 2007/04/06 21:00:25 cheshire 1262Fix log message typo 1263 1264Revision 1.602 2007/04/05 22:55:35 cheshire 1265<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information 1266 1267Revision 1.601 2007/04/04 21:48:52 cheshire 1268<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list 1269 1270Revision 1.600 2007/04/04 01:31:33 cheshire 1271Improve debugging message 1272 1273Revision 1.599 2007/04/04 00:03:26 cheshire 1274<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata 1275 1276Revision 1.598 2007/04/03 19:43:16 cheshire 1277Use mDNSSameIPPort (and similar) instead of accessing internal fields directly 1278 1279Revision 1.597 2007/03/31 00:32:32 cheshire 1280After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType 1281 1282Revision 1.596 2007/03/28 20:59:26 cheshire 1283<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr() 1284 1285Revision 1.595 2007/03/26 23:48:16 cheshire 1286<rdar://problem/4848295> Advertise model information via Bonjour 1287Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record 1288 1289Revision 1.594 2007/03/26 23:05:05 cheshire 1290<rdar://problem/5089257> Don't cache TSIG records 1291 1292Revision 1.593 2007/03/23 17:40:08 cheshire 1293<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision 1294 1295Revision 1.592 2007/03/22 18:31:48 cheshire 1296Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy 1297 1298Revision 1.591 2007/03/22 00:49:19 cheshire 1299<rdar://problem/4848295> Advertise model information via Bonjour 1300 1301Revision 1.590 2007/03/21 23:05:59 cheshire 1302Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields 1303 1304Revision 1.589 2007/03/20 15:37:19 cheshire 1305Delete unnecessary log message 1306 1307Revision 1.588 2007/03/20 00:24:44 cheshire 1308<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record 1309 1310Revision 1.587 2007/03/16 22:10:56 cheshire 1311<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types 1312 1313Revision 1.586 2007/03/10 03:26:44 cheshire 1314<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache 1315 1316Revision 1.585 2007/03/10 02:02:58 cheshire 1317<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache 1318Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer 1319 1320Revision 1.584 2007/02/28 01:51:27 cheshire 1321Added comment about reverse-order IP address 1322 1323Revision 1.583 2007/01/27 03:19:33 cheshire 1324Need to initialize question->sock 1325 1326Revision 1.582 2007/01/25 00:40:16 cheshire 1327Unified CNAME-following functionality into cache management code (which means CNAME-following 1328should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine. 1329 1330Revision 1.581 2007/01/23 02:56:11 cheshire 1331Store negative results in the cache, instead of generating them out of pktResponseHndlr() 1332 1333Revision 1.580 2007/01/19 21:17:33 cheshire 1334StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion 1335 1336Revision 1.579 2007/01/19 18:39:10 cheshire 1337Fix a bunch of parameters that should have been declared "const" 1338 1339Revision 1.578 2007/01/10 22:51:57 cheshire 1340<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries 1341 1342Revision 1.577 2007/01/10 02:05:21 cheshire 1343Delay uDNS_SetupDNSConfig() until *after* the platform layer 1344has set up the interface list and security credentials 1345 1346Revision 1.576 2007/01/09 02:40:57 cheshire 1347uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer); 1348moved it to mDNS_Init() in mDNS.c (core code) 1349 1350Revision 1.575 2007/01/09 00:17:25 cheshire 1351Improve "ERROR m->CurrentRecord already set" debugging messages 1352 1353Revision 1.574 2007/01/05 08:30:41 cheshire 1354Trim excessive "Log" checkin history from before 2006 1355(checkin history still available via "cvs log ..." of course) 1356 1357Revision 1.573 2007/01/05 06:34:03 cheshire 1358Improve "ERROR m->CurrentQuestion already set" debugging messages 1359 1360Revision 1.572 2007/01/04 23:11:11 cheshire 1361<rdar://problem/4720673> uDNS: Need to start caching unicast records 1362When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries 1363 1364Revision 1.571 2007/01/04 21:45:20 cheshire 1365Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, 1366to do additional lock sanity checking around callback invocations 1367 1368Revision 1.570 2007/01/04 20:57:47 cheshire 1369Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates) 1370 1371Revision 1.569 2007/01/04 20:27:27 cheshire 1372Change a LogMsg() to debugf() 1373 1374Revision 1.568 2007/01/04 02:39:53 cheshire 1375<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations 1376 1377Revision 1.567 2006/12/21 00:01:37 cheshire 1378Tidy up code alignment 1379 1380Revision 1.566 2006/12/20 04:07:34 cheshire 1381Remove uDNS_info substructure from AuthRecord_struct 1382 1383Revision 1.565 2006/12/19 22:49:23 cheshire 1384Remove uDNS_info substructure from ServiceRecordSet_struct 1385 1386Revision 1.564 2006/12/19 02:38:20 cheshire 1387Get rid of unnecessary duplicate query ID field from DNSQuestion_struct 1388 1389Revision 1.563 2006/12/19 02:18:48 cheshire 1390Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct 1391 1392Revision 1.562 2006/12/16 01:58:31 cheshire 1393<rdar://problem/4720673> uDNS: Need to start caching unicast records 1394 1395Revision 1.561 2006/12/01 07:38:53 herscher 1396Only perform cache workaround fix if query is wide-area 1397 1398Revision 1.560 2006/11/30 23:07:56 herscher 1399<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS 1400 1401Revision 1.559 2006/11/27 08:20:57 cheshire 1402Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers 1403 1404Revision 1.558 2006/11/10 07:44:03 herscher 1405<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM 1406 1407Revision 1.557 2006/11/10 01:12:51 cheshire 1408<rdar://problem/4829718> Incorrect TTL corrections 1409 1410Revision 1.556 2006/11/10 00:54:14 cheshire 1411<rdar://problem/4816598> Changing case of Computer Name doesn't work 1412 1413Revision 1.555 2006/10/30 20:03:37 cheshire 1414<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number 1415 1416Revision 1.554 2006/10/20 05:35:04 herscher 1417<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list. 1418 1419Revision 1.553 2006/10/05 03:42:43 herscher 1420Remove embedded uDNS_info struct in DNSQuestion_struct 1421 1422Revision 1.552 2006/09/15 21:20:15 cheshire 1423Remove uDNS_info substructure from mDNS_struct 1424 1425Revision 1.551 2006/08/14 23:24:22 cheshire 1426Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 1427 1428Revision 1.550 2006/07/27 17:58:34 cheshire 1429Improved text of "SendQueries didn't send all its queries; will try again" debugging message 1430 1431Revision 1.549 2006/07/20 22:07:31 mkrochma 1432<rdar://problem/4633196> Wide-area browsing is currently broken in TOT 1433More fixes for uninitialized variables 1434 1435Revision 1.548 2006/07/20 19:30:19 mkrochma 1436<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT 1437 1438Revision 1.547 2006/07/15 02:31:30 cheshire 1439<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs 1440 1441Revision 1.546 2006/07/07 01:09:09 cheshire 1442<rdar://problem/4472013> Add Private DNS server functionality to dnsextd 1443Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd 1444 1445Revision 1.545 2006/07/05 23:10:30 cheshire 1446<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder 1447Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" 1448 1449Revision 1.544 2006/06/29 07:42:14 cheshire 1450<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks 1451 1452Revision 1.543 2006/06/29 01:38:43 cheshire 1453<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection 1454 1455Revision 1.542 2006/06/27 23:40:29 cheshire 1456Fix typo in comment: mis-spelled "compile" 1457 1458Revision 1.541 2006/06/27 19:46:24 cheshire 1459Updated comments and debugging messages 1460 1461Revision 1.540 2006/06/15 21:35:16 cheshire 1462Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants 1463from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code 1464 1465Revision 1.539 2006/06/08 23:45:46 cheshire 1466Change SimultaneousProbe messages from debugf() to LogOperation() 1467 1468Revision 1.538 2006/03/19 17:13:06 cheshire 1469<rdar://problem/4483117> Need faster purging of stale records 1470Shorten kDefaultReconfirmTimeForNoAnswer to five seconds 1471and reconfirm whole chain of antecedents ot once 1472 1473Revision 1.537 2006/03/19 02:00:07 cheshire 1474<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions 1475 1476Revision 1.536 2006/03/08 23:29:53 cheshire 1477<rdar://problem/4468716> Improve "Service Renamed" log message 1478 1479Revision 1.535 2006/03/02 20:41:17 cheshire 1480<rdar://problem/4111464> After record update, old record sometimes remains in cache 1481Minor code tidying and comments to reduce the risk of similar programming errors in future 1482 1483Revision 1.534 2006/03/02 03:25:46 cheshire 1484<rdar://problem/4111464> After record update, old record sometimes remains in cache 1485Code to harmonize RRSet TTLs was inadvertently rescuing expiring records 1486 1487Revision 1.533 2006/02/26 00:54:41 cheshire 1488Fixes to avoid code generation warning/error on FreeBSD 7 1489 1490*/ 1491 1492#include "DNSCommon.h" // Defines general DNS untility routines 1493#include "uDNS.h" // Defines entry points into unicast-specific routines 1494 1495// Disable certain benign warnings with Microsoft compilers 1496#if(defined(_MSC_VER)) 1497 // Disable "conditional expression is constant" warning for debug macros. 1498 // Otherwise, this generates warnings for the perfectly natural construct "while(1)" 1499 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know 1500 #pragma warning(disable:4127) 1501 1502 // Disable "assignment within conditional expression". 1503 // Other compilers understand the convention that if you place the assignment expression within an extra pair 1504 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary. 1505 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal 1506 // to the compiler that the assignment is intentional, we have to just turn this warning off completely. 1507 #pragma warning(disable:4706) 1508#endif 1509 1510// Forward declarations 1511mDNSlocal void BeginSleepProcessing(mDNS *const m); 1512mDNSlocal void RetrySPSRegistrations(mDNS *const m); 1513 1514// *************************************************************************** 1515#if COMPILER_LIKES_PRAGMA_MARK 1516#pragma mark - Program Constants 1517#endif 1518 1519#define NO_HINFO 1 1520 1521mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0; 1522 1523// Any records bigger than this are considered 'large' records 1524#define SmallRecordLimit 1024 1525 1526#define kMaxUpdateCredits 10 1527#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6) 1528 1529mDNSexport const char *const mDNS_DomainTypeNames[] = 1530 { 1531 "b._dns-sd._udp.", // Browse 1532 "db._dns-sd._udp.", // Default Browse 1533 "lb._dns-sd._udp.", // Automatic Browse 1534 "r._dns-sd._udp.", // Registration 1535 "dr._dns-sd._udp." // Default Registration 1536 }; 1537 1538#ifdef UNICAST_DISABLED 1539#define uDNS_IsActiveQuery(q, u) mDNSfalse 1540#endif 1541 1542// *************************************************************************** 1543#if COMPILER_LIKES_PRAGMA_MARK 1544#pragma mark - 1545#pragma mark - General Utility Functions 1546#endif 1547 1548#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf) 1549#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0) 1550 1551mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) 1552 { 1553 if (m->mDNS_busy != m->mDNS_reentrancy+1) 1554 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 1555 1556#if ForceAlerts 1557 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0; 1558#endif 1559 1560 if (ActiveQuestion(q)) 1561 { 1562 mDNSs32 sendtime = q->LastQTime + q->ThisQInterval; 1563 1564 // Don't allow sendtime to be earlier than SuppressStdPort53Queries 1565 if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0)) 1566 sendtime = m->SuppressStdPort53Queries; 1567 1568 if (m->NextScheduledQuery - sendtime > 0) 1569 m->NextScheduledQuery = sendtime; 1570 } 1571 } 1572 1573mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name) 1574 { 1575 CacheGroup *cg; 1576 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) 1577 if (cg->namehash == namehash && SameDomainName(cg->name, name)) 1578 break; 1579 return(cg); 1580 } 1581 1582mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 1583 { 1584 return(CacheGroupForName(m, slot, rr->namehash, rr->name)); 1585 } 1586 1587mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr) 1588 { 1589 NetworkInterfaceInfo *intf; 1590 1591 if (addr->type == mDNSAddrType_IPv4) 1592 { 1593 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception 1594 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); 1595 for (intf = m->HostInterfaces; intf; intf = intf->next) 1596 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 1597 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) 1598 return(mDNStrue); 1599 } 1600 1601 if (addr->type == mDNSAddrType_IPv6) 1602 { 1603 if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); 1604 for (intf = m->HostInterfaces; intf; intf = intf->next) 1605 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) 1606 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && 1607 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) && 1608 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) && 1609 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0)) 1610 return(mDNStrue); 1611 } 1612 1613 return(mDNSfalse); 1614 } 1615 1616mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 1617 { 1618 NetworkInterfaceInfo *intf = m->HostInterfaces; 1619 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; 1620 return(intf); 1621 } 1622 1623mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) 1624 { 1625 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 1626 return(intf ? intf->ifname : "<NULL InterfaceID>"); 1627 } 1628 1629// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord 1630// Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion() 1631mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord) 1632 { 1633 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it 1634 if (AddRecord) rr->AnsweredLocalQ = mDNStrue; 1635 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 1636 if (q->QuestionCallback && !q->NoAnswer) 1637 { 1638 q->CurrentAnswers += AddRecord ? 1 : -1; 1639 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 1640 } 1641 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 1642 } 1643 1644// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though 1645// all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each, 1646// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). 1647// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any. 1648// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal() 1649mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) 1650 { 1651 if (m->CurrentQuestion) 1652 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 1653 1654 m->CurrentQuestion = m->LocalOnlyQuestions; 1655 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) 1656 { 1657 DNSQuestion *q = m->CurrentQuestion; 1658 m->CurrentQuestion = q->next; 1659 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 1660 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again 1661 } 1662 1663 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions 1664 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 1665 { 1666 m->CurrentQuestion = m->Questions; 1667 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 1668 { 1669 DNSQuestion *q = m->CurrentQuestion; 1670 m->CurrentQuestion = q->next; 1671 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 1672 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again 1673 } 1674 } 1675 1676 m->CurrentQuestion = mDNSNULL; 1677 } 1678 1679// *************************************************************************** 1680#if COMPILER_LIKES_PRAGMA_MARK 1681#pragma mark - 1682#pragma mark - Resource Record Utility Functions 1683#endif 1684 1685#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA) 1686 1687#define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \ 1688 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 1689 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \ 1690 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) ) 1691 1692#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \ 1693 (ResourceRecordIsValidAnswer(RR) && \ 1694 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID))) 1695 1696#define DefaultProbeCountForTypeUnique ((mDNSu8)3) 1697#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) 1698 1699#define InitialAnnounceCount ((mDNSu8)8) 1700 1701// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. 1702// This means that because the announce interval is doubled after sending the first packet, the first 1703// observed on-the-wire inter-packet interval between announcements is actually one second. 1704// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent. 1705#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4) 1706#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2) 1707#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2) 1708 1709#define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \ 1710 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \ 1711 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0) 1712 1713#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0) 1714#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR)) 1715#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond) 1716#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR)) 1717 1718#define MaxUnansweredQueries 4 1719 1720// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent 1721// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match). 1722// TTL and rdata may differ. 1723// This is used for cache flush management: 1724// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent 1725// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed 1726 1727// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match 1728 1729#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) 1730 1731mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2) 1732 { 1733 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } 1734 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } 1735 if (r1->resrec.InterfaceID && 1736 r2->resrec.InterfaceID && 1737 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); 1738 return(mDNSBool)( 1739 r1->resrec.rrclass == r2->resrec.rrclass && 1740 r1->resrec.namehash == r2->resrec.namehash && 1741 SameDomainName(r1->resrec.name, r2->resrec.name)); 1742 } 1743 1744// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our 1745// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have 1746// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. 1747// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, 1748// so a response of any type should match, even if it is not actually the type the client plans to use. 1749 1750// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, 1751// and require the rrtypes to match for the rdata to be considered potentially conflicting 1752mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) 1753 { 1754 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } 1755 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); } 1756 if (pktrr->resrec.InterfaceID && 1757 authrr->resrec.InterfaceID && 1758 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); 1759 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) 1760 if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); 1761 return(mDNSBool)( 1762 pktrr->resrec.rrclass == authrr->resrec.rrclass && 1763 pktrr->resrec.namehash == authrr->resrec.namehash && 1764 SameDomainName(pktrr->resrec.name, authrr->resrec.name)); 1765 } 1766 1767// CacheRecord *ka is the CacheRecord from the known answer list in the query. 1768// This is the information that the requester believes to be correct. 1769// AuthRecord *rr is the answer we are proposing to give, if not suppressed. 1770// This is the information that we believe to be correct. 1771// We've already determined that we plan to give this answer on this interface 1772// (either the record is non-specific, or it is specific to this interface) 1773// so now we just need to check the name, type, class, rdata and TTL. 1774mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr) 1775 { 1776 // If RR signature is different, or data is different, then don't suppress our answer 1777 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse); 1778 1779 // If the requester's indicated TTL is less than half the real TTL, 1780 // we need to give our answer before the requester's copy expires. 1781 // If the requester's indicated TTL is at least half the real TTL, 1782 // then we can suppress our answer this time. 1783 // If the requester's indicated TTL is greater than the TTL we believe, 1784 // then that's okay, and we don't need to do anything about it. 1785 // (If two responders on the network are offering the same information, 1786 // that's okay, and if they are offering the information with different TTLs, 1787 // the one offering the lower TTL should defer to the one offering the higher TTL.) 1788 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2); 1789 } 1790 1791mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr) 1792 { 1793 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 1794 { 1795 //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); 1796 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 1797 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); 1798 } 1799 else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr)) 1800 { 1801 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 1802 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 1803 } 1804 } 1805 1806mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) 1807 { 1808 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second 1809 rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); 1810 1811 // To allow us to aggregate probes when a group of services are registered together, 1812 // the first probe is delayed 1/4 second. This means the common-case behaviour is: 1813 // 1/4 second wait; probe 1814 // 1/4 second wait; probe 1815 // 1/4 second wait; probe 1816 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered) 1817 1818 if (rr->ProbeCount) 1819 { 1820 // If we have no probe suppression time set, or it is in the past, set it now 1821 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0) 1822 { 1823 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique); 1824 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation 1825 if (m->SuppressProbes - m->NextScheduledProbe >= 0) 1826 m->SuppressProbes = m->NextScheduledProbe; 1827 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation 1828 if (m->SuppressProbes - m->NextScheduledQuery >= 0) 1829 m->SuppressProbes = m->NextScheduledQuery; 1830 } 1831 } 1832 1833 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; 1834 // Set LastMCTime to now, to inhibit multicast responses 1835 // (no need to send additional multicast responses when we're announcing anyway) 1836 rr->LastMCTime = m->timenow; 1837 rr->LastMCInterface = mDNSInterfaceMark; 1838 1839 // If this is a record type that's not going to probe, then delay its first announcement so that 1840 // it will go out synchronized with the first announcement for the other records that *are* probing. 1841 // This is a minor performance tweak that helps keep groups of related records synchronized together. 1842 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are 1843 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. 1844 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, 1845 // because they will meet the criterion of being at least half-way to their scheduled announcement time. 1846 if (rr->resrec.RecordType != kDNSRecordTypeUnique) 1847 rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; 1848 1849 // The exception is unique records that have already been verified and are just being updated 1850 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay. 1851 if (rr->resrec.RecordType == kDNSRecordTypeVerified) 1852 rr->LastAPTime = m->timenow - rr->ThisAPInterval; 1853 1854 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we 1855 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. 1856 // After three probes one second apart with no answer, we conclude the client is now sleeping 1857 // and we can begin broadcasting our announcements to take over ownership of that IP address. 1858 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk 1859 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. 1860 if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; 1861 1862 // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records 1863 if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) 1864 rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; 1865 1866 SetNextAnnounceProbeTime(m, rr); 1867 } 1868 1869// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname 1870// Eventually we should unify this with GetServiceTarget() in uDNS.c 1871mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) 1872 { 1873 domainname *const target = GetRRDomainNameTarget(&rr->resrec); 1874 const domainname *newname = &m->MulticastHostname; 1875 1876 if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype); 1877 1878 if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage))) 1879 { 1880 const domainname *const n = GetServiceTarget(m, rr); 1881 if (n) newname = n; 1882 } 1883 1884 if (target && SameDomainName(target, newname)) 1885 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); 1886 1887 if (target && !SameDomainName(target, newname)) 1888 { 1889 AssignDomainName(target, newname); 1890 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash 1891 1892 // If we're in the middle of probing this record, we need to start again, 1893 // because changing its rdata may change the outcome of the tie-breaker. 1894 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.) 1895 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 1896 1897 // If we've announced this record, we really should send a goodbye packet for the old rdata before 1898 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, 1899 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. 1900 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) 1901 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", 1902 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1903 1904 rr->AnnounceCount = InitialAnnounceCount; 1905 rr->RequireGoodbye = mDNSfalse; 1906 InitializeLastAPTime(m, rr); 1907 } 1908 } 1909 1910mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) 1911 { 1912 if (rr->RecordCallback) 1913 { 1914 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 1915 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 1916 rr->Acknowledged = mDNStrue; 1917 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 1918 rr->RecordCallback(m, rr, mStatus_NoError); 1919 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 1920 } 1921 } 1922 1923mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr) 1924 { 1925 rr->ProbeCount = 0; 1926 rr->AnnounceCount = 0; 1927 rr->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds 1928 rr->LastAPTime = m->timenow - rr->ThisAPInterval; 1929 rr->state = regState_FetchingZoneData; 1930 rr->uselease = mDNStrue; 1931 } 1932 1933// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified 1934#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ 1935 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified)) 1936#define RecordIsLocalDuplicate(A,B) \ 1937 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) 1938 1939// Exported so uDNS.c can call this 1940mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) 1941 { 1942 domainname *target = GetRRDomainNameTarget(&rr->resrec); 1943 AuthRecord *r; 1944 AuthRecord **p = &m->ResourceRecords; 1945 AuthRecord **d = &m->DuplicateRecords; 1946 1947 if ((mDNSs32)rr->resrec.rroriginalttl <= 0) 1948 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 1949 1950 if (!rr->resrec.RecordType) 1951 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } 1952 1953 if (m->ShutdownTime) 1954 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } 1955 1956 if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) 1957 { 1958 mDNSInterfaceID previousID = rr->resrec.InterfaceID; 1959 if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly; 1960 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 1961 { 1962 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 1963 if (intf && !intf->Advertise) rr->resrec.InterfaceID = mDNSInterface_LocalOnly; 1964 } 1965 if (rr->resrec.InterfaceID != previousID) 1966 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); 1967 } 1968 1969 while (*p && *p != rr) p=&(*p)->next; 1970 while (*d && *d != rr) d=&(*d)->next; 1971 if (*d || *p) 1972 { 1973 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list", 1974 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1975 return(mStatus_AlreadyRegistered); 1976 } 1977 1978 if (rr->DependentOn) 1979 { 1980 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 1981 rr->resrec.RecordType = kDNSRecordTypeVerified; 1982 else 1983 { 1984 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique", 1985 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 1986 return(mStatus_Invalid); 1987 } 1988 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified))) 1989 { 1990 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X", 1991 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType); 1992 return(mStatus_Invalid); 1993 } 1994 } 1995 1996 // If this resource record is referencing a specific interface, make sure it exists 1997 if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 1998 { 1999 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 2000 if (!intf) 2001 { 2002 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); 2003 return(mStatus_BadReferenceErr); 2004 } 2005 } 2006 2007 rr->next = mDNSNULL; 2008 2009 // Field Group 1: The actual information pertaining to this resource record 2010 // Set up by client prior to call 2011 2012 // Field Group 2: Persistent metadata for Authoritative Records 2013// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2014// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2015// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2016// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client 2017// rr->Callback = already set in mDNS_SetupResourceRecord 2018// rr->Context = already set in mDNS_SetupResourceRecord 2019// rr->RecordType = already set in mDNS_SetupResourceRecord 2020// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 2021// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client 2022 // Make sure target is not uninitialized data, or we may crash writing debugging log messages 2023 if (rr->AutoTarget && target) target->c[0] = 0; 2024 2025 // Field Group 3: Transient state for Authoritative Records 2026 rr->Acknowledged = mDNSfalse; 2027 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 2028 rr->AnnounceCount = InitialAnnounceCount; 2029 rr->RequireGoodbye = mDNSfalse; 2030 rr->AnsweredLocalQ = mDNSfalse; 2031 rr->IncludeInProbe = mDNSfalse; 2032 rr->ImmedUnicast = mDNSfalse; 2033 rr->SendNSECNow = mDNSNULL; 2034 rr->ImmedAnswer = mDNSNULL; 2035 rr->ImmedAdditional = mDNSNULL; 2036 rr->SendRNow = mDNSNULL; 2037 rr->v4Requester = zerov4Addr; 2038 rr->v6Requester = zerov6Addr; 2039 rr->NextResponse = mDNSNULL; 2040 rr->NR_AnswerTo = mDNSNULL; 2041 rr->NR_AdditionalTo = mDNSNULL; 2042 if (!rr->AutoTarget) InitializeLastAPTime(m, rr); 2043// rr->LastAPTime = Set for us in InitializeLastAPTime() 2044// rr->LastMCTime = Set for us in InitializeLastAPTime() 2045// rr->LastMCInterface = Set for us in InitializeLastAPTime() 2046 rr->NewRData = mDNSNULL; 2047 rr->newrdlength = 0; 2048 rr->UpdateCallback = mDNSNULL; 2049 rr->UpdateCredits = kMaxUpdateCredits; 2050 rr->NextUpdateCredit = 0; 2051 rr->UpdateBlocked = 0; 2052 2053 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient 2054 if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; 2055 2056 // Field Group 4: Transient uDNS state for Authoritative Records 2057 rr->state = regState_Zero; 2058 rr->uselease = 0; 2059 rr->expire = 0; 2060 rr->Private = 0; 2061 rr->updateid = zeroID; 2062 rr->zone = rr->resrec.name; 2063 rr->UpdateServer = zeroAddr; 2064 rr->UpdatePort = zeroIPPort; 2065 rr->nta = mDNSNULL; 2066 rr->tcp = mDNSNULL; 2067 rr->OrigRData = 0; 2068 rr->OrigRDLen = 0; 2069 rr->InFlightRData = 0; 2070 rr->InFlightRDLen = 0; 2071 rr->QueuedRData = 0; 2072 rr->QueuedRDLen = 0; 2073 2074// rr->resrec.interface = already set in mDNS_SetupResourceRecord 2075// rr->resrec.name->c = MUST be set by client 2076// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord 2077// rr->resrec.rrclass = already set in mDNS_SetupResourceRecord 2078// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord 2079// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set 2080 2081 if (rr->AutoTarget) 2082 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); 2083 else 2084 { 2085 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); 2086 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); 2087 } 2088 2089 if (!ValidateDomainName(rr->resrec.name)) 2090 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 2091 2092 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 2093 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 2094 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 2095 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; } 2096 2097 // Don't do this until *after* we've set rr->resrec.rdlength 2098 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) 2099 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); } 2100 2101 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); 2102 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec); 2103 2104 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 2105 { 2106 // If this is supposed to be unique, make sure we don't have any name conflicts 2107 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2108 { 2109 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr; 2110 for (r = m->ResourceRecords; r; r=r->next) 2111 { 2112 const AuthRecord *s2 = r->RRSet ? r->RRSet : r; 2113 if (s1 != s2 && SameResourceRecordSignature(r, rr) && !IdenticalSameNameRecord(&r->resrec, &rr->resrec)) 2114 break; 2115 } 2116 if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback 2117 { 2118 debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2119 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 2120 rr->resrec.rroriginalttl = 0; 2121 rr->ImmedAnswer = mDNSInterfaceMark; 2122 m->NextScheduledResponse = m->timenow; 2123 } 2124 } 2125 } 2126 2127 // Now that we've finished building our new record, make sure it's not identical to one we already have 2128 for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break; 2129 2130 if (r) 2131 { 2132 debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr)); 2133 *d = rr; 2134 // If the previous copy of this record is already verified unique, 2135 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state. 2136 // Setting ProbeCount to zero will cause SendQueries() to advance this record to 2137 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time. 2138 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified) 2139 rr->ProbeCount = 0; 2140 } 2141 else 2142 { 2143 debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr)); 2144 if (!m->NewLocalRecords) m->NewLocalRecords = rr; 2145 *p = rr; 2146 } 2147 2148 if (!AuthRecord_uDNS(rr)) 2149 { 2150 // For records that are not going to probe, acknowledge them right away 2151 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) 2152 AcknowledgeRecord(m, rr); 2153 } 2154#ifndef UNICAST_DISABLED 2155 else 2156 { 2157 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; 2158 ActivateUnicastRegistration(m, rr); 2159 } 2160#endif 2161 2162 return(mStatus_NoError); 2163 } 2164 2165mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr) 2166 { 2167 m->ProbeFailTime = m->timenow; 2168 m->NumFailedProbes++; 2169 // If we've had fifteen or more probe failures, rate-limit to one every five seconds. 2170 // If a bunch of hosts have all been configured with the same name, then they'll all 2171 // conflict and run through the same series of names: name-2, name-3, name-4, etc., 2172 // up to name-10. After that they'll start adding random increments in the range 1-100, 2173 // so they're more likely to branch out in the available namespace and settle on a set of 2174 // unique names quickly. If after five more tries the host is still conflicting, then we 2175 // may have a serious problem, so we start rate-limiting so we don't melt down the network. 2176 if (m->NumFailedProbes >= 15) 2177 { 2178 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 2179 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect", 2180 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2181 } 2182 } 2183 2184mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) 2185 { 2186 RData *OldRData = rr->resrec.rdata; 2187 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata 2188 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 2189 if (rr->UpdateCallback) 2190 rr->UpdateCallback(m, rr, OldRData); // ... and let the client know 2191 } 2192 2193// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. 2194// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 2195// Exported so uDNS.c can call this 2196mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) 2197 { 2198 AuthRecord *r2; 2199 mDNSu8 RecordType = rr->resrec.RecordType; 2200 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records 2201 2202 while (*p && *p != rr) p=&(*p)->next; 2203 2204 if (*p) 2205 { 2206 // We found our record on the main list. See if there are any duplicates that need special handling. 2207 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment 2208 { 2209 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished 2210 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. 2211 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; 2212 } 2213 else 2214 { 2215 // Before we delete the record (and potentially send a goodbye packet) 2216 // first see if we have a record on the duplicate list ready to take over from it. 2217 AuthRecord **d = &m->DuplicateRecords; 2218 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next; 2219 if (*d) 2220 { 2221 AuthRecord *dup = *d; 2222 debugf("Duplicate record %p taking over from %p %##s (%s)", 2223 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2224 *d = dup->next; // Cut replacement record from DuplicateRecords list 2225 dup->next = rr->next; // And then... 2226 rr->next = dup; // ... splice it in right after the record we're about to delete 2227 dup->resrec.RecordType = rr->resrec.RecordType; 2228 dup->ProbeCount = rr->ProbeCount; 2229 dup->AnnounceCount = rr->AnnounceCount; 2230 dup->RequireGoodbye = rr->RequireGoodbye; 2231 dup->AnsweredLocalQ = rr->AnsweredLocalQ; 2232 dup->ImmedAnswer = rr->ImmedAnswer; 2233 dup->ImmedUnicast = rr->ImmedUnicast; 2234 dup->ImmedAdditional = rr->ImmedAdditional; 2235 dup->v4Requester = rr->v4Requester; 2236 dup->v6Requester = rr->v6Requester; 2237 dup->ThisAPInterval = rr->ThisAPInterval; 2238 dup->LastAPTime = rr->LastAPTime; 2239 dup->LastMCTime = rr->LastMCTime; 2240 dup->LastMCInterface = rr->LastMCInterface; 2241 dup->UpdateServer = rr->UpdateServer; 2242 dup->UpdatePort = rr->UpdatePort; 2243 dup->Private = rr->Private; 2244 dup->state = rr->state; 2245 rr->RequireGoodbye = mDNSfalse; 2246 rr->AnsweredLocalQ = mDNSfalse; 2247 } 2248 } 2249 } 2250 else 2251 { 2252 // We didn't find our record on the main list; try the DuplicateRecords list instead. 2253 p = &m->DuplicateRecords; 2254 while (*p && *p != rr) p=&(*p)->next; 2255 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it 2256 if (*p) rr->RequireGoodbye = mDNSfalse; 2257 if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", 2258 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2259 } 2260 2261 if (!*p) 2262 { 2263 // No need to log an error message if we already know this is a potentially repeated deregistration 2264 if (drt != mDNS_Dereg_repeat) 2265 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr)); 2266 return(mStatus_BadReferenceErr); 2267 } 2268 2269 // If this is a shared record and we've announced it at least once, 2270 // we need to retract that announcement before we delete the record 2271 2272 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then 2273 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. 2274 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" 2275 // mechanism to cope with the client callback modifying the question list while that's happening. 2276 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) 2277 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. 2278 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other 2279 // records, thereby invoking yet more callbacks, without limit. 2280 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending 2281 // actual goodbye packets. 2282 2283#ifndef UNICAST_DISABLED 2284 if (AuthRecord_uDNS(rr) && rr->RequireGoodbye) 2285 { 2286 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 2287 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 2288 uDNS_DeregisterRecord(m, rr); 2289 // At this point unconditionally we bail out 2290 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, 2291 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration 2292 // process and will complete asynchronously. Either way we don't need to do anything more here. 2293 return(mStatus_NoError); 2294 } 2295#endif // UNICAST_DISABLED 2296 2297 if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)) 2298 { 2299 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr)); 2300 rr->resrec.RecordType = kDNSRecordTypeDeregistering; 2301 rr->resrec.rroriginalttl = 0; 2302 rr->ImmedAnswer = mDNSInterfaceMark; 2303 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0) 2304 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10); 2305 } 2306 else 2307 { 2308 *p = rr->next; // Cut this record from the list 2309 // If someone is about to look at this, bump the pointer forward 2310 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; 2311 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; 2312 rr->next = mDNSNULL; 2313 2314 if (RecordType == kDNSRecordTypeUnregistered) 2315 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); 2316 else if (RecordType == kDNSRecordTypeDeregistering) 2317 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); 2318 else 2319 { 2320 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); 2321 rr->resrec.RecordType = kDNSRecordTypeUnregistered; 2322 } 2323 2324 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared) 2325 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)", 2326 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2327 2328 // If we have an update queued up which never executed, give the client a chance to free that memory 2329 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 2330 2331 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } 2332 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } 2333 2334 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function 2335 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. 2336 // In this case the likely client action to the mStatus_MemFree message is to free the memory, 2337 // so any attempt to touch rr after this is likely to lead to a crash. 2338 if (drt != mDNS_Dereg_conflict) 2339 { 2340 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 2341 if (rr->RecordCallback) 2342 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this 2343 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 2344 } 2345 else 2346 { 2347 RecordProbeFailure(m, rr); 2348 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 2349 if (rr->RecordCallback) 2350 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this 2351 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 2352 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. 2353 // Note that with all the client callbacks going on, by the time we get here all the 2354 // records we marked may have been explicitly deregistered by the client anyway. 2355 r2 = m->DuplicateRecords; 2356 while (r2) 2357 { 2358 if (r2->ProbeCount != 0xFF) r2 = r2->next; 2359 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } 2360 } 2361 } 2362 } 2363 return(mStatus_NoError); 2364 } 2365 2366// *************************************************************************** 2367#if COMPILER_LIKES_PRAGMA_MARK 2368#pragma mark - 2369#pragma mark - Packet Sending Functions 2370#endif 2371 2372mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add) 2373 { 2374 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse) 2375 { 2376 **nrpp = rr; 2377 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo) 2378 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does 2379 // The referenced record will definitely be acceptable (by recursive application of this rule) 2380 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo; 2381 rr->NR_AdditionalTo = add; 2382 *nrpp = &rr->NextResponse; 2383 } 2384 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 2385 } 2386 2387mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID) 2388 { 2389 AuthRecord *rr, *rr2; 2390 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put 2391 { 2392 // (Note: This is an "if", not a "while". If we add a record, we'll find it again 2393 // later in the "for" loop, and we will follow further "additional" links then.) 2394 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID)) 2395 AddRecordToResponseList(nrpp, rr->Additional1, rr); 2396 2397 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) 2398 AddRecordToResponseList(nrpp, rr->Additional2, rr); 2399 2400 // For SRV records, automatically add the Address record(s) for the target host 2401 if (rr->resrec.rrtype == kDNSType_SRV) 2402 { 2403 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 2404 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 2405 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 2406 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target 2407 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) 2408 AddRecordToResponseList(nrpp, rr2, rr); 2409 } 2410 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional 2411 { 2412 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records 2413 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... 2414 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... 2415 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name 2416 SameDomainName(rr->resrec.name, rr2->resrec.name)) 2417 AddRecordToResponseList(nrpp, rr2, rr); 2418 } 2419 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record 2420 { 2421 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && 2422 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) 2423 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); 2424 } 2425 } 2426 } 2427 2428mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID) 2429 { 2430 AuthRecord *rr; 2431 AuthRecord *ResponseRecords = mDNSNULL; 2432 AuthRecord **nrp = &ResponseRecords; 2433 2434 // Make a list of all our records that need to be unicast to this destination 2435 for (rr = m->ResourceRecords; rr; rr=rr->next) 2436 { 2437 // If we find we can no longer unicast this answer, clear ImmedUnicast 2438 if (rr->ImmedAnswer == mDNSInterfaceMark || 2439 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) || 2440 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) ) 2441 rr->ImmedUnicast = mDNSfalse; 2442 2443 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID) 2444 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) || 2445 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6))) 2446 { 2447 rr->ImmedAnswer = mDNSNULL; // Clear the state fields 2448 rr->ImmedUnicast = mDNSfalse; 2449 rr->v4Requester = zerov4Addr; 2450 rr->v6Requester = zerov6Addr; 2451 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo 2452 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; } 2453 } 2454 } 2455 2456 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 2457 2458 while (ResponseRecords) 2459 { 2460 mDNSu8 *responseptr = m->omsg.data; 2461 mDNSu8 *newptr; 2462 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 2463 2464 // Put answers in the packet 2465 while (ResponseRecords && ResponseRecords->NR_AnswerTo) 2466 { 2467 rr = ResponseRecords; 2468 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2469 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2470 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); 2471 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2472 if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now 2473 if (newptr) responseptr = newptr; 2474 ResponseRecords = rr->NextResponse; 2475 rr->NextResponse = mDNSNULL; 2476 rr->NR_AnswerTo = mDNSNULL; 2477 rr->NR_AdditionalTo = mDNSNULL; 2478 rr->RequireGoodbye = mDNStrue; 2479 } 2480 2481 // Add additionals, if there's space 2482 while (ResponseRecords && !ResponseRecords->NR_AnswerTo) 2483 { 2484 rr = ResponseRecords; 2485 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2486 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2487 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec); 2488 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2489 2490 if (newptr) responseptr = newptr; 2491 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue; 2492 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark; 2493 ResponseRecords = rr->NextResponse; 2494 rr->NextResponse = mDNSNULL; 2495 rr->NR_AnswerTo = mDNSNULL; 2496 rr->NR_AdditionalTo = mDNSNULL; 2497 } 2498 2499 if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL); 2500 } 2501 } 2502 2503mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) 2504 { 2505 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that 2506 // it should go ahead and immediately dispose of this registration 2507 rr->resrec.RecordType = kDNSRecordTypeShared; 2508 rr->RequireGoodbye = mDNSfalse; 2509 if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } 2510 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this 2511 } 2512 2513// Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change 2514// the record list and/or question list. 2515// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 2516mDNSlocal void DiscardDeregistrations(mDNS *const m) 2517 { 2518 if (m->CurrentRecord) 2519 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 2520 m->CurrentRecord = m->ResourceRecords; 2521 2522 while (m->CurrentRecord) 2523 { 2524 AuthRecord *rr = m->CurrentRecord; 2525 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 2526 CompleteDeregistration(m, rr); // Don't touch rr after this 2527 else 2528 m->CurrentRecord = rr->next; 2529 } 2530 } 2531 2532mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst) 2533 { 2534 int i, val = 0; 2535 if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid); 2536 for (i=1; i<=src[0]; i++) 2537 { 2538 if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid); 2539 val = val * 10 + src[i] - '0'; 2540 } 2541 if (val > 255) return(mStatus_Invalid); 2542 *dst = val; 2543 return(mStatus_NoError); 2544 } 2545 2546mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name) 2547 { 2548 int skip = CountLabels(name) - 6; 2549 if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; } 2550 if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) || 2551 GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) || 2552 GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) || 2553 GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid; 2554 a->type = mDNSAddrType_IPv4; 2555 return(mStatus_NoError); 2556 } 2557 2558#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \ 2559 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \ 2560 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1) 2561 2562mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name) 2563 { 2564 int i, h, l; 2565 const domainname *n; 2566 2567 int skip = CountLabels(name) - 34; 2568 if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; } 2569 2570 n = SkipLeadingLabels(name, skip); 2571 for (i=0; i<16; i++) 2572 { 2573 if (n->c[0] != 1) return mStatus_Invalid; 2574 l = HexVal(n->c[1]); 2575 n = (const domainname *)(n->c + 2); 2576 2577 if (n->c[0] != 1) return mStatus_Invalid; 2578 h = HexVal(n->c[1]); 2579 n = (const domainname *)(n->c + 2); 2580 2581 if (l<0 || h<0) return mStatus_Invalid; 2582 a->ip.v6.b[15-i] = (h << 4) | l; 2583 } 2584 2585 a->type = mDNSAddrType_IPv6; 2586 return(mStatus_NoError); 2587 } 2588 2589mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name) 2590 { 2591 int skip = CountLabels(name) - 2; 2592 if (skip >= 0) 2593 { 2594 const domainname *suffix = SkipLeadingLabels(name, skip); 2595 if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4; 2596 if (SameDomainName(suffix, (const domainname*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6; 2597 } 2598 return(mDNSAddrType_None); 2599 } 2600 2601mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr, 2602 const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst) 2603 { 2604 int i; 2605 mDNSu8 *ptr = m->omsg.data; 2606 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); 2607 if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; } 2608 2609 // 0x00 Destination address 2610 for (i=0; i<6; i++) *ptr++ = dst[i]; 2611 2612 // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address) 2613 for (i=0; i<6; i++) *ptr++ = 0x0; 2614 2615 // 0x0C ARP Ethertype (0x0806) 2616 *ptr++ = 0x08; *ptr++ = 0x06; 2617 2618 // 0x0E ARP header 2619 *ptr++ = 0x00; *ptr++ = 0x01; // Hardware address space; Ethernet = 1 2620 *ptr++ = 0x08; *ptr++ = 0x00; // Protocol address space; IP = 0x0800 2621 *ptr++ = 6; // Hardware address length 2622 *ptr++ = 4; // Protocol address length 2623 *ptr++ = 0x00; *ptr++ = op; // opcode; Request = 1, Response = 2 2624 2625 // 0x16 Sender hardware address (our MAC address) 2626 for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i]; 2627 2628 // 0x1C Sender protocol address 2629 for (i=0; i<4; i++) *ptr++ = spa[i]; 2630 2631 // 0x20 Target hardware address 2632 for (i=0; i<6; i++) *ptr++ = tha[i]; 2633 2634 // 0x26 Target protocol address 2635 for (i=0; i<4; i++) *ptr++ = tpa[i]; 2636 2637 // 0x2A Total ARP Packet length 42 bytes 2638 mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID); 2639 } 2640 2641mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner) 2642 { 2643 owner->u.owner.vers = 0; 2644 owner->u.owner.seq = m->SleepSeqNum; 2645 owner->u.owner.HMAC = m->PrimaryMAC; 2646 owner->u.owner.IMAC = intf->MAC; 2647 owner->u.owner.password = zeroEthAddr; 2648 2649 // Don't try to compute the optlen until *after* we've set up the data fields 2650 owner->opt = kDNSOpt_Owner; 2651 owner->optlen = DNSOpt_Owner_Space(owner) - 4; 2652 } 2653 2654mDNSlocal void GrantUpdateCredit(AuthRecord *rr) 2655 { 2656 if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; 2657 else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval); 2658 } 2659 2660// Note about acceleration of announcements to facilitate automatic coalescing of 2661// multiple independent threads of announcements into a single synchronized thread: 2662// The announcements in the packet may be at different stages of maturity; 2663// One-second interval, two-second interval, four-second interval, and so on. 2664// After we've put in all the announcements that are due, we then consider 2665// whether there are other nearly-due announcements that are worth accelerating. 2666// To be eligible for acceleration, a record MUST NOT be older (further along 2667// its timeline) than the most mature record we've already put in the packet. 2668// In other words, younger records can have their timelines accelerated to catch up 2669// with their elder bretheren; this narrows the age gap and helps them eventually get in sync. 2670// Older records cannot have their timelines accelerated; this would just widen 2671// the gap between them and their younger bretheren and get them even more out of sync. 2672 2673// Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change 2674// the record list and/or question list. 2675// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 2676mDNSlocal void SendResponses(mDNS *const m) 2677 { 2678 int pktcount = 0; 2679 AuthRecord *rr, *r2; 2680 mDNSs32 maxExistingAnnounceInterval = 0; 2681 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 2682 2683 m->NextScheduledResponse = m->timenow + 0x78000000; 2684 2685 if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m); 2686 2687 for (rr = m->ResourceRecords; rr; rr=rr->next) 2688 if (rr->ImmedUnicast) 2689 { 2690 mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} }; 2691 mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} }; 2692 v4.ip.v4 = rr->v4Requester; 2693 v6.ip.v6 = rr->v6Requester; 2694 if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer); 2695 if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer); 2696 if (rr->ImmedUnicast) 2697 { 2698 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr)); 2699 rr->ImmedUnicast = mDNSfalse; 2700 } 2701 } 2702 2703 // *** 2704 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on 2705 // *** 2706 2707 // Run through our list of records, and decide which ones we're going to announce on all interfaces 2708 for (rr = m->ResourceRecords; rr; rr=rr->next) 2709 { 2710 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 2711 if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr)) 2712 { 2713 if (rr->AddressProxy.type) 2714 { 2715 rr->AnnounceCount--; 2716 rr->ThisAPInterval *= 2; 2717 rr->LastAPTime = m->timenow; 2718 if (rr->AddressProxy.type == mDNSAddrType_IPv4) 2719 { 2720 LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr)); 2721 SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); 2722 } 2723 else if (rr->AddressProxy.type == mDNSAddrType_IPv6) 2724 { 2725 //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr)); 2726 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); 2727 } 2728 } 2729 else 2730 { 2731 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 2732 if (maxExistingAnnounceInterval < rr->ThisAPInterval) 2733 maxExistingAnnounceInterval = rr->ThisAPInterval; 2734 if (rr->UpdateBlocked) rr->UpdateBlocked = 0; 2735 } 2736 } 2737 } 2738 2739 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one) 2740 // Eligible records that are more than half-way to their announcement time are accelerated 2741 for (rr = m->ResourceRecords; rr; rr=rr->next) 2742 if ((rr->resrec.InterfaceID && rr->ImmedAnswer) || 2743 (rr->ThisAPInterval <= maxExistingAnnounceInterval && 2744 TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) && 2745 !rr->AddressProxy.type && // Don't include ARP Annoucements when considering which records to accelerate 2746 ResourceRecordIsValidAnswer(rr))) 2747 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces 2748 2749 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals 2750 // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID, 2751 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen) 2752 // then all that means is that it won't get sent -- which would not be the end of the world. 2753 for (rr = m->ResourceRecords; rr; rr=rr->next) 2754 { 2755 if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV) 2756 for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records 2757 if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ... 2758 ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ... 2759 rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ... 2760 rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target 2761 SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) && 2762 (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID)) 2763 r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too 2764 // We also make sure we send the DeviceInfo TXT record too, if necessary 2765 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the 2766 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering). 2767 if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR) 2768 if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) 2769 { 2770 if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer; 2771 else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark; 2772 } 2773 } 2774 2775 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give 2776 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class 2777 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a 2778 // record, then other RRSet members that have not been sent recently will get flushed out of client caches. 2779 // -- 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 2780 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces 2781 for (rr = m->ResourceRecords; rr; rr=rr->next) 2782 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2783 { 2784 if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked 2785 { 2786 for (r2 = m->ResourceRecords; r2; r2=r2->next) 2787 if (ResourceRecordIsValidAnswer(r2)) 2788 if (r2->ImmedAnswer != mDNSInterfaceMark && 2789 r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr)) 2790 r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark; 2791 } 2792 else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked 2793 { 2794 for (r2 = m->ResourceRecords; r2; r2=r2->next) 2795 if (ResourceRecordIsValidAnswer(r2)) 2796 if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr)) 2797 r2->ImmedAdditional = rr->ImmedAdditional; 2798 } 2799 } 2800 2801 // Now set SendRNow state appropriately 2802 for (rr = m->ResourceRecords; rr; rr=rr->next) 2803 { 2804 if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces 2805 { 2806 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID; 2807 rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer 2808 rr->LastMCTime = m->timenow; 2809 rr->LastMCInterface = rr->ImmedAnswer; 2810 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done 2811 if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2)) 2812 { 2813 rr->AnnounceCount--; 2814 rr->ThisAPInterval *= 2; 2815 rr->LastAPTime = m->timenow; 2816 debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount); 2817 } 2818 } 2819 else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface: 2820 { 2821 rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface 2822 rr->ImmedAdditional = mDNSNULL; // No need to send as additional too 2823 rr->LastMCTime = m->timenow; 2824 rr->LastMCInterface = rr->ImmedAnswer; 2825 } 2826 SetNextAnnounceProbeTime(m, rr); 2827 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr)); 2828 } 2829 2830 // *** 2831 // *** 2. Loop through interface list, sending records as appropriate 2832 // *** 2833 2834 while (intf) 2835 { 2836 int numDereg = 0; 2837 int numAnnounce = 0; 2838 int numAnswer = 0; 2839 mDNSu8 *responseptr = m->omsg.data; 2840 mDNSu8 *newptr; 2841 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags); 2842 2843 // First Pass. Look for: 2844 // 1. Deregistering records that need to send their goodbye packet 2845 // 2. Updated records that need to retract their old data 2846 // 3. Answers and announcements we need to send 2847 for (rr = m->ResourceRecords; rr; rr=rr->next) 2848 { 2849 if (rr->SendRNow == intf->InterfaceID) 2850 { 2851 newptr = mDNSNULL; 2852 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 2853 { 2854 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 2855 if (newptr) { responseptr = newptr; numDereg++; } 2856 } 2857 else if (rr->NewRData && !m->SleepState) // If we have new data for this record 2858 { 2859 RData *OldRData = rr->resrec.rdata; 2860 mDNSu16 oldrdlength = rr->resrec.rdlength; 2861 // See if we should send a courtesy "goodbye" for the old data before we replace it. 2862 if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye) 2863 { 2864 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 2865 if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; } 2866 } 2867 // Now try to see if we can fit the update in the same packet (not fatal if we can't) 2868 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); 2869 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2870 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2871 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec); 2872 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2873 if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; } 2874 SetNewRData(&rr->resrec, OldRData, oldrdlength); 2875 } 2876 else 2877 { 2878 mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type); 2879 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2880 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2881 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0); 2882 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2883 if (newptr) 2884 { 2885 responseptr = newptr; 2886 rr->RequireGoodbye = active; 2887 if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; 2888 } 2889 2890 // The first time through (pktcount==0), if this record is verified unique 2891 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too. 2892 if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1; 2893 } 2894 2895 if (newptr) // If succeeded in sending, advance to next interface 2896 { 2897 // If sending on all interfaces, go to next interface; else we're finished now 2898 if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) 2899 rr->SendRNow = GetNextActiveInterfaceID(intf); 2900 else 2901 rr->SendRNow = mDNSNULL; 2902 } 2903 } 2904 } 2905 2906 // Second Pass. Add additional records, if there's space. 2907 newptr = responseptr; 2908 for (rr = m->ResourceRecords; rr; rr=rr->next) 2909 if (rr->ImmedAdditional == intf->InterfaceID) 2910 if (ResourceRecordIsValidAnswer(rr)) 2911 { 2912 // If we have at least one answer already in the packet, then plan to add additionals too 2913 mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0); 2914 2915 // If we're not planning to send any additionals, but this record is a unique one, then 2916 // make sure we haven't already sent any other members of its RRSet -- if we have, then they 2917 // will have had the cache flush bit set, so now we need to finish the job and send the rest. 2918 if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)) 2919 { 2920 const AuthRecord *a; 2921 for (a = m->ResourceRecords; a; a=a->next) 2922 if (a->LastMCTime == m->timenow && 2923 a->LastMCInterface == intf->InterfaceID && 2924 SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; } 2925 } 2926 if (!SendAdditional) // If we don't want to send this after all, 2927 rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field 2928 else if (newptr) // Else, try to add it if we can 2929 { 2930 // The first time through (pktcount==0), if this record is verified unique 2931 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too. 2932 if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1; 2933 2934 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 2935 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it 2936 newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec); 2937 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state 2938 if (newptr) 2939 { 2940 responseptr = newptr; 2941 rr->ImmedAdditional = mDNSNULL; 2942 rr->RequireGoodbye = mDNStrue; 2943 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface. 2944 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise, 2945 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get 2946 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches. 2947 rr->LastMCTime = m->timenow; 2948 rr->LastMCInterface = intf->InterfaceID; 2949 } 2950 } 2951 } 2952 2953 // Third Pass. Add NSEC records, if there's space. 2954 for (rr = m->ResourceRecords; rr; rr=rr->next) 2955 if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID) 2956 { 2957 AuthRecord nsec; 2958 mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL); 2959 nsec.resrec.rrclass |= kDNSClass_UniqueRRSet; 2960 AssignDomainName(&nsec.namestorage, rr->resrec.name); 2961 mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap)); 2962 for (r2 = m->ResourceRecords; r2; r2=r2->next) 2963 if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr)) 2964 { 2965 if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; } 2966 else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7); 2967 } 2968 newptr = responseptr; 2969 if (!r2) // If we successfully built our NSEC record, add it to the packet now 2970 { 2971 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec); 2972 if (newptr) responseptr = newptr; 2973 } 2974 2975 // If we successfully put the NSEC record, clear the SendNSECNow flag 2976 // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record 2977 if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1) 2978 { 2979 rr->SendNSECNow = mDNSNULL; 2980 // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC 2981 for (r2 = rr->next; r2; r2=r2->next) 2982 if (SameResourceRecordNameClassInterface(r2, rr)) 2983 if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID) 2984 r2->SendNSECNow = mDNSNULL; 2985 } 2986 } 2987 2988 if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals) 2989 { 2990 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p", 2991 numDereg, numDereg == 1 ? "" : "s", 2992 numAnnounce, numAnnounce == 1 ? "" : "s", 2993 numAnswer, numAnswer == 1 ? "" : "s", 2994 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID); 2995 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); 2996 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); 2997 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 2998 if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; } 2999 // There might be more things to send on this interface, so go around one more time and try again. 3000 } 3001 else // Nothing more to send on this interface; go to next 3002 { 3003 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 3004 #if MDNS_DEBUGMSGS && 0 3005 const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p"; 3006 debugf(msg, intf, next); 3007 #endif 3008 intf = next; 3009 pktcount = 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it 3010 } 3011 } 3012 3013 // *** 3014 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables 3015 // *** 3016 3017 if (m->CurrentRecord) 3018 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 3019 m->CurrentRecord = m->ResourceRecords; 3020 while (m->CurrentRecord) 3021 { 3022 rr = m->CurrentRecord; 3023 m->CurrentRecord = rr->next; 3024 3025 if (rr->SendRNow) 3026 { 3027 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) 3028 LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); 3029 rr->SendRNow = mDNSNULL; 3030 } 3031 3032 if (rr->ImmedAnswer) 3033 { 3034 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client 3035 3036 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) 3037 CompleteDeregistration(m, rr); // Don't touch rr after this 3038 else 3039 { 3040 rr->ImmedAnswer = mDNSNULL; 3041 rr->ImmedUnicast = mDNSfalse; 3042 rr->v4Requester = zerov4Addr; 3043 rr->v6Requester = zerov6Addr; 3044 } 3045 } 3046 } 3047 verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow); 3048 } 3049 3050// Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache, 3051// so we want to be lazy about how frequently we do it. 3052// 1. If a cache record is currently referenced by *no* active questions, 3053// then we don't mind expiring it up to a minute late (who will know?) 3054// 2. Else, if a cache record is due for some of its final expiration queries, 3055// we'll allow them to be late by up to 2% of the TTL 3056// 3. Else, if a cache record has completed all its final expiration queries without success, 3057// and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late 3058// 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets), 3059// so allow at most 1/10 second lateness 3060// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately 3061// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients). 3062#define CacheCheckGracePeriod(RR) ( \ 3063 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \ 3064 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \ 3065 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \ 3066 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \ 3067 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0) 3068 3069// Note: MUST call SetNextCacheCheckTime any time we change: 3070// rr->TimeRcvd 3071// rr->resrec.rroriginalttl 3072// rr->UnansweredQueries 3073// rr->CRActiveQuestion 3074// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary 3075// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime 3076mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr) 3077 { 3078 rr->NextRequiredQuery = RRExpireTime(rr); 3079 3080 // If we have an active question, then see if we want to schedule a refresher query for this record. 3081 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL. 3082 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 3083 { 3084 rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries); 3085 rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50); 3086 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks", 3087 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), 3088 (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr)); 3089 } 3090 3091 if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0) 3092 m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)); 3093 3094 if (rr->DelayDelivery) 3095 if (m->NextCacheCheck - rr->DelayDelivery > 0) 3096 m->NextCacheCheck = rr->DelayDelivery; 3097 } 3098 3099#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) 3100#define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5) 3101#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5) 3102#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30) 3103 3104mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval) 3105 { 3106 if (interval < kMinimumReconfirmTime) 3107 interval = kMinimumReconfirmTime; 3108 if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below 3109 interval = 0x10000000; 3110 3111 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration 3112 if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3)) 3113 { 3114 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts 3115 // For all the reconfirmations in a given batch, we want to use the same random value 3116 // so that the reconfirmation questions can be grouped into a single query packet 3117 if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF); 3118 interval += m->RandomReconfirmDelay % ((interval/3) + 1); 3119 rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; 3120 rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; 3121 SetNextCacheCheckTime(m, rr); 3122 } 3123 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p", 3124 RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion); 3125 return(mStatus_NoError); 3126 } 3127 3128#define MaxQuestionInterval (3600 * mDNSPlatformOneSecond) 3129 3130// BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr. 3131// It also appends to the list of known answer records that need to be included, 3132// and updates the forcast for the size of the known answer section. 3133mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q, 3134 CacheRecord ***kalistptrptr, mDNSu32 *answerforecast) 3135 { 3136 mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353; 3137 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 3138 const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData; 3139 mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit)); 3140 if (!newptr) 3141 { 3142 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3143 return(mDNSfalse); 3144 } 3145 else if (newptr + *answerforecast >= limit) 3146 { 3147 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d", 3148 q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data); 3149 query->h.numQuestions--; 3150 return(mDNSfalse); 3151 } 3152 else 3153 { 3154 mDNSu32 forecast = *answerforecast; 3155 const mDNSu32 slot = HashSlot(&q->qname); 3156 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 3157 CacheRecord *rr; 3158 CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update 3159 3160 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 3161 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 3162 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list 3163 rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 3164 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 3165 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away 3166 mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1) 3167 { 3168 *ka = rr; // Link this record into our known answer chain 3169 ka = &rr->NextInKAList; 3170 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3171 forecast += 12 + rr->resrec.rdestimate; 3172 // If we're trying to put more than one question in this packet, and it doesn't fit 3173 // then undo that last question and try again next time 3174 if (query->h.numQuestions > 1 && newptr + forecast >= limit) 3175 { 3176 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d", 3177 q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data); 3178 query->h.numQuestions--; 3179 ka = *kalistptrptr; // Go back to where we started and retract these answer records 3180 while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; } 3181 return(mDNSfalse); // Return false, so we'll try again in the next packet 3182 } 3183 } 3184 3185 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return 3186 *queryptr = newptr; // Update the packet pointer 3187 *answerforecast = forecast; // Update the forecast 3188 *kalistptrptr = ka; // Update the known answer list pointer 3189 if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow); 3190 3191 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache, 3192 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface 3193 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list 3194 SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question 3195 { 3196 rr->UnansweredQueries++; // indicate that we're expecting a response 3197 rr->LastUnansweredTime = m->timenow; 3198 SetNextCacheCheckTime(m, rr); 3199 } 3200 3201 return(mDNStrue); 3202 } 3203 } 3204 3205// When we have a query looking for a specified name, but there appear to be no answers with 3206// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process 3207// for any records in our cache that reference the given name (e.g. PTR and SRV records). 3208// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name. 3209// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5. 3210// A typical reconfirmation scenario might go like this: 3211// Depth 0: Name "myhost.local" has no address records 3212// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale 3213// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale 3214// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale 3215// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we 3216// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents. 3217mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth) 3218 { 3219 mDNSu32 slot; 3220 CacheGroup *cg; 3221 CacheRecord *cr; 3222 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c); 3223 FORALL_CACHERECORDS(slot, cg, cr) 3224 { 3225 domainname *crtarget = GetRRDomainNameTarget(&cr->resrec); 3226 if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name)) 3227 { 3228 LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr)); 3229 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 3230 if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1); 3231 } 3232 } 3233 } 3234 3235// If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents 3236// we check if we have an address record for the same name. If we do have an IPv4 address for a given 3237// name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure 3238// to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name. 3239mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash) 3240 { 3241 CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name); 3242 const CacheRecord *cr = cg ? cg->members : mDNSNULL; 3243 while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next; 3244 return(cr); 3245 } 3246 3247mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1) 3248 { 3249 CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname); 3250 const CacheRecord *cr, *bestcr = mDNSNULL; 3251 mDNSu32 bestmetric = 1000000; 3252 for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) 3253 if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6) // If record is PTR type, with long enough name, 3254 if (cr != c0 && cr != c1) // that's not one we've seen before, 3255 if (SameNameRecordAnswersQuestion(&cr->resrec, q)) // and answers our browse query, 3256 if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec)) // and is not our own advertised service... 3257 { 3258 mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c); 3259 if (bestmetric > metric) { bestmetric = metric; bestcr = cr; } 3260 } 3261 return(bestcr); 3262 } 3263 3264// Finds the three best Sleep Proxies we currently have in our cache 3265mDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]) 3266 { 3267 sps[0] = FindSPSInCache1(m, q, mDNSNULL, mDNSNULL); 3268 sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], mDNSNULL); 3269 sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], sps[1]); 3270 } 3271 3272// Only DupSuppressInfos newer than the specified 'time' are allowed to remain active 3273mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time) 3274 { 3275 int i; 3276 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 3277 } 3278 3279mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID) 3280 { 3281 int i; 3282 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL; 3283 } 3284 3285mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf) 3286 { 3287 int i; 3288 mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query 3289 mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query 3290 for (i=0; i<DupSuppressInfoSize; i++) 3291 if (ds[i].InterfaceID == intf->InterfaceID) 3292 { 3293 if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue; 3294 else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue; 3295 if (v4 && v6) return(mDNStrue); 3296 } 3297 return(mDNSfalse); 3298 } 3299 3300mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type) 3301 { 3302 int i, j; 3303 3304 // See if we have this one in our list somewhere already 3305 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break; 3306 3307 // If not, find a slot we can re-use 3308 if (i >= DupSuppressInfoSize) 3309 { 3310 i = 0; 3311 for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++) 3312 if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0) 3313 i = j; 3314 } 3315 3316 // Record the info about this query we saw 3317 ds[i].Time = Time; 3318 ds[i].InterfaceID = InterfaceID; 3319 ds[i].Type = Type; 3320 3321 return(i); 3322 } 3323 3324mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) 3325 { 3326 // If more than 90% of the way to the query time, we should unconditionally accelerate it 3327 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10)) 3328 return(mDNStrue); 3329 3330 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet 3331 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2)) 3332 { 3333 // We forecast: qname (n) type (2) class (2) 3334 mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4; 3335 const mDNSu32 slot = HashSlot(&q->qname); 3336 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 3337 const CacheRecord *rr; 3338 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, 3339 if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet 3340 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question 3341 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry 3342 rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery 3343 { 3344 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3345 forecast += 12 + rr->resrec.rdestimate; 3346 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate 3347 } 3348 return(mDNStrue); 3349 } 3350 3351 return(mDNSfalse); 3352 } 3353 3354// How Standard Queries are generated: 3355// 1. The Question Section contains the question 3356// 2. The Additional Section contains answers we already know, to suppress duplicate responses 3357 3358// How Probe Queries are generated: 3359// 1. The Question Section contains queries for the name we intend to use, with QType=ANY because 3360// if some other host is already using *any* records with this name, we want to know about it. 3361// 2. The Authority Section contains the proposed values we intend to use for one or more 3362// of our records with that name (analogous to the Update section of DNS Update packets) 3363// because if some other host is probing at the same time, we each want to know what the other is 3364// planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't. 3365 3366mDNSlocal void SendQueries(mDNS *const m) 3367 { 3368 mDNSu32 slot; 3369 CacheGroup *cg; 3370 CacheRecord *cr; 3371 AuthRecord *ar; 3372 int pktcount = 0; 3373 DNSQuestion *q; 3374 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval 3375 mDNSs32 maxExistingQuestionInterval = 0; 3376 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); 3377 CacheRecord *KnownAnswerList = mDNSNULL; 3378 3379 // 1. If time for a query, work out what we need to do 3380 if (m->timenow - m->NextScheduledQuery >= 0) 3381 { 3382 CacheRecord *rr; 3383 3384 // We're expecting to send a query anyway, so see if any expiring cache records are close enough 3385 // to their NextRequiredQuery to be worth batching them together with this one 3386 FORALL_CACHERECORDS(slot, cg, rr) 3387 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 3388 if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0) 3389 { 3390 debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr)); 3391 q = rr->CRActiveQuestion; 3392 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID); 3393 // For uDNS queries (TargetQID non-zero) we adjust LastQTime, 3394 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly 3395 if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it 3396 else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; } 3397 else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID; 3398 else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark; 3399 } 3400 3401 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) 3402 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it 3403 3404 // Scan our list of questions to see which: 3405 // *WideArea* queries need to be sent 3406 // *unicast* queries need to be sent 3407 // *multicast* queries we're definitely going to send 3408 if (m->CurrentQuestion) 3409 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3410 m->CurrentQuestion = m->Questions; 3411 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3412 { 3413 q = m->CurrentQuestion; 3414 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m); 3415 else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow))) 3416 { 3417 mDNSu8 *qptr = m->omsg.data; 3418 const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data); 3419 3420 // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time 3421 if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); 3422 if (q->LocalSocket) 3423 { 3424 InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags); 3425 qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass); 3426 mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL); 3427 q->ThisQInterval *= QuestionIntervalStep; 3428 } 3429 if (q->ThisQInterval > MaxQuestionInterval) 3430 q->ThisQInterval = MaxQuestionInterval; 3431 q->LastQTime = m->timenow; 3432 q->LastQTxTime = m->timenow; 3433 q->RecentAnswerPkts = 0; 3434 q->SendQNow = mDNSNULL; 3435 q->ExpectUnicastResp = NonZeroTime(m->timenow); 3436 } 3437 else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow)) 3438 { 3439 //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval)); 3440 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 3441 if (maxExistingQuestionInterval < q->ThisQInterval) 3442 maxExistingQuestionInterval = q->ThisQInterval; 3443 } 3444 // If m->CurrentQuestion wasn't modified out from under us, advance it now 3445 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having 3446 // m->CurrentQuestion point to the right question 3447 if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next; 3448 } 3449 m->CurrentQuestion = mDNSNULL; 3450 3451 // Scan our list of questions 3452 // (a) to see if there are any more that are worth accelerating, and 3453 // (b) to update the state variables for *all* the questions we're going to send 3454 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list, 3455 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very 3456 // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value. 3457 m->NextScheduledQuery = m->timenow + 0x78000000; 3458 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 3459 { 3460 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow || 3461 (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))) 3462 { 3463 // If at least halfway to next query time, advance to next interval 3464 // If less than halfway to next query time, then 3465 // treat this as logically a repeat of the last transmission, without advancing the interval 3466 if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0) 3467 { 3468 //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval)); 3469 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces 3470 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d", 3471 q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast); 3472 q->ThisQInterval *= QuestionIntervalStep; 3473 if (q->ThisQInterval > MaxQuestionInterval) 3474 q->ThisQInterval = MaxQuestionInterval; 3475 else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast && 3476 !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash))) 3477 { 3478 // Generally don't need to log this. 3479 // It's not especially noteworthy if a query finds no results -- this usually happens for domain 3480 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa") 3481 // and when there simply happen to be no instances of the service the client is looking 3482 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none). 3483 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", 3484 q->qname.c, DNSTypeName(q->qtype)); 3485 // Sending third query, and no answers yet; time to begin doubting the source 3486 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); 3487 } 3488 } 3489 3490 // Mark for sending. (If no active interfaces, then don't even try.) 3491 q->SendOnAll = (q->SendQNow == mDNSInterfaceMark); 3492 if (q->SendOnAll) 3493 { 3494 q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID; 3495 q->LastQTime = m->timenow; 3496 } 3497 3498 // If we recorded a duplicate suppression for this question less than half an interval ago, 3499 // then we consider it recent enough that we don't need to do an identical query ourselves. 3500 ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2); 3501 3502 q->LastQTxTime = m->timenow; 3503 q->RecentAnswerPkts = 0; 3504 if (q->RequestUnicast) q->RequestUnicast--; 3505 } 3506 // For all questions (not just the ones we're sending) check what the next scheduled event will be 3507 SetNextQueryTime(m,q); 3508 } 3509 } 3510 3511 // 2. Scan our authoritative RR list to see what probes we might need to send 3512 if (m->timenow - m->NextScheduledProbe >= 0) 3513 { 3514 m->NextScheduledProbe = m->timenow + 0x78000000; 3515 3516 if (m->CurrentRecord) 3517 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 3518 m->CurrentRecord = m->ResourceRecords; 3519 while (m->CurrentRecord) 3520 { 3521 AuthRecord *rr = m->CurrentRecord; 3522 m->CurrentRecord = rr->next; 3523 if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing... 3524 { 3525 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly 3526 if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0) 3527 { 3528 SetNextAnnounceProbeTime(m, rr); 3529 } 3530 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly 3531 else if (rr->ProbeCount) 3532 { 3533 if (rr->AddressProxy.type == mDNSAddrType_IPv4) 3534 { 3535 LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr)); 3536 SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b); 3537 } 3538 else if (rr->AddressProxy.type == mDNSAddrType_IPv6) 3539 { 3540 //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr)); 3541 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); 3542 } 3543 // Mark for sending. (If no active interfaces, then don't even try.) 3544 rr->SendRNow = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID; 3545 rr->LastAPTime = m->timenow; 3546 // When we have a late conflict that resets a record to probing state we use a special marker value greater 3547 // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value. 3548 if (rr->ProbeCount > DefaultProbeCountForTypeUnique) 3549 rr->ProbeCount = DefaultProbeCountForTypeUnique; 3550 rr->ProbeCount--; 3551 SetNextAnnounceProbeTime(m, rr); 3552 if (rr->ProbeCount == 0) 3553 { 3554 // If this is the last probe for this record, then see if we have any matching records 3555 // on our duplicate list which should similarly have their ProbeCount cleared to zero... 3556 AuthRecord *r2; 3557 for (r2 = m->DuplicateRecords; r2; r2=r2->next) 3558 if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr)) 3559 r2->ProbeCount = 0; 3560 // ... then acknowledge this record to the client. 3561 // We do this optimistically, just as we're about to send the third probe. 3562 // This helps clients that both advertise and browse, and want to filter themselves 3563 // from the browse results list, because it helps ensure that the registration 3564 // confirmation will be delivered 1/4 second *before* the browse "add" event. 3565 // A potential downside is that we could deliver a registration confirmation and then find out 3566 // moments later that there's a name conflict, but applications have to be prepared to handle 3567 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new. 3568 if (!rr->Acknowledged) AcknowledgeRecord(m, rr); 3569 } 3570 } 3571 // else, if it has now finished probing, move it to state Verified, 3572 // and update m->NextScheduledResponse so it will be announced 3573 else 3574 { 3575 if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow 3576 rr->resrec.RecordType = kDNSRecordTypeVerified; 3577 rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique; 3578 rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique; 3579 SetNextAnnounceProbeTime(m, rr); 3580 } 3581 } 3582 } 3583 m->CurrentRecord = m->DuplicateRecords; 3584 while (m->CurrentRecord) 3585 { 3586 AuthRecord *rr = m->CurrentRecord; 3587 m->CurrentRecord = rr->next; 3588 if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged) 3589 AcknowledgeRecord(m, rr); 3590 } 3591 } 3592 3593 // 3. Now we know which queries and probes we're sending, 3594 // go through our interface list sending the appropriate queries on each interface 3595 while (intf) 3596 { 3597 const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + (mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space); 3598 int OwnerRecordSpace = 0; 3599 AuthRecord *rr; 3600 mDNSu8 *queryptr = m->omsg.data; 3601 mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData; 3602 InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags); 3603 if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet"); 3604 if (!KnownAnswerList) 3605 { 3606 // Start a new known-answer list 3607 CacheRecord **kalistptr = &KnownAnswerList; 3608 mDNSu32 answerforecast = 0; 3609 3610 // Put query questions in this packet 3611 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 3612 { 3613 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID)) 3614 { 3615 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d", 3616 SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ", 3617 q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data); 3618 3619 // If we're suppressing this question, or we successfully put it, update its SendQNow state 3620 if (SuppressOnThisInterface(q->DupSuppress, intf) || 3621 BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) 3622 q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); 3623 3624 // Once we've put at least one question, cut back our limit to the normal single-packet size 3625 if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData; 3626 } 3627 } 3628 3629 // Put probe questions in this packet 3630 for (rr = m->ResourceRecords; rr; rr=rr->next) 3631 if (rr->SendRNow == intf->InterfaceID) 3632 { 3633 mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353; 3634 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); 3635 mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit)); 3636 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) 3637 mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate; 3638 if (newptr && newptr + forecast + os < limit) 3639 { 3640 queryptr = newptr; 3641 limit = m->omsg.data + NormalMaxDNSMessageData; 3642 answerforecast = forecast; 3643 OwnerRecordSpace = os; 3644 rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); 3645 rr->IncludeInProbe = mDNStrue; 3646 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", 3647 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount); 3648 } 3649 else 3650 { 3651 verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); 3652 m->omsg.h.numQuestions--; 3653 } 3654 } 3655 } 3656 3657 if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace; 3658 3659 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) 3660 while (KnownAnswerList) 3661 { 3662 CacheRecord *ka = KnownAnswerList; 3663 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond; 3664 mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit); 3665 if (newptr) 3666 { 3667 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", 3668 ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); 3669 queryptr = newptr; 3670 limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace; 3671 KnownAnswerList = ka->NextInKAList; 3672 ka->NextInKAList = mDNSNULL; 3673 } 3674 else 3675 { 3676 // If we ran out of space and we have more than one question in the packet, that's an error -- 3677 // we shouldn't have put more than one question if there was a risk of us running out of space. 3678 if (m->omsg.h.numQuestions > 1) 3679 LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers); 3680 m->omsg.h.flags.b[0] |= kDNSFlag0_TC; 3681 break; 3682 } 3683 } 3684 3685 for (rr = m->ResourceRecords; rr; rr=rr->next) 3686 if (rr->IncludeInProbe) 3687 { 3688 mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec); 3689 rr->IncludeInProbe = mDNSfalse; 3690 if (newptr) queryptr = newptr; 3691 else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,rr)); 3692 } 3693 3694 if (OwnerRecordSpace) 3695 { 3696 AuthRecord opt; 3697 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 3698 opt.resrec.rrclass = NormalMaxDNSMessageData; 3699 opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 3700 opt.resrec.rdestimate = sizeof(rdataOPT); 3701 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); 3702 LogSPS("SendQueries putting %s", ARDisplayString(m, &opt)); 3703 queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals, 3704 &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 3705 if (!queryptr) 3706 LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s", 3707 m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); 3708 } 3709 3710 if (queryptr > m->omsg.data) 3711 { 3712 if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1) 3713 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions); 3714 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p", 3715 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 3716 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 3717 m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID); 3718 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); 3719 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); 3720 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); 3721 if (++pktcount >= 1000) 3722 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; } 3723 // There might be more records left in the known answer list, or more questions to send 3724 // on this interface, so go around one more time and try again. 3725 } 3726 else // Nothing more to send on this interface; go to next 3727 { 3728 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next); 3729 #if MDNS_DEBUGMSGS && 0 3730 const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p"; 3731 debugf(msg, intf, next); 3732 #endif 3733 intf = next; 3734 } 3735 } 3736 3737 // 4. Final housekeeping 3738 3739 // 4a. Debugging check: Make sure we announced all our records 3740 for (ar = m->ResourceRecords; ar; ar=ar->next) 3741 if (ar->SendRNow) 3742 { 3743 if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) 3744 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar)); 3745 ar->SendRNow = mDNSNULL; 3746 } 3747 3748 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope 3749 // that their interface which went away might come back again, the logic will want to send queries 3750 // for those records, but we can't because their interface isn't here any more, so to keep the 3751 // state machine ticking over we just pretend we did so. 3752 // If the interface does not come back in time, the cache record will expire naturally 3753 FORALL_CACHERECORDS(slot, cg, cr) 3754 if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0) 3755 { 3756 cr->UnansweredQueries++; 3757 cr->CRActiveQuestion->SendQNow = mDNSNULL; 3758 SetNextCacheCheckTime(m, cr); 3759 } 3760 3761 // 4c. Debugging check: Make sure we sent all our planned questions 3762 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions 3763 // we legitimately couldn't send because the interface is no longer available 3764 for (q = m->Questions; q; q=q->next) 3765 if (q->SendQNow) 3766 { 3767 LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3768 q->SendQNow = mDNSNULL; 3769 } 3770 } 3771 3772mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password) 3773 { 3774 int i, j; 3775 mDNSu8 *ptr = m->omsg.data; 3776 3777 if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; } 3778 3779 // 0x00 Destination address 3780 for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; 3781 3782 // 0x06 Source address (we just use zero -- BPF will fill in real interface address) 3783 for (i=0; i<6; i++) *ptr++ = 0x0; 3784 3785 // 0x0C Ethertype (0x0842) 3786 *ptr++ = 0x08; 3787 *ptr++ = 0x42; 3788 3789 // 0x0E Wakeup sync sequence 3790 for (i=0; i<6; i++) *ptr++ = 0xFF; 3791 3792 // 0x14 Wakeup data 3793 for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; 3794 3795 // 0x74 Password 3796 for (i=0; i<6; i++) *ptr++ = password->b[i]; 3797 3798 mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); 3799 3800 // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses, 3801 // broadcast is the only reliable way to get a wakeup packet to the intended target machine. 3802 // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast 3803 // key rotation, unicast is the only way to get a wakeup packet to the intended target machine. 3804 // So, we send one of each, unicast first, then broadcast second. 3805 for (i=0; i<6; i++) m->omsg.data[i] = 0xFF; 3806 mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); 3807 } 3808 3809// *************************************************************************** 3810#if COMPILER_LIKES_PRAGMA_MARK 3811#pragma mark - 3812#pragma mark - RR List Management & Task Management 3813#endif 3814 3815// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. 3816// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this. 3817// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion, 3818// which will be auto-advanced (possibly to NULL) if the client callback cancels the question. 3819mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord) 3820 { 3821 DNSQuestion *const q = m->CurrentQuestion; 3822 mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord && 3823 rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME; 3824 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr)); 3825 3826 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue) 3827 // may be called twice, once when the record is received, and again when it's time to notify local clients. 3828 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this. 3829 3830 rr->LastUsed = m->timenow; 3831 if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q) 3832 { 3833 if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count 3834 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr)); 3835 rr->CRActiveQuestion = q; // We know q is non-null 3836 SetNextCacheCheckTime(m, rr); 3837 } 3838 3839 // If this is: 3840 // (a) a no-cache add, where we've already done at least one 'QM' query, or 3841 // (b) a normal add, where we have at least one unique-type answer, 3842 // then there's no need to keep polling the network. 3843 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.) 3844 // We do this for mDNS questions and uDNS one-shot questions, but not for 3845 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing. 3846 if ((AddRecord == QC_addnocache && !q->RequestUnicast) || 3847 (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) 3848 if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived)) 3849 { 3850 q->LastQTime = m->timenow; 3851 q->LastQTxTime = m->timenow; 3852 q->RecentAnswerPkts = 0; 3853 q->ThisQInterval = MaxQuestionInterval; 3854 q->RequestUnicast = mDNSfalse; 3855 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 3856 } 3857 3858 if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us 3859 3860 // Only deliver negative answers if client has explicitly requested them 3861 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))) 3862 if (!AddRecord || !q->ReturnIntermed) return; 3863 3864 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that 3865 if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed)) 3866 { 3867 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls 3868 if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)) 3869 { 3870 CacheRecord neg; 3871 MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID); 3872 q->QuestionCallback(m, q, &neg.resrec, AddRecord); 3873 } 3874 else 3875 q->QuestionCallback(m, q, &rr->resrec, AddRecord); 3876 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 3877 } 3878 // Note: Proceed with caution here because client callback function is allowed to do anything, 3879 // including starting/stopping queries, registering/deregistering records, etc. 3880 3881 if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10) 3882 { 3883 const mDNSu32 c = q->CNAMEReferrals + 1; 3884 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, 3885 // and track CNAMEs coming and going, we should really create a subordinate query here, 3886 // which we would subsequently cancel and retract if the CNAME referral record were removed. 3887 // In reality this is such a corner case we'll ignore it until someone actually needs it. 3888 LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr)); 3889 mDNS_StopQuery_internal(m, q); // Stop old query 3890 AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname 3891 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash 3892 mDNS_StartQuery_internal(m, q); // start new query 3893 q->CNAMEReferrals = c; // and keep count of how many times we've done this 3894 } 3895 } 3896 3897mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) 3898 { 3899 rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared 3900 if (m->CurrentQuestion) 3901 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3902 m->CurrentQuestion = m->Questions; 3903 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3904 { 3905 DNSQuestion *q = m->CurrentQuestion; 3906 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3907 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 3908 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 3909 m->CurrentQuestion = q->next; 3910 } 3911 m->CurrentQuestion = mDNSNULL; 3912 } 3913 3914mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot) 3915 { 3916 const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second 3917 const mDNSs32 start = m->timenow - 0x10000000; 3918 mDNSs32 delay = start; 3919 CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); 3920 const CacheRecord *rr; 3921 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 3922 if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second 3923 if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted 3924 delay = RRExpireTime(rr); 3925 if (delay - start > 0) return(NonZeroTime(delay)); 3926 else return(0); 3927 } 3928 3929// CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 3930// If new questions are created as a result of invoking client callbacks, they will be added to 3931// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 3932// rr is a new CacheRecord just received into our cache 3933// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 3934// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 3935// which may change the record list and/or question list. 3936// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 3937mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) 3938 { 3939 DNSQuestion *q; 3940 3941 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers 3942 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion(). 3943 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 3944 { 3945 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3946 { 3947 // If this question is one that's actively sending queries, and it's received ten answers within one 3948 // second of sending the last query packet, then that indicates some radical network topology change, 3949 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval 3950 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating 3951 // because we will anyway send another query within a few seconds. The first reset query is sent out 3952 // randomized over the next four seconds to reduce possible synchronization between machines. 3953 if (q->LastAnswerPktNum != m->PktNum) 3954 { 3955 q->LastAnswerPktNum = m->PktNum; 3956 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && 3957 q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) 3958 { 3959 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)", 3960 q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval); 3961 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4); 3962 q->ThisQInterval = InitialQuestionInterval; 3963 SetNextQueryTime(m,q); 3964 } 3965 } 3966 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", 3967 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl); 3968 q->CurrentAnswers++; 3969 q->unansweredQueries = 0; 3970 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 3971 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 3972 if (q->CurrentAnswers > 4000) 3973 { 3974 static int msgcount = 0; 3975 if (msgcount++ < 10) 3976 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", 3977 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); 3978 rr->resrec.rroriginalttl = 0; 3979 rr->UnansweredQueries = MaxUnansweredQueries; 3980 } 3981 } 3982 } 3983 3984 if (!rr->DelayDelivery) 3985 { 3986 if (m->CurrentQuestion) 3987 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 3988 m->CurrentQuestion = m->Questions; 3989 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 3990 { 3991 q = m->CurrentQuestion; 3992 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 3993 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 3994 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 3995 m->CurrentQuestion = q->next; 3996 } 3997 m->CurrentQuestion = mDNSNULL; 3998 } 3999 4000 SetNextCacheCheckTime(m, rr); 4001 } 4002 4003// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call. 4004// If new questions are created as a result of invoking client callbacks, they will be added to 4005// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 4006// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique) 4007// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any 4008// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, 4009// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. 4010// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 4011// which may change the record list and/or question list. 4012// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4013mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) 4014 { 4015 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); 4016 if (m->CurrentQuestion) 4017 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4018 m->CurrentQuestion = m->Questions; 4019 // We do this for *all* questions, not stopping when we get to m->NewQuestions, 4020 // since we're not caching the record and we'll get no opportunity to do this later 4021 while (m->CurrentQuestion) 4022 { 4023 DNSQuestion *q = m->CurrentQuestion; 4024 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4025 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" 4026 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 4027 m->CurrentQuestion = q->next; 4028 } 4029 m->CurrentQuestion = mDNSNULL; 4030 } 4031 4032// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute. 4033// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question. 4034// If new questions are created as a result of invoking client callbacks, they will be added to 4035// the end of the question list, and m->NewQuestions will be set to indicate the first new question. 4036// rr is an existing cache CacheRecord that just expired and is being deleted 4037// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). 4038// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback, 4039// which may change the record list and/or question list. 4040// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 4041mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) 4042 { 4043 if (m->CurrentQuestion) 4044 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4045 m->CurrentQuestion = m->Questions; 4046 4047 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters 4048 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them. 4049 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) 4050 { 4051 DNSQuestion *q = m->CurrentQuestion; 4052 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4053 { 4054 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); 4055 q->FlappingInterface1 = mDNSNULL; 4056 q->FlappingInterface2 = mDNSNULL; 4057 if (q->CurrentAnswers == 0) 4058 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", 4059 q, q->qname.c, DNSTypeName(q->qtype)); 4060 else 4061 { 4062 q->CurrentAnswers--; 4063 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; 4064 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; 4065 } 4066 if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results 4067 { 4068 if (q->CurrentAnswers == 0) 4069 { 4070 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", 4071 q->qname.c, DNSTypeName(q->qtype)); 4072 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); 4073 } 4074 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); 4075 } 4076 } 4077 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now 4078 m->CurrentQuestion = q->next; 4079 } 4080 m->CurrentQuestion = mDNSNULL; 4081 } 4082 4083mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) 4084 { 4085#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 4086 unsigned int i; 4087 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF; 4088#endif 4089 e->next = m->rrcache_free; 4090 m->rrcache_free = e; 4091 m->rrcache_totalused--; 4092 } 4093 4094mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) 4095 { 4096 CacheEntity *e = (CacheEntity *)(*cp); 4097 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); 4098 if ((*cp)->rrcache_tail != &(*cp)->members) 4099 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); 4100 //if ((*cp)->name != (domainname*)((*cp)->namestorage)) 4101 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); 4102 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); 4103 (*cp)->name = mDNSNULL; 4104 *cp = (*cp)->next; // Cut record from list 4105 ReleaseCacheEntity(m, e); 4106 } 4107 4108mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) 4109 { 4110 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); 4111 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); 4112 r->resrec.rdata = mDNSNULL; 4113 ReleaseCacheEntity(m, (CacheEntity *)r); 4114 } 4115 4116// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering 4117// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all 4118// callbacks for old records are delivered before callbacks for newer records. 4119mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg) 4120 { 4121 CacheRecord **rp = &cg->members; 4122 4123 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; } 4124 m->lock_rrcache = 1; 4125 4126 while (*rp) 4127 { 4128 CacheRecord *const rr = *rp; 4129 mDNSs32 event = RRExpireTime(rr); 4130 if (m->timenow - event >= 0) // If expired, delete it 4131 { 4132 *rp = rr->next; // Cut it from the list 4133 verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s", 4134 m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); 4135 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away 4136 { 4137 CacheRecordRmv(m, rr); 4138 m->rrcache_active--; 4139 } 4140 ReleaseCacheRecord(m, rr); 4141 } 4142 else // else, not expired; see if we need to query 4143 { 4144 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0) 4145 event = rr->DelayDelivery; 4146 else 4147 { 4148 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr); 4149 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) 4150 { 4151 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query 4152 event = rr->NextRequiredQuery; // then just record when we want the next query 4153 else // else trigger our question to go out now 4154 { 4155 // Set NextScheduledQuery to timenow so that SendQueries() will run. 4156 // SendQueries() will see that we have records close to expiration, and send FEQs for them. 4157 m->NextScheduledQuery = m->timenow; 4158 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(), 4159 // which will correctly update m->NextCacheCheck for us. 4160 event = m->timenow + 0x3FFFFFFF; 4161 } 4162 } 4163 } 4164 verbosedebugf("CheckCacheExpiration:%6d %5d %s", 4165 (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); 4166 if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0) 4167 m->NextCacheCheck = (event + CacheCheckGracePeriod(rr)); 4168 rp = &rr->next; 4169 } 4170 } 4171 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp); 4172 cg->rrcache_tail = rp; 4173 m->lock_rrcache = 0; 4174 } 4175 4176mDNSlocal void AnswerNewQuestion(mDNS *const m) 4177 { 4178 mDNSBool ShouldQueryImmediately = mDNStrue; 4179 DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer 4180 const mDNSu32 slot = HashSlot(&q->qname); 4181 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 4182 4183 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4184 4185 if (cg) CheckCacheExpiration(m, cg); 4186 m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration(); 4187 4188 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); 4189 // This should be safe, because calling the client's question callback may cause the 4190 // question list to be modified, but should not ever cause the rrcache list to be modified. 4191 // If the client's question callback deletes the question, then m->CurrentQuestion will 4192 // be advanced, and we'll exit out of the loop 4193 m->lock_rrcache = 1; 4194 if (m->CurrentQuestion) 4195 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4196 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 4197 4198 if (q->NoAnswer == NoAnswer_Fail) 4199 { 4200 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4201 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any); 4202 q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression 4203 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); 4204 q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state 4205 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 4206 } 4207 4208 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records 4209 if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any) 4210 { 4211 if (m->CurrentRecord) 4212 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 4213 m->CurrentRecord = m->ResourceRecords; 4214 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 4215 { 4216 AuthRecord *rr = m->CurrentRecord; 4217 m->CurrentRecord = rr->next; 4218 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) 4219 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4220 { 4221 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue); 4222 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4223 } 4224 } 4225 m->CurrentRecord = mDNSNULL; 4226 } 4227 4228 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers"); 4229 4230 if (m->CurrentQuestion == q) 4231 { 4232 CacheRecord *rr; 4233 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 4234 if (SameNameRecordAnswersQuestion(&rr->resrec, q)) 4235 { 4236 // SecsSinceRcvd is whole number of elapsed seconds, rounded down 4237 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; 4238 if (rr->resrec.rroriginalttl <= SecsSinceRcvd) 4239 { 4240 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", 4241 rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); 4242 continue; // Go to next one in loop 4243 } 4244 4245 // If this record set is marked unique, then that means we can reasonably assume we have the whole set 4246 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there 4247 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) 4248 ShouldQueryImmediately = mDNSfalse; 4249 q->CurrentAnswers++; 4250 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; 4251 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; 4252 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); 4253 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4254 } 4255 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) 4256 ShouldQueryImmediately = mDNSfalse; 4257 } 4258 4259 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers"); 4260 4261 if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q)) 4262 { 4263 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4264 q->ThisQInterval = InitialQuestionInterval; 4265 q->LastQTime = m->timenow - q->ThisQInterval; 4266 if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries 4267 { 4268 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms 4269 if (!m->RandomQueryDelay) 4270 m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; 4271 q->LastQTime += m->RandomQueryDelay; 4272 } 4273 4274 if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0) 4275 m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval); 4276 } 4277 4278 m->CurrentQuestion = mDNSNULL; 4279 m->lock_rrcache = 0; 4280 } 4281 4282// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any 4283// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord 4284mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) 4285 { 4286 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer 4287 m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any) 4288 4289 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4290 4291 if (m->CurrentQuestion) 4292 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4293 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted 4294 4295 if (m->CurrentRecord) 4296 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 4297 m->CurrentRecord = m->ResourceRecords; 4298 4299 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) 4300 { 4301 AuthRecord *rr = m->CurrentRecord; 4302 m->CurrentRecord = rr->next; 4303 if (ResourceRecordAnswersQuestion(&rr->resrec, q)) 4304 { 4305 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue); 4306 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here 4307 } 4308 } 4309 4310 m->CurrentQuestion = mDNSNULL; 4311 m->CurrentRecord = mDNSNULL; 4312 } 4313 4314mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG) 4315 { 4316 CacheEntity *e = mDNSNULL; 4317 4318 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); } 4319 m->lock_rrcache = 1; 4320 4321 // If we have no free records, ask the client layer to give us some more memory 4322 if (!m->rrcache_free && m->MainCallback) 4323 { 4324 if (m->rrcache_totalused != m->rrcache_size) 4325 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu", 4326 m->rrcache_totalused, m->rrcache_size); 4327 4328 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite 4329 // number of bogus records so that we keep growing our cache until the machine runs out of memory. 4330 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), 4331 // and we're actively using less than 1/32 of that cache, then we purge all the unused records 4332 // and recycle them, instead of allocating more memory. 4333 if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) 4334 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", 4335 m->rrcache_size, m->rrcache_active); 4336 else 4337 { 4338 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 4339 m->MainCallback(m, mStatus_GrowCache); 4340 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 4341 } 4342 } 4343 4344 // If we still have no free records, recycle all the records we can. 4345 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. 4346 if (!m->rrcache_free) 4347 { 4348 mDNSu32 oldtotalused = m->rrcache_totalused; 4349 mDNSu32 slot; 4350 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4351 { 4352 CacheGroup **cp = &m->rrcache_hash[slot]; 4353 while (*cp) 4354 { 4355 CacheRecord **rp = &(*cp)->members; 4356 while (*rp) 4357 { 4358 // Records that answer still-active questions are not candidates for recycling 4359 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash 4360 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList) 4361 rp=&(*rp)->next; 4362 else 4363 { 4364 CacheRecord *rr = *rp; 4365 *rp = (*rp)->next; // Cut record from list 4366 ReleaseCacheRecord(m, rr); 4367 } 4368 } 4369 if ((*cp)->rrcache_tail != rp) 4370 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); 4371 (*cp)->rrcache_tail = rp; 4372 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; 4373 else ReleaseCacheGroup(m, cp); 4374 } 4375 } 4376 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", 4377 oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); 4378 } 4379 4380 if (m->rrcache_free) // If there are records in the free list, take one 4381 { 4382 e = m->rrcache_free; 4383 m->rrcache_free = e->next; 4384 if (++m->rrcache_totalused >= m->rrcache_report) 4385 { 4386 LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); 4387 if (m->rrcache_report < 100) m->rrcache_report += 10; 4388 else if (m->rrcache_report < 1000) m->rrcache_report += 100; 4389 else m->rrcache_report += 1000; 4390 } 4391 mDNSPlatformMemZero(e, sizeof(*e)); 4392 } 4393 4394 m->lock_rrcache = 0; 4395 4396 return(e); 4397 } 4398 4399mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength) 4400 { 4401 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); 4402 if (r) 4403 { 4404 r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage 4405 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage 4406 { 4407 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); 4408 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength; 4409 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; } 4410 } 4411 } 4412 return(r); 4413 } 4414 4415mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr) 4416 { 4417 mDNSu16 namelen = DomainNameLength(rr->name); 4418 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL); 4419 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); } 4420 cg->next = m->rrcache_hash[slot]; 4421 cg->namehash = rr->namehash; 4422 cg->members = mDNSNULL; 4423 cg->rrcache_tail = &cg->members; 4424 cg->name = (domainname*)cg->namestorage; 4425 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", 4426 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); 4427 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); 4428 if (!cg->name) 4429 { 4430 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c); 4431 ReleaseCacheEntity(m, (CacheEntity*)cg); 4432 return(mDNSNULL); 4433 } 4434 AssignDomainName(cg->name, rr->name); 4435 4436 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c); 4437 m->rrcache_hash[slot] = cg; 4438 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c); 4439 4440 return(cg); 4441 } 4442 4443mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) 4444 { 4445 if (m->mDNS_busy != m->mDNS_reentrancy+1) 4446 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); 4447 // Make sure we mark this record as thoroughly expired -- we don't ever want to give 4448 // a positive answer using an expired record (e.g. from an interface that has gone away). 4449 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to 4450 // summary deletion without giving the proper callback to any questions that are monitoring it. 4451 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries. 4452 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60; 4453 rr->UnansweredQueries = MaxUnansweredQueries; 4454 rr->resrec.rroriginalttl = 0; 4455 SetNextCacheCheckTime(m, rr); 4456 } 4457 4458mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) 4459 { 4460 mDNSs32 time; 4461 mDNSPlatformLock(m); 4462 if (m->mDNS_busy) 4463 { 4464 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow."); 4465 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy); 4466 } 4467 4468 if (m->timenow) time = m->timenow; 4469 else time = mDNS_TimeNow_NoLock(m); 4470 mDNSPlatformUnlock(m); 4471 return(time); 4472 } 4473 4474// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that 4475// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). 4476// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) 4477#define SetSPSProxyListChanged(X) do { \ 4478 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ 4479 m->SPSProxyListChanged = (X); } while(0) 4480 4481// Called from mDNS_Execute() to expire stale proxy records 4482mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) 4483 { 4484 m->CurrentRecord = list; 4485 while (m->CurrentRecord) 4486 { 4487 AuthRecord *rr = m->CurrentRecord; 4488 if (rr->WakeUp.HMAC.l[0]) 4489 { 4490 if (m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS 4491 { 4492 if (m->NextScheduledSPS - rr->TimeExpire > 0) 4493 m->NextScheduledSPS = rr->TimeExpire; 4494 } 4495 else // else proxy record expired, so remove it 4496 { 4497 LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s", 4498 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); 4499 SetSPSProxyListChanged(rr->resrec.InterfaceID); 4500 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 4501 // Don't touch rr after this -- memory may have been free'd 4502 } 4503 } 4504 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, 4505 // because the list may have been changed in that call. 4506 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 4507 m->CurrentRecord = rr->next; 4508 } 4509 } 4510 4511mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) 4512 { 4513 mDNS_Lock(m); // Must grab lock before trying to read m->timenow 4514 4515 if (m->timenow - m->NextScheduledEvent >= 0) 4516 { 4517 int i; 4518 4519 verbosedebugf("mDNS_Execute"); 4520 if (m->CurrentQuestion) 4521 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4522 4523 // 1. If we're past the probe suppression time, we can clear it 4524 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; 4525 4526 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter 4527 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0; 4528 4529 // 3. Purge our cache of stale old records 4530 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0) 4531 { 4532 mDNSu32 slot; 4533 m->NextCacheCheck = m->timenow + 0x3FFFFFFF; 4534 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 4535 { 4536 CacheGroup **cp = &m->rrcache_hash[slot]; 4537 while (*cp) 4538 { 4539 CheckCacheExpiration(m, *cp); 4540 if ((*cp)->members) cp=&(*cp)->next; 4541 else ReleaseCacheGroup(m, cp); 4542 } 4543 } 4544 } 4545 4546 if (m->timenow - m->NextScheduledSPS >= 0) 4547 { 4548 m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; 4549 CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords 4550 CheckProxyRecords(m, m->ResourceRecords); 4551 } 4552 4553 SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now 4554 4555 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) 4556 { 4557 m->DelaySleep = 0; 4558 if (m->SleepState == SleepState_Transferring) 4559 { 4560 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); 4561 BeginSleepProcessing(m); 4562 } 4563 } 4564 4565 // 4. See if we can answer any of our new local questions from the cache 4566 for (i=0; m->NewQuestions && i<1000; i++) 4567 { 4568 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break; 4569 AnswerNewQuestion(m); 4570 } 4571 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit"); 4572 4573 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m); 4574 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit"); 4575 4576 for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++) 4577 { 4578 AuthRecord *rr = m->NewLocalRecords; 4579 m->NewLocalRecords = m->NewLocalRecords->next; 4580 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); 4581 } 4582 if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit"); 4583 4584 // 5. See what packets we need to send 4585 if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) 4586 DiscardDeregistrations(m); 4587 if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) 4588 { 4589 // If the platform code is ready, and we're not suppressing packet generation right now 4590 // then send our responses, probes, and questions. 4591 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. 4592 // We send queries next, because there might be final-stage probes that complete their probing here, causing 4593 // them to advance to announcing state, and we want those to be included in any announcements we send out. 4594 // Finally, we send responses, including the previously mentioned records that just completed probing. 4595 m->SuppressSending = 0; 4596 4597 // 6. Send Query packets. This may cause some probing records to advance to announcing state 4598 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); 4599 if (m->timenow - m->NextScheduledQuery >= 0) 4600 { 4601 DNSQuestion *q; 4602 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", 4603 m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); 4604 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; 4605 for (q = m->Questions; q && q != m->NewQuestions; q=q->next) 4606 if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0) 4607 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 4608 } 4609 if (m->timenow - m->NextScheduledProbe >= 0) 4610 { 4611 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", 4612 m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); 4613 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; 4614 } 4615 4616 // 7. Send Response packets, including probing records just advanced to announcing state 4617 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m); 4618 if (m->timenow - m->NextScheduledResponse >= 0) 4619 { 4620 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second"); 4621 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond; 4622 } 4623 } 4624 4625 // Clear RandomDelay values, ready to pick a new different value next time 4626 m->RandomQueryDelay = 0; 4627 m->RandomReconfirmDelay = 0; 4628 } 4629 4630 // Note about multi-threaded systems: 4631 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(), 4632 // performing mDNS API operations that change our next scheduled event time. 4633 // 4634 // On multi-threaded systems (like the current Windows implementation) that have a single main thread 4635 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility 4636 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will 4637 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one 4638 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful 4639 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it 4640 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately 4641 // without blocking. This avoids the race condition between the signal from the other thread arriving 4642 // just *before* or just *after* the main thread enters the blocking primitive. 4643 // 4644 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven, 4645 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to 4646 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer 4647 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale 4648 // by the time it gets to the timer callback function). 4649 4650#ifndef UNICAST_DISABLED 4651 uDNS_Execute(m); 4652#endif 4653 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value 4654 return(m->NextScheduledEvent); 4655 } 4656 4657mDNSlocal void SuspendLLQs(mDNS *m) 4658 { 4659 DNSQuestion *q; 4660 for (q = m->Questions; q; q = q->next) 4661 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established) 4662 { q->ReqLease = 0; sendLLQRefresh(m, q); } 4663 } 4664 4665// ActivateUnicastQuery() is called from three places: 4666// 1. When a new question is created 4667// 2. On wake from sleep 4668// 3. When the DNS configuration changes 4669// In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false) 4670// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true) 4671mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately) 4672 { 4673 // For now this AutoTunnel stuff is specific to Mac OS X. 4674 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer 4675#if APPLE_OSX_mDNSResponder 4676 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally. 4677 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the 4678 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel. 4679 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then 4680 // returns results for both at the same time. 4681 if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback) 4682 { 4683 question->NoAnswer = NoAnswer_Suspended; 4684 AddNewClientTunnel(m, question); 4685 return; 4686 } 4687#endif // APPLE_OSX_mDNSResponder 4688 4689 if (!question->DuplicateOf) 4690 { 4691 debugf("ActivateUnicastQuery: %##s %s%s%s", 4692 question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); 4693 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } 4694 if (question->LongLived) 4695 { 4696 question->state = LLQ_InitialRequest; 4697 question->id = zeroOpaque64; 4698 question->servPort = zeroIPPort; 4699 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } 4700 } 4701 if (ScheduleImmediately) 4702 { 4703 question->ThisQInterval = InitialQuestionInterval; 4704 question->LastQTime = m->timenow - question->ThisQInterval; 4705 SetNextQueryTime(m, question); 4706 } 4707 } 4708 } 4709 4710mDNSexport void mDNSCoreRestartQueries(mDNS *const m) 4711 { 4712 DNSQuestion *q; 4713 4714#ifndef UNICAST_DISABLED 4715 // Retrigger all our uDNS questions 4716 if (m->CurrentQuestion) 4717 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); 4718 m->CurrentQuestion = m->Questions; 4719 while (m->CurrentQuestion) 4720 { 4721 q = m->CurrentQuestion; 4722 m->CurrentQuestion = m->CurrentQuestion->next; 4723 if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue); 4724 } 4725#endif 4726 4727 // Retrigger all our mDNS questions 4728 for (q = m->Questions; q; q=q->next) // Scan our list of questions 4729 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) 4730 { 4731 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 4732 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 4733 q->LastQTime = m->timenow - q->ThisQInterval; 4734 q->RecentAnswerPkts = 0; 4735 ExpireDupSuppressInfo(q->DupSuppress, m->timenow); 4736 m->NextScheduledQuery = m->timenow; 4737 } 4738 } 4739 4740// *************************************************************************** 4741#if COMPILER_LIKES_PRAGMA_MARK 4742#pragma mark - 4743#pragma mark - Power Management (Sleep/Wake) 4744#endif 4745 4746mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id) 4747 { 4748 const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space; 4749 const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace; 4750 const int sps = intf->NextSPSAttempt / 3; 4751 AuthRecord *rr; 4752 4753 if (!intf->SPSAddr[sps].type) 4754 { 4755 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 4756 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 4757 m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 4758 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); 4759 goto exit; 4760 } 4761 4762 // Mark our mDNS records (not unicast records) for transfer to SPS 4763 if (mDNSOpaque16IsZero(id)) 4764 for (rr = m->ResourceRecords; rr; rr=rr->next) 4765 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) 4766 if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) 4767 rr->SendRNow = mDNSInterfaceMark; // mark it now 4768 4769 while (1) 4770 { 4771 mDNSu8 *p = m->omsg.data; 4772 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. 4773 // For now we follow that same logic for SPS registrations too. 4774 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our 4775 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. 4776 InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); 4777 4778 for (rr = m->ResourceRecords; rr; rr=rr->next) 4779 if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) 4780 { 4781 mDNSu8 *newptr; 4782 const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; 4783 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 4784 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it 4785 newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); 4786 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state 4787 if (!newptr) 4788 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); 4789 else 4790 { 4791 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); 4792 rr->SendRNow = mDNSNULL; 4793 rr->ThisAPInterval = mDNSPlatformOneSecond; 4794 rr->LastAPTime = m->timenow; 4795 rr->updateid = m->omsg.h.id; 4796 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 4797 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); 4798 p = newptr; 4799 } 4800 } 4801 4802 if (!m->omsg.h.mDNS_numUpdates) break; 4803 else 4804 { 4805 AuthRecord opt; 4806 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 4807 opt.resrec.rrclass = NormalMaxDNSMessageData; 4808 opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record 4809 opt.resrec.rdestimate = sizeof(rdataOPT) * 2; 4810 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 4811 opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; 4812 opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; 4813 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); 4814 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); 4815 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 4816 if (!p) 4817 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); 4818 else 4819 { 4820 mStatus err; 4821 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, 4822 mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); 4823 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss 4824 err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); 4825 if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); 4826 if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) 4827 { 4828 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); 4829 intf->NetWakeResolve[sps].qtype = kDNSType_A; 4830 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); 4831 return; 4832 } 4833 } 4834 } 4835 } 4836 4837 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime 4838 4839exit: 4840 if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; 4841 } 4842 4843// RetrySPSRegistrations is called from SendResponses, with the lock held 4844mDNSlocal void RetrySPSRegistrations(mDNS *const m) 4845 { 4846 AuthRecord *rr; 4847 NetworkInterfaceInfo *intf; 4848 4849 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 4850 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4851 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) 4852 intf->NextSPSAttemptTime++; 4853 4854 // Retry any record registrations that are due 4855 for (rr = m->ResourceRecords; rr; rr=rr->next) 4856 if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) 4857 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4858 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) 4859 { 4860 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); 4861 SendSPSRegistration(m, intf, rr->updateid); 4862 } 4863 4864 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt 4865 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4866 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) 4867 intf->NextSPSAttempt++; 4868 } 4869 4870mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 4871 { 4872 NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; 4873 int sps = question - intf->NetWakeResolve; 4874 (void)m; // Unused 4875 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); 4876 4877 if (!AddRecord) return; // Don't care about REMOVE events 4878 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs 4879 4880 mDNS_StopQuery(m, question); 4881 question->ThisQInterval = -1; 4882 4883 if (answer->rrtype == kDNSType_SRV) 4884 { 4885 intf->SPSPort[sps] = answer->rdata->u.srv.port; 4886 AssignDomainName(&question->qname, &answer->rdata->u.srv.target); 4887 question->qtype = kDNSType_AAAA; 4888 mDNS_StartQuery(m, question); 4889 } 4890 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) 4891 { 4892 intf->SPSAddr[sps].type = mDNSAddrType_IPv6; 4893 intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; 4894 mDNS_Lock(m); 4895 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 4896 mDNS_Unlock(m); 4897 } 4898 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) // If negative answer for IPv6, look for IPv4 addresses instead 4899 { 4900 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); 4901 question->qtype = kDNSType_A; 4902 mDNS_StartQuery(m, question); 4903 } 4904 else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) 4905 { 4906 intf->SPSAddr[sps].type = mDNSAddrType_IPv4; 4907 intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; 4908 mDNS_Lock(m); 4909 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now 4910 mDNS_Unlock(m); 4911 } 4912 } 4913 4914mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) 4915 { 4916 AuthRecord *rr; 4917 for (rr = m->ResourceRecords; rr; rr=rr->next) 4918 if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) 4919 return mDNStrue; 4920 return mDNSfalse; 4921 } 4922 4923// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep 4924mDNSlocal void BeginSleepProcessing(mDNS *const m) 4925 { 4926 const CacheRecord *sps[3] = { mDNSNULL }; 4927 4928 m->NextScheduledSPRetry = m->timenow; 4929 4930 if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); 4931 else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); 4932 else // If we have at least one advertised service 4933 { 4934 NetworkInterfaceInfo *intf; 4935 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 4936 { 4937 if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); 4938 else 4939 { 4940 FindSPSInCache(m, &intf->NetWakeBrowse, sps); 4941 if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval); 4942 else 4943 { 4944 int i; 4945 intf->NextSPSAttempt = 0; 4946 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; 4947 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above 4948 for (i=0; i<3; i++) 4949 { 4950#if ForceAlerts 4951 if (intf->SPSAddr[i].type) 4952 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } 4953 if (intf->NetWakeResolve[i].ThisQInterval >= 0) 4954 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } 4955#endif 4956 intf->SPSAddr[i].type = mDNSAddrType_None; 4957 if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); 4958 intf->NetWakeResolve[i].ThisQInterval = -1; 4959 if (sps[i]) 4960 { 4961 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); 4962 mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); 4963 intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; 4964 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); 4965 } 4966 } 4967 } 4968 } 4969 } 4970 } 4971 4972 if (!sps[0]) // If we didn't find even one Sleep Proxy 4973 { 4974 AuthRecord *rr; 4975 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); 4976 m->SleepState = SleepState_Sleeping; 4977 4978#ifndef UNICAST_DISABLED 4979 SleepServiceRegistrations(m); 4980 SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records 4981#endif 4982 4983 // Mark all the records we need to deregister and send them 4984 for (rr = m->ResourceRecords; rr; rr=rr->next) 4985 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) 4986 rr->ImmedAnswer = mDNSInterfaceMark; 4987 SendResponses(m); 4988 } 4989 } 4990 4991// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. 4992// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. 4993// Normally, the platform support layer below mDNSCore should call this, not the client layer above. 4994mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) 4995 { 4996 AuthRecord *rr; 4997 4998 mDNS_Lock(m); 4999 5000 LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); 5001 5002 if (sleep && !m->SleepState) // Going to sleep 5003 { 5004 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server 5005 if (m->SPSSocket) 5006 { 5007 mDNSu8 oldstate = m->SPSState; 5008 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here 5009 m->SPSState = 2; 5010 if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); 5011 mDNS_ReclaimLockAfterCallback(); 5012 } 5013 5014 m->SleepState = SleepState_Transferring; 5015 if (m->SystemWakeOnLANEnabled && m->DelaySleep) 5016 { 5017 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep 5018 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); 5019 m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10; 5020 } 5021 else 5022 { 5023 m->DelaySleep = 0; 5024 m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10; 5025 BeginSleepProcessing(m); 5026 } 5027 5028#ifndef UNICAST_DISABLED 5029 SuspendLLQs(m); 5030#endif 5031 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, 5032 m->SleepState == SleepState_Transferring ? "Transferring" : 5033 m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); 5034 } 5035 else if (!sleep) // Waking up 5036 { 5037 mDNSu32 slot; 5038 CacheGroup *cg; 5039 CacheRecord *cr; 5040 NetworkInterfaceInfo *intf; 5041 5042 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness 5043 if (m->SleepState != SleepState_Awake) 5044 { 5045 m->SleepState = SleepState_Awake; 5046 m->SleepSeqNum++; 5047 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) 5048 // then we enforce a minimum delay of 16 seconds before we begin sleep processing. 5049 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., 5050 // before we make our determination of whether there's a Sleep Proxy out there we should register with. 5051 m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); 5052 } 5053 5054 if (m->SPSState == 3) 5055 { 5056 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here 5057 m->SPSState = 0; 5058 mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); 5059 mDNS_ReclaimLockAfterCallback(); 5060 } 5061 5062 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, 5063 // on wake we go through our record list and clear updateid back to zero 5064 for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; 5065 5066 // ... and the same for NextSPSAttempt 5067 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; 5068 5069 // Restart unicast and multicast queries 5070 mDNSCoreRestartQueries(m); 5071 5072 // and reactivtate service registrations 5073 m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); 5074 LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate); 5075 5076 // 2. Re-validate our cache records 5077 m->NextCacheCheck = m->timenow; 5078 FORALL_CACHERECORDS(slot, cg, cr) 5079 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); 5080 5081 // 3. Retrigger probing and announcing for all our authoritative records 5082 for (rr = m->ResourceRecords; rr; rr=rr->next) 5083 if (AuthRecord_uDNS(rr)) 5084 { 5085 ActivateUnicastRegistration(m, rr); 5086 } 5087 else 5088 { 5089 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 5090 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 5091 rr->AnnounceCount = InitialAnnounceCount; 5092 InitializeLastAPTime(m, rr); 5093 } 5094 5095 // 4. Refresh NAT mappings 5096 // We don't want to have to assume that all hardware can necessarily keep accurate 5097 // track of passage of time while asleep, so on wake we refresh our NAT mappings 5098 m->retryIntervalGetAddr = NATMAP_INIT_RETRY; 5099 m->retryGetAddr = m->timenow; 5100 RecreateNATMappings(m); 5101 } 5102 5103 mDNS_Unlock(m); 5104 } 5105 5106mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m) 5107 { 5108 DNSQuestion *q; 5109 AuthRecord *rr; 5110 ServiceRecordSet *srs; 5111 NetworkInterfaceInfo *intf; 5112 5113 mDNS_Lock(m); 5114 5115 if (m->NextScheduledSPRetry - m->timenow > 0) goto notready; 5116 5117 m->NextScheduledSPRetry = m->timenow + 0x40000000UL; 5118 5119 if (m->DelaySleep) goto notready; 5120 5121 // See if we might need to retransmit any lost Sleep Proxy Registrations 5122 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5123 if (intf->NextSPSAttempt >= 0) 5124 { 5125 if (m->timenow - intf->NextSPSAttemptTime >= 0) 5126 { 5127 LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt); 5128 SendSPSRegistration(m, intf, zeroID); 5129 } 5130 else 5131 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) 5132 m->NextScheduledSPRetry = intf->NextSPSAttemptTime; 5133 } 5134 5135 // Scan list of private LLQs, and make sure they've all completed their handshake with the server 5136 for (q = m->Questions; q; q = q->next) 5137 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) 5138 { 5139 LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 5140 goto notready; 5141 } 5142 5143 // Scan list of interfaces 5144 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) 5145 if (intf->NetWakeResolve[0].ThisQInterval >= 0) 5146 { 5147 LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); 5148 goto notready; 5149 } 5150 5151 // Scan list of registered records 5152 for (rr = m->ResourceRecords; rr; rr = rr->next) 5153 { 5154 if (AuthRecord_uDNS(rr)) 5155 { 5156 if (rr->state == regState_Refresh && rr->tcp) 5157 { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } 5158 } 5159 else 5160 { 5161 if (!mDNSOpaque16IsZero(rr->updateid)) 5162 { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } 5163 } 5164 } 5165 5166 // Scan list of registered services 5167 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) 5168 if (srs->state == regState_NoTarget && srs->tcp) goto notready; 5169 5170 mDNS_Unlock(m); 5171 return mDNStrue; 5172 5173notready: 5174 mDNS_Unlock(m); 5175 return mDNSfalse; 5176 } 5177 5178mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) 5179 { 5180 AuthRecord *ar; 5181 5182 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other 5183 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. 5184 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, 5185 // and if that happens we don't want to just give up and go back to sleep and never try again. 5186 mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes 5187 5188 NATTraversalInfo *nat; 5189 for (nat = m->NATTraversals; nat; nat=nat->next) 5190 if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) 5191 { 5192 mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time 5193 if (e - t > 0) e = t; 5194 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", 5195 nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", 5196 mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, 5197 nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, 5198 nat->retryInterval / mDNSPlatformOneSecond, 5199 nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, 5200 (t - now) / mDNSPlatformOneSecond); 5201 } 5202 5203 // This loop checks both the time we need to renew wide-area registrations, 5204 // and the time we need to renew Sleep Proxy registrations 5205 for (ar = m->ResourceRecords; ar; ar = ar->next) 5206 if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) 5207 { 5208 mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time 5209 if (e - t > 0) e = t; 5210 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", 5211 ar, ar->ThisAPInterval / mDNSPlatformOneSecond, 5212 (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, 5213 ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, 5214 (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); 5215 } 5216 5217 return(e - now); 5218 } 5219 5220// *************************************************************************** 5221#if COMPILER_LIKES_PRAGMA_MARK 5222#pragma mark - 5223#pragma mark - Packet Reception Functions 5224#endif 5225 5226#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) 5227 5228mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, 5229 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) 5230 { 5231 mDNSu8 *responseptr = response->data; 5232 const mDNSu8 *const limit = response->data + sizeof(response->data); 5233 const mDNSu8 *ptr = query->data; 5234 AuthRecord *rr; 5235 mDNSu32 maxttl = 0x70000000; 5236 int i; 5237 5238 // Initialize the response fields so we can answer the questions 5239 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags); 5240 5241 // *** 5242 // *** 1. Write out the list of questions we are actually going to answer with this packet 5243 // *** 5244 if (LegacyQuery) 5245 { 5246 maxttl = 10; 5247 for (i=0; i<query->h.numQuestions; i++) // For each question... 5248 { 5249 DNSQuestion q; 5250 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question... 5251 if (!ptr) return(mDNSNULL); 5252 5253 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers 5254 { 5255 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question 5256 { // then put the question in the question section 5257 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass); 5258 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); } 5259 break; // break out of the ResponseRecords loop, and go on to the next question 5260 } 5261 } 5262 } 5263 5264 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); } 5265 } 5266 5267 // *** 5268 // *** 2. Write Answers 5269 // *** 5270 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5271 if (rr->NR_AnswerTo) 5272 { 5273 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, 5274 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 5275 if (p) responseptr = p; 5276 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } 5277 } 5278 5279 // *** 5280 // *** 3. Write Additionals 5281 // *** 5282 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5283 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) 5284 { 5285 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, 5286 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); 5287 if (p) responseptr = p; 5288 else debugf("GenerateUnicastResponse: No more space for additionals"); 5289 } 5290 5291 return(responseptr); 5292 } 5293 5294// AuthRecord *our is our Resource Record 5295// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network 5296// Returns 0 if there is no conflict 5297// Returns +1 if there was a conflict and we won 5298// Returns -1 if there was a conflict and we lost and have to rename 5299mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) 5300 { 5301 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; 5302 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; 5303 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); } 5304 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); } 5305 5306 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec); 5307 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec); 5308 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; } 5309 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict 5310 5311 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost 5312 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won 5313 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost 5314 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won 5315 5316 LogMsg("CompareRData ERROR: Invalid state"); 5317 return(-1); 5318 } 5319 5320// See if we have an authoritative record that's identical to this packet record, 5321// whose canonical DependentOn record is the specified master record. 5322// The DependentOn pointer is typically used for the TXT record of service registrations 5323// It indicates that there is no inherent conflict detection for the TXT record 5324// -- it depends on the SRV record to resolve name conflicts 5325// If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn 5326// pointer chain (if any) to make sure we reach the canonical DependentOn record 5327// If the record has no DependentOn, then just return that record's pointer 5328// Returns NULL if we don't have any local RRs that are identical to the one from the packet 5329mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master) 5330 { 5331 const AuthRecord *r1; 5332 for (r1 = m->ResourceRecords; r1; r1=r1->next) 5333 { 5334 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 5335 { 5336 const AuthRecord *r2 = r1; 5337 while (r2->DependentOn) r2 = r2->DependentOn; 5338 if (r2 == master) return(mDNStrue); 5339 } 5340 } 5341 for (r1 = m->DuplicateRecords; r1; r1=r1->next) 5342 { 5343 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec)) 5344 { 5345 const AuthRecord *r2 = r1; 5346 while (r2->DependentOn) r2 = r2->DependentOn; 5347 if (r2 == master) return(mDNStrue); 5348 } 5349 } 5350 return(mDNSfalse); 5351 } 5352 5353// Find the canonical RRSet pointer for this RR received in a packet. 5354// If we find any identical AuthRecord in our authoritative list, then follow its RRSet 5355// pointers (if any) to make sure we return the canonical member of this name/type/class 5356// Returns NULL if we don't have any local RRs that are identical to the one from the packet 5357mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr) 5358 { 5359 const AuthRecord *rr; 5360 for (rr = m->ResourceRecords; rr; rr=rr->next) 5361 { 5362 if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec)) 5363 { 5364 while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet; 5365 return(rr); 5366 } 5367 } 5368 return(mDNSNULL); 5369 } 5370 5371// PacketRRConflict is called when we've received an RR (pktrr) which has the same name 5372// as one of our records (our) but different rdata. 5373// 1. If our record is not a type that's supposed to be unique, we don't care. 5374// 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one. 5375// 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer 5376// points to our record, ignore this conflict (e.g. the packet record matches one of our 5377// TXT records, and that record is marked as dependent on 'our', its SRV record). 5378// 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record 5379// are members of the same RRSet, then this is not a conflict. 5380mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr) 5381 { 5382 // If not supposed to be unique, not a conflict 5383 if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse); 5384 5385 // If a dependent record, not a conflict 5386 if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse); 5387 else 5388 { 5389 // If the pktrr matches a member of ourset, not a conflict 5390 const AuthRecord *ourset = our->RRSet ? our->RRSet : our; 5391 const AuthRecord *pktset = FindRRSet(m, pktrr); 5392 if (pktset == ourset) return(mDNSfalse); 5393 5394 // For records we're proxying, where we don't know the full 5395 // relationship between the records, having any matching record 5396 // in our AuthRecords list is sufficient evidence of non-conflict 5397 if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse); 5398 } 5399 5400 // Okay, this is a conflict 5401 return(mDNStrue); 5402 } 5403 5404// Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change 5405// the record list and/or question list. 5406// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 5407mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 5408 DNSQuestion *q, AuthRecord *our) 5409 { 5410 int i; 5411 const mDNSu8 *ptr = LocateAuthorities(query, end); 5412 mDNSBool FoundUpdate = mDNSfalse; 5413 5414 for (i = 0; i < query->h.numAuthorities; i++) 5415 { 5416 ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 5417 if (!ptr) break; 5418 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 5419 { 5420 FoundUpdate = mDNStrue; 5421 if (PacketRRConflict(m, our, &m->rec.r)) 5422 { 5423 int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass; 5424 if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; 5425 if (!result) result = CompareRData(our, &m->rec.r); 5426 if (result) 5427 { 5428 const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: "; 5429 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 5430 LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our)); 5431 } 5432 // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network. 5433 // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again. 5434 // If there really is another live host out there with the same name, it will answer our probes and we'll then rename. 5435 if (result < 0) 5436 { 5437 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond); 5438 our->ProbeCount = DefaultProbeCountForTypeUnique; 5439 our->AnnounceCount = InitialAnnounceCount; 5440 InitializeLastAPTime(m, our); 5441 goto exit; 5442 } 5443 } 5444#if 0 5445 else 5446 { 5447 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 5448 LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our->resrec.rdatahash, ARDisplayString(m, our)); 5449 } 5450#endif 5451 } 5452 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5453 } 5454 if (!FoundUpdate) 5455 LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); 5456exit: 5457 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5458 } 5459 5460mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr) 5461 { 5462 mDNSu32 slot = HashSlot(pktrr->name); 5463 CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); 5464 CacheRecord *rr; 5465 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 5466 if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break; 5467 return(rr); 5468 } 5469 5470// Called from ProcessQuery when we get an mDNS packet with an owner record in it 5471mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist) 5472 { 5473 m->CurrentRecord = thelist; 5474 while (m->CurrentRecord) 5475 { 5476 AuthRecord *const rr = m->CurrentRecord; 5477 if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC)) 5478 if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60) 5479 { 5480 LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s", 5481 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr)); 5482 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 5483 SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID); 5484 } 5485 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, 5486 // because the list may have been changed in that call. 5487 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 5488 m->CurrentRecord = rr->next; 5489 } 5490 } 5491 5492// ProcessQuery examines a received query to see if we have any answers to give 5493mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, 5494 const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, 5495 mDNSBool QueryWasLocalUnicast, DNSMessage *const response) 5496 { 5497 mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr); 5498 AuthRecord *ResponseRecords = mDNSNULL; 5499 AuthRecord **nrp = &ResponseRecords; 5500 CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated 5501 CacheRecord **eap = &ExpectedAnswers; 5502 DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet 5503 DNSQuestion **dqp = &DupQuestions; 5504 mDNSs32 delayresponse = 0; 5505 mDNSBool SendLegacyResponse = mDNSfalse; 5506 const mDNSu8 *ptr; 5507 mDNSu8 *responseptr = mDNSNULL; 5508 AuthRecord *rr; 5509 int i; 5510 5511 // *** 5512 // *** 1. Look in Additional Section for an OPT record 5513 // *** 5514 ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space); 5515 if (ptr) 5516 { 5517 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec); 5518 if (m->rec.r.resrec.rrtype == kDNSType_OPT) 5519 { 5520 const rdataOPT *opt; 5521 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 5522 // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently 5523 // delete all our own AuthRecords (which are identified by having zero MAC tags on them). 5524 for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++) 5525 if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0]) 5526 { 5527 ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords); 5528 ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords); 5529 } 5530 } 5531 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5532 } 5533 5534 // *** 5535 // *** 2. Parse Question Section and mark potential answers 5536 // *** 5537 ptr = query->data; 5538 for (i=0; i<query->h.numQuestions; i++) // For each question... 5539 { 5540 mDNSBool QuestionNeedsMulticastResponse; 5541 int NumAnswersForThisQuestion = 0; 5542 AuthRecord *NSECAnswer = mDNSNULL; 5543 DNSQuestion pktq, *q; 5544 ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question... 5545 if (!ptr) goto exit; 5546 5547 // The only queries that *need* a multicast response are: 5548 // * Queries sent via multicast 5549 // * from port 5353 5550 // * that don't have the kDNSQClass_UnicastResponse bit set 5551 // These queries need multicast responses because other clients will: 5552 // * suppress their own identical questions when they see these questions, and 5553 // * expire their cache records if they don't see the expected responses 5554 // For other queries, we may still choose to send the occasional multicast response anyway, 5555 // to keep our neighbours caches warm, and for ongoing conflict detection. 5556 QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse); 5557 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later 5558 pktq.qclass &= ~kDNSQClass_UnicastResponse; 5559 5560 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe 5561 // can result in user callbacks which may change the record list and/or question list. 5562 // Also note: we just mark potential answer records here, without trying to build the 5563 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records 5564 // from that list while we're in the middle of trying to build it. 5565 if (m->CurrentRecord) 5566 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 5567 m->CurrentRecord = m->ResourceRecords; 5568 while (m->CurrentRecord) 5569 { 5570 rr = m->CurrentRecord; 5571 m->CurrentRecord = rr->next; 5572 if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery)) 5573 { 5574 if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype)) 5575 { 5576 if (rr->resrec.RecordType == kDNSRecordTypeUnique) 5577 ResolveSimultaneousProbe(m, query, end, &pktq, rr); 5578 else if (ResourceRecordIsValidAnswer(rr)) 5579 { 5580 NumAnswersForThisQuestion++; 5581 // Note: We should check here if this is a probe-type query, and if so, generate an immediate 5582 // unicast answer back to the source, because timeliness in answering probes is important. 5583 5584 // Notes: 5585 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast) 5586 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead) 5587 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later) 5588 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set, 5589 // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link) 5590 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source) 5591 if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery)) 5592 { 5593 // We only mark this question for sending if it is at least one second since the last time we multicast it 5594 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. 5595 // This is to guard against the case where someone blasts us with queries as fast as they can. 5596 if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || 5597 (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) 5598 rr->NR_AnswerTo = (mDNSu8*)~0; 5599 } 5600 else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1; 5601 } 5602 } 5603 else if (rr->resrec.RecordType == kDNSRecordTypeVerified) 5604 { 5605 // If we don't have any answers for this question, but we do own another record with the same name, 5606 // then mark it to generate an NSEC record on this interface 5607 if (!NSECAnswer) NSECAnswer = rr; 5608 } 5609 } 5610 } 5611 5612 if (NumAnswersForThisQuestion == 0 && NSECAnswer) 5613 { 5614 NumAnswersForThisQuestion++; 5615 NSECAnswer->SendNSECNow = InterfaceID; 5616 m->NextScheduledResponse = m->timenow; 5617 } 5618 5619 // If we couldn't answer this question, someone else might be able to, 5620 // so use random delay on response to reduce collisions 5621 if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 5622 5623#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5624 if (QuestionNeedsMulticastResponse) 5625#else 5626 // We only do the following accelerated cache expiration and duplicate question suppression processing 5627 // for non-truncated multicast queries with multicast responses. 5628 // For any query generating a unicast response we don't do this because we can't assume we will see the response. 5629 // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent 5630 // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets. 5631 if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC)) 5632#endif 5633 { 5634 const mDNSu32 slot = HashSlot(&pktq.qname); 5635 CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); 5636 CacheRecord *cr; 5637 5638 // Make a list indicating which of our own cache records we expect to see updated as a result of this query 5639 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated 5640#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5641 if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 5642#endif 5643 for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) 5644 if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) 5645 if (!cr->NextInKAList && eap != &cr->NextInKAList) 5646 { 5647 *eap = cr; 5648 eap = &cr->NextInKAList; 5649#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5650 if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) 5651 { 5652 // Although MPUnansweredQ is only really used for multi-packet query processing, 5653 // we increment it for both single-packet and multi-packet queries, so that it stays in sync 5654 // with the MPUnansweredKA value, which by necessity is incremented for both query types. 5655 cr->MPUnansweredQ++; 5656 cr->MPLastUnansweredQT = m->timenow; 5657 cr->MPExpectingKA = mDNStrue; 5658 } 5659#endif 5660 } 5661 5662 // Check if this question is the same as any of mine. 5663 // We only do this for non-truncated queries. Right now it would be too complicated to try 5664 // to keep track of duplicate suppression state between multiple packets, especially when we 5665 // can't guarantee to receive all of the Known Answer packets that go with a particular query. 5666#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5667 if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 5668#endif 5669 for (q = m->Questions; q; q=q->next) 5670 if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4) 5671 if (!q->InterfaceID || q->InterfaceID == InterfaceID) 5672 if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList) 5673 if (q->qtype == pktq.qtype && 5674 q->qclass == pktq.qclass && 5675 q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname)) 5676 { *dqp = q; dqp = &q->NextInDQList; } 5677 } 5678 } 5679 5680 // *** 5681 // *** 3. Now we can safely build the list of marked answers 5682 // *** 5683 for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers 5684 if (rr->NR_AnswerTo) // If we marked the record... 5685 AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list 5686 5687 // *** 5688 // *** 4. Add additional records 5689 // *** 5690 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); 5691 5692 // *** 5693 // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list 5694 // *** 5695 for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section... 5696 { 5697 // Get the record... 5698 CacheRecord *ourcacherr; 5699 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec); 5700 if (!ptr) goto exit; 5701 5702 // See if this Known-Answer suppresses any of our currently planned answers 5703 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5704 if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 5705 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 5706 5707 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression) 5708 for (rr=m->ResourceRecords; rr; rr=rr->next) 5709 { 5710 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression 5711 if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr)) 5712 { 5713 if (srcaddr->type == mDNSAddrType_IPv4) 5714 { 5715 if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr; 5716 } 5717 else if (srcaddr->type == mDNSAddrType_IPv6) 5718 { 5719 if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr; 5720 } 5721 if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester)) 5722 { 5723 rr->ImmedAnswer = mDNSNULL; 5724 rr->ImmedUnicast = mDNSfalse; 5725#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5726 LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr)); 5727#endif 5728 } 5729 } 5730 } 5731 5732 ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); 5733 5734#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5735 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always, 5736 // 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). 5737 if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond) 5738 { 5739 ourcacherr->MPUnansweredKA++; 5740 ourcacherr->MPExpectingKA = mDNSfalse; 5741 } 5742#endif 5743 5744 // Having built our ExpectedAnswers list from the questions in this packet, we then remove 5745 // any records that are suppressed by the Known Answer list in this packet. 5746 eap = &ExpectedAnswers; 5747 while (*eap) 5748 { 5749 CacheRecord *cr = *eap; 5750 if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec)) 5751 { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; } 5752 else eap = &cr->NextInKAList; 5753 } 5754 5755 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query. 5756 if (!ourcacherr) 5757 { 5758 dqp = &DupQuestions; 5759 while (*dqp) 5760 { 5761 DNSQuestion *q = *dqp; 5762 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q)) 5763 { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; } 5764 else dqp = &q->NextInDQList; 5765 } 5766 } 5767 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5768 } 5769 5770 // *** 5771 // *** 6. Cancel any additionals that were added because of now-deleted records 5772 // *** 5773 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5774 if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo)) 5775 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } 5776 5777 // *** 5778 // *** 7. Mark the send flags on the records we plan to send 5779 // *** 5780 for (rr=ResponseRecords; rr; rr=rr->NextResponse) 5781 { 5782 if (rr->NR_AnswerTo) 5783 { 5784 mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response 5785 mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response) 5786 5787 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc. 5788 if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) 5789 { 5790 SendMulticastResponse = mDNStrue; 5791 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to 5792 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below). 5793 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value. 5794 if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0; 5795 } 5796 5797 // If the client insists on a multicast response, then we'd better send one 5798 if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue; 5799 else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue; 5800 else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue; 5801 5802 if (SendMulticastResponse || SendUnicastResponse) 5803 { 5804#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5805 rr->ImmedAnswerMarkTime = m->timenow; 5806#endif 5807 m->NextScheduledResponse = m->timenow; 5808 // If we're already planning to send this on another interface, just send it on all interfaces 5809 if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID) 5810 rr->ImmedAnswer = mDNSInterfaceMark; 5811 else 5812 { 5813 rr->ImmedAnswer = InterfaceID; // Record interface to send it on 5814 if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue; 5815 if (srcaddr->type == mDNSAddrType_IPv4) 5816 { 5817 if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4; 5818 else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr; 5819 } 5820 else if (srcaddr->type == mDNSAddrType_IPv6) 5821 { 5822 if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6; 5823 else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr; 5824 } 5825 } 5826 } 5827 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet, 5828 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11) 5829 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses 5830 // else, for a simple unique record reply, we can reply immediately; no need for delay 5831 if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms 5832 else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms 5833 } 5834 else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0) 5835 { 5836 // Since additional records are an optimization anyway, we only ever send them on one interface at a time 5837 // If two clients on different interfaces do queries that invoke the same optional additional answer, 5838 // then the earlier client is out of luck 5839 rr->ImmedAdditional = InterfaceID; 5840 // No need to set m->NextScheduledResponse here 5841 // We'll send these additional records when we send them, or not, as the case may be 5842 } 5843 } 5844 5845 // *** 5846 // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer 5847 // *** 5848 if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50)) 5849 { 5850#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5851 mDNSs32 oldss = m->SuppressSending; 5852 if (oldss && delayresponse) 5853 LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50); 5854#endif 5855 // Pick a random delay: 5856 // We start with the base delay chosen above (typically either 1 second or 20 seconds), 5857 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds). 5858 // This is an integer value, with resolution determined by the platform clock rate. 5859 // We then divide that by 50 to get the delay value in ticks. We defer the division until last 5860 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second). 5861 // The +49 before dividing is to ensure we round up, not down, to ensure that even 5862 // on platforms where the native clock rate is less than fifty ticks per second, 5863 // we still guarantee that the final calculated delay is at least one platform tick. 5864 // We want to make sure we don't ever allow the delay to be zero ticks, 5865 // because if that happens we'll fail the Bonjour Conformance Test. 5866 // Our final computed delay is 20-120ms for normal delayed replies, 5867 // or 400-500ms in the case of multi-packet known-answer lists. 5868 m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50; 5869 if (m->SuppressSending == 0) m->SuppressSending = 1; 5870#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES 5871 if (oldss && delayresponse) 5872 LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow); 5873#endif 5874 } 5875 5876 // *** 5877 // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too 5878 // *** 5879 if (SendLegacyResponse) 5880 responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords); 5881 5882exit: 5883 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 5884 5885 // *** 5886 // *** 10. Finally, clear our link chains ready for use next time 5887 // *** 5888 while (ResponseRecords) 5889 { 5890 rr = ResponseRecords; 5891 ResponseRecords = rr->NextResponse; 5892 rr->NextResponse = mDNSNULL; 5893 rr->NR_AnswerTo = mDNSNULL; 5894 rr->NR_AdditionalTo = mDNSNULL; 5895 } 5896 5897 while (ExpectedAnswers) 5898 { 5899 CacheRecord *cr = ExpectedAnswers; 5900 ExpectedAnswers = cr->NextInKAList; 5901 cr->NextInKAList = mDNSNULL; 5902 5903 // For non-truncated queries, we can definitively say that we should expect 5904 // to be seeing a response for any records still left in the ExpectedAnswers list 5905 if (!(query->h.flags.b[0] & kDNSFlag0_TC)) 5906 if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond) 5907 { 5908 cr->UnansweredQueries++; 5909 cr->LastUnansweredTime = m->timenow; 5910#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5911 if (cr->UnansweredQueries > 1) 5912 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", 5913 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 5914#endif 5915 SetNextCacheCheckTime(m, cr); 5916 } 5917 5918 // If we've seen multiple unanswered queries for this record, 5919 // then mark it to expire in five seconds if we don't get a response by then. 5920 if (cr->UnansweredQueries >= MaxUnansweredQueries) 5921 { 5922#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5923 // Only show debugging message if this record was not about to expire anyway 5924 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) 5925 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 5926 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 5927#endif 5928 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 5929 } 5930#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 5931 // Make a guess, based on the multi-packet query / known answer counts, whether we think we 5932 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for 5933 // possible packet loss of up to 20% of the additional KA packets.) 5934 else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8) 5935 { 5936 // We want to do this conservatively. 5937 // If there are so many machines on the network that they have to use multi-packet known-answer lists, 5938 // then we don't want them to all hit the network simultaneously with their final expiration queries. 5939 // By setting the record to expire in four minutes, we achieve two things: 5940 // (a) the 90-95% final expiration queries will be less bunched together 5941 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own 5942 mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4; 5943 if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond) 5944 remain = 240 * (mDNSu32)mDNSPlatformOneSecond; 5945 5946 // Only show debugging message if this record was not about to expire anyway 5947 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) 5948 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", 5949 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); 5950 5951 if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond) 5952 cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query 5953 cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics 5954 cr->MPUnansweredKA = 0; 5955 cr->MPExpectingKA = mDNSfalse; 5956 5957 if (remain < kDefaultReconfirmTimeForNoAnswer) 5958 remain = kDefaultReconfirmTimeForNoAnswer; 5959 mDNS_Reconfirm_internal(m, cr, remain); 5960 } 5961#endif 5962 } 5963 5964 while (DupQuestions) 5965 { 5966 DNSQuestion *q = DupQuestions; 5967 DupQuestions = q->NextInDQList; 5968 q->NextInDQList = mDNSNULL; 5969 i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type); 5970 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID, 5971 srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i); 5972 } 5973 5974 return(responseptr); 5975 } 5976 5977mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, 5978 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 5979 const mDNSInterfaceID InterfaceID) 5980 { 5981 mDNSu8 *responseend = mDNSNULL; 5982 mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr && 5983 !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr); 5984 5985 if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr)) 5986 { 5987 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 5988 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)", 5989 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 5990 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 5991 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 5992 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 5993 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); 5994 return; 5995 } 5996 5997 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 5998 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", 5999 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 6000 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 6001 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 6002 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 6003 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); 6004 6005 responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID, 6006 !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg); 6007 6008 if (responseend) // If responseend is non-null, that means we built a unicast response packet 6009 { 6010 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld", 6011 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", 6012 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", 6013 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", 6014 srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type); 6015 mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL); 6016 } 6017 } 6018 6019#if 0 6020mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr) 6021 { 6022 DNSServer *s; 6023 (void)m; // Unused 6024 (void)srcaddr; // Unused 6025 for (s = m->DNSServers; s; s = s->next) 6026 if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue); 6027 return(mDNSfalse); 6028 } 6029#endif 6030 6031struct UDPSocket_struct 6032 { 6033 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port 6034 }; 6035 6036mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question) 6037 { 6038 DNSQuestion *q; 6039 for (q = m->Questions; q; q=q->next) 6040 if (q->LocalSocket && 6041 mDNSSameIPPort (q->LocalSocket->port, port) && 6042 mDNSSameOpaque16(q->TargetQID, id) && 6043 q->qtype == question->qtype && 6044 q->qclass == question->qclass && 6045 q->qnamehash == question->qnamehash && 6046 SameDomainName(&q->qname, &question->qname)) 6047 return(q); 6048 return(mDNSNULL); 6049 } 6050 6051mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr) 6052 { 6053 DNSQuestion *q; 6054 (void)id; 6055 (void)srcaddr; 6056 for (q = m->Questions; q; q=q->next) 6057 if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q)) 6058 { 6059 if (!mDNSOpaque16IsZero(q->TargetQID)) 6060 { 6061 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr)); 6062 if (mDNSSameOpaque16(q->TargetQID, id)) 6063 { 6064 if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue); 6065 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue); 6066 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking 6067 // if (TrustedSource(m, srcaddr)) return(mDNStrue); 6068 LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s", 6069 q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr)); 6070 return(mDNSfalse); 6071 } 6072 } 6073 else 6074 { 6075 if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2)) 6076 return(mDNStrue); 6077 } 6078 } 6079 return(mDNSfalse); 6080 } 6081 6082// Certain data types need more space for in-memory storage than their in-packet rdlength would imply 6083// Currently this applies only to rdata types containing more than one domainname, 6084// or types where the domainname is not the last item in the structure. 6085// In addition, NSEC currently requires less space for in-memory storage than its in-packet representation. 6086mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr) 6087 { 6088 switch (rr->rrtype) 6089 { 6090 case kDNSType_SOA: return sizeof(rdataSOA); 6091 case kDNSType_RP: return sizeof(rdataRP); 6092 case kDNSType_PX: return sizeof(rdataPX); 6093 case kDNSType_NSEC:return sizeof(rdataNSEC); 6094 default: return rr->rdlength; 6095 } 6096 } 6097 6098mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg) 6099 { 6100 CacheRecord *rr = mDNSNULL; 6101 mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec); 6102 6103 if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r)); 6104 6105 //if (RDLength > InlineCacheRDSize) 6106 // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); 6107 6108 if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now 6109 if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg 6110 if (!rr) NoCacheAnswer(m, &m->rec.r); 6111 else 6112 { 6113 RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer 6114 *rr = m->rec.r; // Block copy the CacheRecord object 6115 rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment 6116 rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header 6117 6118 // If this is an oversized record with external storage allocated, copy rdata to external storage 6119 if (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize) 6120 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c); 6121 else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && RDLength <= InlineCacheRDSize) 6122 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c); 6123 if (RDLength > InlineCacheRDSize) 6124 mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength); 6125 6126 rr->next = mDNSNULL; // Clear 'next' pointer 6127 *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list 6128 cg->rrcache_tail = &(rr->next); // Advance tail pointer 6129 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) 6130 rr->DelayDelivery = NonZeroTime(m->timenow); 6131 else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique, 6132 rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have 6133 rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event 6134 else 6135 rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); 6136 6137 CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us 6138 } 6139 return(rr); 6140 } 6141 6142mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) 6143 { 6144 rr->TimeRcvd = m->timenow; 6145 rr->resrec.rroriginalttl = ttl; 6146 rr->UnansweredQueries = 0; 6147#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 6148 rr->MPUnansweredQ = 0; 6149 rr->MPUnansweredKA = 0; 6150 rr->MPExpectingKA = mDNSfalse; 6151#endif 6152 SetNextCacheCheckTime(m, rr); 6153 } 6154 6155mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease) 6156 { 6157 CacheRecord *rr; 6158 const mDNSu32 slot = HashSlot(&q->qname); 6159 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 6160 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 6161 if (rr->CRActiveQuestion == q) 6162 { 6163 //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr)); 6164 RefreshCacheRecord(m, rr, lease); 6165 } 6166 } 6167 6168mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds 6169 { 6170 if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease; 6171 else if (LLQType == uDNS_LLQ_Events) 6172 { 6173 // If the TTL is -1 for uDNS LLQ event packet, that means "remove" 6174 if (ttl == 0xFFFFFFFF) ttl = 0; 6175 else ttl = kLLQ_DefLease; 6176 } 6177 else // else not LLQ (standard uDNS response) 6178 { 6179 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we 6180 // also do this check here to make sure we can't get integer overflow below 6181 if (ttl > 0x8000000UL) ttl = 0x8000000UL; 6182 6183 // Adjustment factor to avoid race condition: 6184 // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100. 6185 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another 6186 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox. 6187 // To avoid this, we extend the record's effective TTL to give it a little extra grace period. 6188 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds, 6189 // the cached copy at our local caching server will already have expired, so the server will be forced 6190 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds. 6191 ttl += ttl/4 + 2; 6192 6193 // For mDNS, TTL zero means "delete this record" 6194 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it. 6195 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds. 6196 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry). 6197 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers. 6198 if (ttl < 15) ttl = 15; 6199 } 6200 6201 return ttl; 6202 } 6203 6204// Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change 6205// the record list and/or question list. 6206// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 6207// InterfaceID non-NULL tells us the interface this multicast response was received on 6208// InterfaceID NULL tells us this was a unicast response 6209// dstaddr NULL tells us we received this over an outgoing TCP connection we made 6210mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, 6211 const DNSMessage *const response, const mDNSu8 *end, 6212 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 6213 const mDNSInterfaceID InterfaceID) 6214 { 6215 int i; 6216 mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr); 6217 mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr); 6218 uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport); 6219 6220 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker 6221 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList 6222 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling. 6223 CacheRecord *CacheFlushRecords = (CacheRecord*)1; 6224 CacheRecord **cfp = &CacheFlushRecords; 6225 6226 // All records in a DNS response packet are treated as equally valid statements of truth. If we want 6227 // to guard against spoof responses, then the only credible protection against that is cryptographic 6228 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record 6229 int firstauthority = response->h.numAnswers; 6230 int firstadditional = firstauthority + response->h.numAuthorities; 6231 int totalrecords = firstadditional + response->h.numAdditionals; 6232 const mDNSu8 *ptr = response->data; 6233 6234 debugf("Received Response from %#-15a addressed to %#-15a on %p with " 6235 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d", 6236 srcaddr, dstaddr, InterfaceID, 6237 response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,", 6238 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", 6239 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", 6240 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType); 6241 6242 // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt> 6243 // When a DNS client receives a reply with TC 6244 // set, it should ignore that response, and query again, using a 6245 // mechanism, such as a TCP connection, that will permit larger replies. 6246 // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but 6247 // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing 6248 // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once. 6249 // <rdar://problem/6690034> Can't bind to Active Directory 6250 // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll 6251 // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache. 6252 // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already, 6253 // and not even do the TCP query. 6254 // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet. 6255 if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return; 6256 6257 if (LLQType == uDNS_LLQ_Ignore) return; 6258 6259 // 1. We ignore questions (if any) in mDNS response packets 6260 // 2. If this is an LLQ response, we handle it much the same 6261 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this 6262 // answer as being the authoritative complete RRSet, and respond by deleting all other 6263 // matching cache records that don't appear in this packet. 6264 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged 6265 if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC)) 6266 ptr = LocateAnswers(response, end); 6267 // Otherwise, for one-shot queries, any answers in our cache that are not also contained 6268 // in this response packet are immediately deemed to be invalid. 6269 else 6270 { 6271 mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask); 6272 mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth); 6273 mDNSBool returnEarly = mDNSfalse; 6274 // We could possibly combine this with the similar loop at the end of this function -- 6275 // instead of tagging cache records here and then rescuing them if we find them in the answer section, 6276 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in 6277 // which it was received (or refreshed), and then at the end if we find any cache records which 6278 // answer questions in this packet's question section, but which aren't tagged with this packet's 6279 // packet number, then we deduce they are old and delete them 6280 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) 6281 { 6282 DNSQuestion q, *qptr = mDNSNULL; 6283 ptr = getQuestion(response, ptr, end, InterfaceID, &q); 6284 if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))) 6285 { 6286 if (!failure) 6287 { 6288 CacheRecord *rr; 6289 const mDNSu32 slot = HashSlot(&q.qname); 6290 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); 6291 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 6292 if (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q)) 6293 { 6294 debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype), 6295 rr->resrec.InterfaceID, CRDisplayString(m, rr)); 6296 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm 6297 rr->TimeRcvd = m->timenow - TicksTTL(rr) - 1; 6298 rr->UnansweredQueries = MaxUnansweredQueries; 6299 } 6300 } 6301 else 6302 { 6303 if (qptr) 6304 { 6305 LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype)); 6306 PushDNSServerToEnd(m, qptr); 6307 } 6308 returnEarly = mDNStrue; 6309 } 6310 } 6311 } 6312 if (returnEarly) 6313 { 6314 LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s", 6315 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", 6316 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", 6317 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s"); 6318 // not goto exit because we won't have any CacheFlushRecords and we do not want to 6319 // generate negative cache entries (we want to query the next server) 6320 return; 6321 } 6322 } 6323 6324 for (i = 0; i < totalrecords && ptr && ptr < end; i++) 6325 { 6326 // All responses sent via LL multicast are acceptable for caching 6327 // All responses received over our outbound TCP connections are acceptable for caching 6328 mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType; 6329 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer 6330 // to any specific question -- any code reading records from the cache needs to make that determination for itself.) 6331 6332 const mDNSu8 RecordType = 6333 (i < firstauthority ) ? (mDNSu8)kDNSRecordTypePacketAns : 6334 (i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd; 6335 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec); 6336 if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting 6337 6338 // Don't want to cache OPT or TSIG pseudo-RRs 6339 if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG) 6340 { m->rec.r.resrec.RecordType = 0; continue; } 6341 6342 // When we receive uDNS LLQ responses, we assume a long cache lifetime -- 6343 // In the case of active LLQs, we'll get remove events when the records actually do go away 6344 // In the case of polling LLQs, we assume the record remains valid until the next poll 6345 if (!mDNSOpaque16IsZero(response->h.id)) 6346 m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl); 6347 6348 // If response was not sent via LL multicast, 6349 // then see if it answers a recent query of ours, which would also make it acceptable for caching. 6350 if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r); 6351 6352 // 1. Check that this packet resource record does not conflict with any of ours 6353 if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC) 6354 { 6355 if (m->CurrentRecord) 6356 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 6357 m->CurrentRecord = m->ResourceRecords; 6358 while (m->CurrentRecord) 6359 { 6360 AuthRecord *rr = m->CurrentRecord; 6361 m->CurrentRecord = rr->next; 6362 // We accept all multicast responses, and unicast responses resulting from queries we issued 6363 // For other unicast responses, this code accepts them only for responses with an 6364 // (apparently) local source address that pertain to a record of our own that's in probing state 6365 if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue; 6366 6367 if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match... 6368 { 6369 // ... check to see if type and rdata are identical 6370 if (IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec)) 6371 { 6372 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us 6373 if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState) 6374 { 6375 // If we were planning to send on this -- and only this -- interface, then we don't need to any more 6376 if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; } 6377 } 6378 else 6379 { 6380 if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; } 6381 else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 6382 } 6383 } 6384 // else, the packet RR has different type or different rdata -- check to see if this is a conflict 6385 else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r)) 6386 { 6387 LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); 6388 LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); 6389 6390 // If this record is marked DependentOn another record for conflict detection purposes, 6391 // then *that* record has to be bumped back to probing state to resolve the conflict 6392 if (rr->DependentOn) 6393 { 6394 while (rr->DependentOn) rr = rr->DependentOn; 6395 LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); 6396 } 6397 6398 // If we've just whacked this record's ProbeCount, don't need to do it again 6399 if (rr->ProbeCount > DefaultProbeCountForTypeUnique) 6400 LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr)); 6401 else if (rr->ProbeCount == DefaultProbeCountForTypeUnique) 6402 LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr)); 6403 else 6404 { 6405 LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r)); 6406 // If we'd previously verified this record, put it back to probing state and try again 6407 if (rr->resrec.RecordType == kDNSRecordTypeVerified) 6408 { 6409 LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m, rr)); 6410 rr->resrec.RecordType = kDNSRecordTypeUnique; 6411 // We set ProbeCount to one more than the usual value so we know we've already touched this record. 6412 // This is because our single probe for "example-name.local" could yield a response with (say) two A records and 6413 // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts. 6414 // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries(). 6415 rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; 6416 rr->AnnounceCount = InitialAnnounceCount; 6417 InitializeLastAPTime(m, rr); 6418 RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate 6419 } 6420 // If we're probing for this record, we just failed 6421 else if (rr->resrec.RecordType == kDNSRecordTypeUnique) 6422 { 6423 LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr)); 6424 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 6425 } 6426 // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving 6427 // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it. 6428 else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) 6429 { 6430 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr)); 6431 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); 6432 } 6433 else 6434 LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); 6435 } 6436 } 6437 // Else, matching signature, different type or rdata, but not a considered a conflict. 6438 // If the packet record has the cache-flush bit set, then we check to see if we 6439 // have any record(s) of the same type that we should re-assert to rescue them 6440 // (see note about "multi-homing and bridged networks" at the end of this function). 6441 else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype) 6442 if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2) 6443 { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } 6444 } 6445 } 6446 } 6447 6448 if (!AcceptableResponse) 6449 { 6450 const CacheRecord *cr; 6451 for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList) 6452 { 6453 domainname *target = GetRRDomainNameTarget(&cr->resrec); 6454 if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name)) 6455 { AcceptableResponse = mDNStrue; break; } 6456 } 6457 } 6458 6459 // 2. See if we want to add this packet resource record to our cache 6460 // We only try to cache answers if we have a cache to put them in 6461 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query 6462 if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r)); 6463 if (m->rrcache_size && AcceptableResponse) 6464 { 6465 const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); 6466 CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); 6467 CacheRecord *rr; 6468 6469 // 2a. Check if this packet resource record is already in our cache 6470 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 6471 { 6472 // If we found this exact resource record, refresh its TTL 6473 if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec)) 6474 { 6475 if (m->rec.r.resrec.rdlength > InlineCacheRDSize) 6476 verbosedebugf("Found record size %5d interface %p already in cache: %s", 6477 m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r)); 6478 rr->TimeRcvd = m->timenow; 6479 6480 if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) 6481 { 6482 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list 6483 if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events) 6484 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 6485 6486 // If this packet record is marked unique, and our previous cached copy was not, then fix it 6487 if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) 6488 { 6489 DNSQuestion *q; 6490 for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++; 6491 rr->resrec.RecordType = m->rec.r.resrec.RecordType; 6492 } 6493 } 6494 6495 if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength)) 6496 { 6497 // If the rdata of the packet record differs in name capitalization from the record in our cache 6498 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get 6499 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one. 6500 rr->resrec.rroriginalttl = 0; 6501 rr->UnansweredQueries = MaxUnansweredQueries; 6502 SetNextCacheCheckTime(m, rr); 6503 // DO NOT break out here -- we want to continue as if we never found it 6504 } 6505 else if (m->rec.r.resrec.rroriginalttl > 0) 6506 { 6507 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr)); 6508 RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl); 6509 break; 6510 } 6511 else 6512 { 6513 // If the packet TTL is zero, that means we're deleting this record. 6514 // To give other hosts on the network a chance to protest, we push the deletion 6515 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries. 6516 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent 6517 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth. 6518 debugf("DE for %s", CRDisplayString(m, rr)); 6519 rr->resrec.rroriginalttl = 1; 6520 rr->UnansweredQueries = MaxUnansweredQueries; 6521 SetNextCacheCheckTime(m, rr); 6522 break; 6523 } 6524 } 6525 } 6526 6527 // If packet resource record not in our cache, add it now 6528 // (unless it is just a deletion of a record we never had, in which case we don't care) 6529 if (!rr && m->rec.r.resrec.rroriginalttl > 0) 6530 { 6531 rr = CreateNewCacheEntry(m, slot, cg); 6532 if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events) 6533 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } 6534 } 6535 } 6536 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6537 } 6538 6539exit: 6540 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6541 6542 // If we've just received one or more records with their cache flush bits set, 6543 // then scan that cache slot to see if there are any old stale records we need to flush 6544 while (CacheFlushRecords != (CacheRecord*)1) 6545 { 6546 CacheRecord *r1 = CacheFlushRecords, *r2; 6547 const mDNSu32 slot = HashSlot(r1->resrec.name); 6548 const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); 6549 CacheFlushRecords = CacheFlushRecords->NextInCFList; 6550 r1->NextInCFList = mDNSNULL; 6551 6552 // Look for records in the cache with the same signature as this new one with the cache flush 6553 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL 6554 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second. 6555 // We make these TTL adjustments *only* for records that still have *more* than one second 6556 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago 6557 // (and now has half a second remaining) could inadvertently get its life extended, by either 6558 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered 6559 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet, 6560 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire 6561 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it. 6562 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely. 6563 // To avoid this, we need to ensure that the cache flushing operation will only act to 6564 // *decrease* a record's remaining lifetime, never *increase* it. 6565 for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) 6566 if (r1->resrec.InterfaceID == r2->resrec.InterfaceID && 6567 r1->resrec.rrtype == r2->resrec.rrtype && 6568 r1->resrec.rrclass == r2->resrec.rrclass) 6569 { 6570 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) 6571 // else, if record is old, mark it to be flushed 6572 if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) 6573 { 6574 // If we find mismatched TTLs in an RRSet, correct them. 6575 // We only do this for records with a TTL of 2 or higher. It's possible to have a 6576 // goodbye announcement with the cache flush bit set (or a case change on record rdata, 6577 // which we treat as a goodbye followed by an addition) and in that case it would be 6578 // inappropriate to synchronize all the other records to a TTL of 0 (or 1). 6579 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT, 6580 // because certain early Bonjour devices are known to have this specific mismatch, and 6581 // there's no point filling syslog with messages about something we already know about. 6582 // We also don't log this for uDNS responses, since a caching name server is obliged 6583 // to give us an aged TTL to correct for how long it has held the record, 6584 // so our received TTLs are expected to vary in that case 6585 if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) 6586 { 6587 if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) && 6588 mDNSOpaque16IsZero(response->h.id)) 6589 LogInfo("Correcting TTL from %4d to %4d for %s", 6590 r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); 6591 r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; 6592 } 6593 r2->TimeRcvd = m->timenow; 6594 } 6595 else // else, if record is old, mark it to be flushed 6596 { 6597 verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2)); 6598 // We set stale records to expire in one second. 6599 // This gives the owner a chance to rescue it if necessary. 6600 // This is important in the case of multi-homing and bridged networks: 6601 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be 6602 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit 6603 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet 6604 // will promptly delete their cached copies of the (still valid) Ethernet IP address record. 6605 // By delaying the deletion by one second, we give X a change to notice that this bridging has 6606 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches. 6607 6608 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary 6609 // final expiration queries for this record. 6610 6611 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache 6612 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual 6613 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates. 6614 if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries) 6615 { 6616 debugf("Cache flush for DE record %s", CRDisplayString(m, r2)); 6617 r2->resrec.rroriginalttl = 0; 6618 m->NextCacheCheck = m->timenow; 6619 m->NextScheduledEvent = m->timenow; 6620 } 6621 else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) 6622 { 6623 // We only set a record to expire in one second if it currently has *more* than a second to live 6624 // If it's already due to expire in a second or less, we just leave it alone 6625 r2->resrec.rroriginalttl = 1; 6626 r2->UnansweredQueries = MaxUnansweredQueries; 6627 r2->TimeRcvd = m->timenow - 1; 6628 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records 6629 // that we marked for deletion via an explicit DE record 6630 } 6631 } 6632 SetNextCacheCheckTime(m, r2); 6633 } 6634 if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to 6635 { 6636 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared 6637 r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot); 6638 if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); 6639 } 6640 } 6641 6642 // See if we need to generate negative cache entries for unanswered unicast questions 6643 ptr = response->data; 6644 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) 6645 { 6646 DNSQuestion q; 6647 ptr = getQuestion(response, ptr, end, InterfaceID, &q); 6648 if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))) 6649 { 6650 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft 6651 // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers. 6652 // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up 6653 // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist). 6654 // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we 6655 // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache. 6656 // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're 6657 // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not 6658 // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache 6659 // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-) 6660 if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname)) 6661 LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 6662 else 6663 { 6664 CacheRecord *rr, *neg = mDNSNULL; 6665 mDNSu32 slot = HashSlot(&q.qname); 6666 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); 6667 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 6668 if (SameNameRecordAnswersQuestion(&rr->resrec, &q)) 6669 { 6670 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry 6671 if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break; 6672 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one 6673 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr; 6674 } 6675 6676 if (!rr) 6677 { 6678 // We start off assuming a negative caching TTL of 60 seconds 6679 // but then look to see if we can find an SOA authority record to tell us a better value we should be using 6680 mDNSu32 negttl = 60; 6681 int repeat = 0; 6682 const domainname *name = &q.qname; 6683 mDNSu32 hash = q.qnamehash; 6684 6685 // Special case for our special Microsoft Active Directory "local SOA" check. 6686 // Some cheap home gateways don't include an SOA record in the authority section when 6687 // they send negative responses, so we don't know how long to cache the negative result. 6688 // Because we don't want to keep hitting the root name servers with our query to find 6689 // if we're on a network using Microsoft Active Directory using "local" as a private 6690 // internal top-level domain, we make sure to cache the negative result for at least one day. 6691 if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24; 6692 6693 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record 6694 if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL) 6695 { 6696 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 6697 if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA) 6698 { 6699 const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data; 6700 mDNSu32 ttl_s = soa->min; 6701 // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except* 6702 // for the SOA record for ".", where the record is reported as non-cacheable 6703 // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is 6704 if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0]) 6705 ttl_s = m->rec.r.resrec.rroriginalttl; 6706 if (negttl < ttl_s) negttl = ttl_s; 6707 6708 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer, 6709 // with an Authority Section SOA record for d.com, then this is a hint that the authority 6710 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either. 6711 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us 6712 if (q.qtype == kDNSType_SOA) 6713 { 6714 int qcount = CountLabels(&q.qname); 6715 int scount = CountLabels(m->rec.r.resrec.name); 6716 if (qcount - 1 > scount) 6717 if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name)) 6718 repeat = qcount - 1 - scount; 6719 } 6720 } 6721 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6722 } 6723 6724 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid 6725 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query), 6726 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL 6727 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist. 6728 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour), 6729 // so that we back off our polling rate and don't keep hitting the server continually. 6730 if (neg) 6731 { 6732 if (negttl < neg->resrec.rroriginalttl * 2) 6733 negttl = neg->resrec.rroriginalttl * 2; 6734 if (negttl > 3600) 6735 negttl = 3600; 6736 } 6737 6738 negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary 6739 6740 // If we already had a negative cache entry just update it, else make one or more new negative cache entries 6741 if (neg) 6742 { 6743 debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); 6744 RefreshCacheRecord(m, neg, negttl); 6745 } 6746 else while (1) 6747 { 6748 debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype)); 6749 MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any); 6750 CreateNewCacheEntry(m, slot, cg); 6751 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6752 if (!repeat) break; 6753 repeat--; 6754 name = (const domainname *)(name->c + 1 + name->c[0]); 6755 hash = DomainNameHashValue(name); 6756 slot = HashSlot(name); 6757 cg = CacheGroupForName(m, slot, hash, name); 6758 } 6759 } 6760 } 6761 } 6762 } 6763 } 6764 6765mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result) 6766 { 6767 if (result && result != mStatus_MemFree) 6768 LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar)); 6769 6770 if (result == mStatus_NameConflict) 6771 { 6772 LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", 6773 InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar)); 6774 SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password); 6775 } 6776 else if (result == mStatus_MemFree) 6777 { 6778 m->ProxyRecords--; 6779 mDNSPlatformMemFree(ar); 6780 } 6781 } 6782 6783mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m, 6784 const DNSMessage *const msg, const mDNSu8 *end, 6785 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, 6786 const mDNSInterfaceID InterfaceID) 6787 { 6788 int i; 6789 AuthRecord opt; 6790 mDNSu8 *p = m->omsg.data; 6791 OwnerOptData owner; 6792 mDNSu32 updatelease = 0; 6793 const mDNSu8 *ptr; 6794 6795 LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " 6796 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", 6797 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, 6798 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", 6799 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", 6800 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", 6801 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); 6802 6803 if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return; 6804 6805 if (mDNS_PacketLoggingEnabled) 6806 DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); 6807 6808 ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space); 6809 if (ptr) 6810 { 6811 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 6812 if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT) 6813 { 6814 const rdataOPT *o; 6815 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 6816 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 6817 { 6818 if (o->opt == kDNSOpt_Lease) updatelease = o->u.updatelease; 6819 else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner = o->u.owner; 6820 } 6821 } 6822 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6823 } 6824 6825 InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags); 6826 6827 if (!updatelease || !owner.HMAC.l[0]) 6828 { 6829 static int msgs = 0; 6830 if (msgs < 100) 6831 { 6832 msgs++; 6833 LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport), 6834 !updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : ""); 6835 } 6836 m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr; 6837 } 6838 else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS) 6839 { 6840 static int msgs = 0; 6841 if (msgs < 100) 6842 { 6843 msgs++; 6844 LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport), 6845 m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS); 6846 } 6847 m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; 6848 } 6849 else 6850 { 6851 LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq); 6852 6853 if (updatelease > 24 * 60 * 60) 6854 updatelease = 24 * 60 * 60; 6855 6856 if (updatelease > 0x40000000UL / mDNSPlatformOneSecond) 6857 updatelease = 0x40000000UL / mDNSPlatformOneSecond; 6858 6859 ptr = LocateAuthorities(msg, end); 6860 for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++) 6861 { 6862 ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); 6863 if (ptr) 6864 { 6865 mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec); 6866 AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem); 6867 if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; } 6868 else 6869 { 6870 mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared; 6871 m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet; 6872 mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar); 6873 AssignDomainName(&ar->namestorage, m->rec.r.resrec.name); 6874 ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse); 6875 ar->resrec.rdata->MaxRDLength = RDLengthMem; 6876 mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem); 6877 ar->WakeUp = owner; 6878 if (m->rec.r.resrec.rrtype == kDNSType_PTR) 6879 { 6880 mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name); 6881 if (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name); 6882 else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name); 6883 debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar)); 6884 if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID); 6885 } 6886 ar->TimeRcvd = m->timenow; 6887 ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond; 6888 if (m->NextScheduledSPS - ar->TimeExpire > 0) 6889 m->NextScheduledSPS = ar->TimeExpire; 6890 mDNS_Register_internal(m, ar); 6891 // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients 6892 if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0; 6893 m->ProxyRecords++; 6894 LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar)); 6895 } 6896 } 6897 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6898 } 6899 6900 if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask) 6901 { 6902 LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport)); 6903 ClearProxyRecords(m, &owner, m->DuplicateRecords); 6904 ClearProxyRecords(m, &owner, m->ResourceRecords); 6905 } 6906 else 6907 { 6908 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 6909 opt.resrec.rrclass = NormalMaxDNSMessageData; 6910 opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record 6911 opt.resrec.rdestimate = sizeof(rdataOPT); 6912 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; 6913 opt.resrec.rdata->u.opt[0].u.updatelease = updatelease; 6914 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); 6915 } 6916 } 6917 6918 if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL); 6919 } 6920 6921mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID) 6922 { 6923 if (InterfaceID) 6924 { 6925 AuthRecord *rr; 6926 mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour 6927 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); 6928 if (ptr) 6929 { 6930 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); 6931 if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT) 6932 { 6933 const rdataOPT *o; 6934 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; 6935 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) 6936 if (o->opt == kDNSOpt_Lease) 6937 { 6938 updatelease = o->u.updatelease; 6939 LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease); 6940 } 6941 } 6942 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it 6943 } 6944 6945 for (rr = m->ResourceRecords; rr; rr=rr->next) 6946 if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) 6947 if (mDNSSameOpaque16(rr->updateid, msg->h.id)) 6948 { 6949 rr->updateid = zeroID; 6950 rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond); 6951 LogSPS("Sleep Proxy registered record %5d %s", updatelease, ARDisplayString(m,rr)); 6952 } 6953 6954 } 6955 // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion 6956 // may have been the thing we were waiting for, so schedule another check to see if we can sleep now. 6957 if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow; 6958 } 6959 6960mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, 6961 const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID) 6962 { 6963 if (cr == &m->rec.r && m->rec.r.resrec.RecordType) 6964 { 6965 LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); 6966#if ForceAlerts 6967 *(long*)0 = 0; 6968#endif 6969 } 6970 6971 // Create empty resource record 6972 cr->resrec.RecordType = kDNSRecordTypePacketNegative; 6973 cr->resrec.InterfaceID = InterfaceID; 6974 cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry 6975 cr->resrec.rrtype = rrtype; 6976 cr->resrec.rrclass = rrclass; 6977 cr->resrec.rroriginalttl = ttl_seconds; 6978 cr->resrec.rdlength = 0; 6979 cr->resrec.rdestimate = 0; 6980 cr->resrec.namehash = namehash; 6981 cr->resrec.rdatahash = 0; 6982 cr->resrec.rdata = (RData*)&cr->smallrdatastorage; 6983 cr->resrec.rdata->MaxRDLength = 0; 6984 6985 cr->NextInKAList = mDNSNULL; 6986 cr->TimeRcvd = m->timenow; 6987 cr->DelayDelivery = 0; 6988 cr->NextRequiredQuery = m->timenow; 6989 cr->LastUsed = m->timenow; 6990 cr->CRActiveQuestion = mDNSNULL; 6991 cr->UnansweredQueries = 0; 6992 cr->LastUnansweredTime = 0; 6993#if ENABLE_MULTI_PACKET_QUERY_SNOOPING 6994 cr->MPUnansweredQ = 0; 6995 cr->MPLastUnansweredQT = 0; 6996 cr->MPUnansweredKA = 0; 6997 cr->MPExpectingKA = mDNSfalse; 6998#endif 6999 cr->NextInCFList = mDNSNULL; 7000 } 7001 7002mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, 7003 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, 7004 const mDNSInterfaceID InterfaceID) 7005 { 7006 mDNSInterfaceID ifid = InterfaceID; 7007 DNSMessage *msg = (DNSMessage *)pkt; 7008 const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery; 7009 const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; 7010 const mDNSu8 UpdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_Update; 7011 const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; 7012 mDNSu8 QR_OP; 7013 mDNSu8 *ptr = mDNSNULL; 7014 mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS 7015 if (TLS) dstaddr = mDNSNULL; 7016 7017#ifndef UNICAST_DISABLED 7018 if (mDNSSameAddress(srcaddr, &m->Router)) 7019 { 7020#ifdef _LEGACY_NAT_TRAVERSAL_ 7021 if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port))) 7022 { 7023 mDNS_Lock(m); 7024 LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); 7025 mDNS_Unlock(m); 7026 return; 7027 } 7028#endif 7029 if (mDNSSameIPPort(srcport, NATPMPPort)) 7030 { 7031 mDNS_Lock(m); 7032 uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); 7033 mDNS_Unlock(m); 7034 return; 7035 } 7036 } 7037#ifdef _LEGACY_NAT_TRAVERSAL_ 7038 else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; } 7039#endif 7040 7041#endif 7042 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; } 7043 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); 7044 // Read the integer parts which are in IETF byte-order (MSB first, LSB second) 7045 ptr = (mDNSu8 *)&msg->h.numQuestions; 7046 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 7047 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 7048 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 7049 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); 7050 7051 if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; } 7052 7053 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address" 7054 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up 7055 if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; } 7056 7057 mDNS_Lock(m); 7058 m->PktNum++; 7059#ifndef UNICAST_DISABLED 7060 if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR))) 7061 if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses 7062 { 7063 ifid = mDNSInterface_Any; 7064 if (mDNS_PacketLoggingEnabled) 7065 DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); 7066 uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport); 7067 // Note: mDNSCore also needs to get access to received unicast responses 7068 } 7069#endif 7070 if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); 7071 else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); 7072 else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); 7073 else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, InterfaceID); 7074 else 7075 { 7076 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)", 7077 msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID); 7078 if (mDNS_LoggingEnabled) 7079 { 7080 int i = 0; 7081 while (i<end-(mDNSu8 *)pkt) 7082 { 7083 char buffer[128]; 7084 char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i); 7085 do if (i<end-(mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15); 7086 LogInfo("%s", buffer); 7087 } 7088 } 7089 } 7090 // Packet reception often causes a change to the task list: 7091 // 1. Inbound queries can cause us to need to send responses 7092 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses 7093 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records 7094 // 4. Response packets that answer questions may cause our client to issue new questions 7095 mDNS_Unlock(m); 7096 } 7097 7098// *************************************************************************** 7099#if COMPILER_LIKES_PRAGMA_MARK 7100#pragma mark - 7101#pragma mark - Searcher Functions 7102#endif 7103 7104// Targets are considered the same if both queries are untargeted, or 7105// if both are targeted to the same address+port 7106// (If Target address is zero, TargetPort is undefined) 7107#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \ 7108 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort))) 7109 7110// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the 7111// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV" 7112// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails 7113// doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query 7114// a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come. 7115 7116// If IsLLQ(Q) is true, it means the question is both: 7117// (a) long-lived and 7118// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling) 7119// for multicast questions, we don't want to treat LongLived as anything special 7120#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID)) 7121 7122mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question) 7123 { 7124 DNSQuestion *q; 7125 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list. 7126 // This prevents circular references, where two questions are each marked as a duplicate of the other. 7127 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching 7128 // further in the list. 7129 for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question 7130 if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID, 7131 SameQTarget(q, question) && // and same unicast/multicast target settings 7132 q->qtype == question->qtype && // type, 7133 q->qclass == question->qclass && // class, 7134 IsLLQ(q) == IsLLQ(question) && // and long-lived status matches 7135 (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one 7136 q->qnamehash == question->qnamehash && 7137 SameDomainName(&q->qname, &question->qname)) // and name 7138 return(q); 7139 return(mDNSNULL); 7140 } 7141 7142// This is called after a question is deleted, in case other identical questions were being suppressed as duplicates 7143mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question) 7144 { 7145 DNSQuestion *q; 7146 for (q = m->Questions; q; q=q->next) // Scan our list of questions 7147 if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate 7148 if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL) 7149 { 7150 // If q used to be a duplicate, but now is not, 7151 // then inherit the state from the question that's going away 7152 q->LastQTime = question->LastQTime; 7153 q->ThisQInterval = question->ThisQInterval; 7154 q->ExpectUnicastResp = question->ExpectUnicastResp; 7155 q->LastAnswerPktNum = question->LastAnswerPktNum; 7156 q->RecentAnswerPkts = question->RecentAnswerPkts; 7157 q->RequestUnicast = question->RequestUnicast; 7158 q->LastQTxTime = question->LastQTxTime; 7159 q->CNAMEReferrals = question->CNAMEReferrals; 7160 q->nta = question->nta; 7161 q->servAddr = question->servAddr; 7162 q->servPort = question->servPort; 7163 q->qDNSServer = question->qDNSServer; 7164 q->unansweredQueries = question->unansweredQueries; 7165 7166 q->TargetQID = question->TargetQID; 7167 q->LocalSocket = question->LocalSocket; 7168 7169 q->state = question->state; 7170 // q->tcp = question->tcp; 7171 q->ReqLease = question->ReqLease; 7172 q->expire = question->expire; 7173 q->ntries = question->ntries; 7174 q->id = question->id; 7175 7176 question->LocalSocket = mDNSNULL; 7177 question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question 7178 // question->tcp = mDNSNULL; 7179 7180 if (q->LocalSocket) 7181 debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 7182 7183 if (q->nta) 7184 { 7185 LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 7186 q->nta->ZoneDataContext = q; 7187 } 7188 7189 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash 7190 if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer"); 7191 7192 if (question->state == LLQ_Established) 7193 { 7194 LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); 7195 question->state = 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server 7196 } 7197 7198 SetNextQueryTime(m,q); 7199 } 7200 } 7201 7202// Look up a DNS Server, matching by name in split-dns configurations. 7203mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name) 7204 { 7205 DNSServer *curmatch = mDNSNULL, *p; 7206 int curmatchlen = -1, ncount = name ? CountLabels(name) : 0; 7207 7208 for (p = m->DNSServers; p; p = p->next) 7209 { 7210 int scount = CountLabels(&p->domain); 7211 if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen) 7212 if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain)) 7213 { curmatch = p; curmatchlen = scount; } 7214 } 7215 return(curmatch); 7216 } 7217 7218#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \ 7219 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort))) 7220 7221// Called in normal client context (lock not held) 7222mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n) 7223 { 7224 DNSQuestion *q; 7225 (void)n; // Unused 7226 mDNS_Lock(m); 7227 LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort)); 7228 for (q = m->Questions; q; q=q->next) 7229 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) 7230 startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead 7231#if APPLE_OSX_mDNSResponder 7232 UpdateAutoTunnelDomainStatuses(m); 7233#endif 7234 mDNS_Unlock(m); 7235 } 7236 7237mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question) 7238 { 7239 if (question->Target.type && !ValidQuestionTarget(question)) 7240 { 7241 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)", 7242 question->Target.type, mDNSVal16(question->TargetPort)); 7243 question->Target.type = mDNSAddrType_None; 7244 } 7245 7246 if (!question->Target.type) question->TargetPort = zeroIPPort; // If question->Target specified clear TargetPort 7247 7248 question->TargetQID = 7249#ifndef UNICAST_DISABLED 7250 (question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) || 7251 (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname))) 7252 ? mDNS_NewMessageID(m) : 7253#endif // UNICAST_DISABLED 7254 zeroID; 7255 7256 debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 7257 7258 if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated 7259 return(mStatus_NoCache); 7260 else 7261 { 7262 int i; 7263 DNSQuestion **q; 7264 7265 if (!ValidateDomainName(&question->qname)) 7266 { 7267 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 7268 return(mStatus_Invalid); 7269 } 7270 7271 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start 7272 q = &m->Questions; 7273 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; 7274 while (*q && *q != question) q=&(*q)->next; 7275 7276 if (*q) 7277 { 7278 LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list", 7279 question->qname.c, DNSTypeName(question->qtype), question); 7280 return(mStatus_AlreadyRegistered); 7281 } 7282 7283 *q = question; 7284 7285 // If this question is referencing a specific interface, verify it exists 7286 if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast) 7287 { 7288 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID); 7289 if (!intf) 7290 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list", 7291 question->InterfaceID, question->qname.c, DNSTypeName(question->qtype)); 7292 } 7293 7294 // Note: In the case where we already have the answer to this question in our cache, that may be all the client 7295 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would 7296 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval). 7297 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate 7298 // that to go out immediately. 7299 question->next = mDNSNULL; 7300 question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion() 7301 question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname)); 7302 question->LastQTime = m->timenow; 7303 question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question 7304 question->ExpectUnicastResp = 0; 7305 question->LastAnswerPktNum = m->PktNum; 7306 question->RecentAnswerPkts = 0; 7307 question->CurrentAnswers = 0; 7308 question->LargeAnswers = 0; 7309 question->UniqueAnswers = 0; 7310 question->FlappingInterface1 = mDNSNULL; 7311 question->FlappingInterface2 = mDNSNULL; 7312 question->AuthInfo = GetAuthInfoForQuestion(m, question); // Must do this before calling FindDuplicateQuestion() 7313 question->DuplicateOf = FindDuplicateQuestion(m, question); 7314 question->NextInDQList = mDNSNULL; 7315 question->SendQNow = mDNSNULL; 7316 question->SendOnAll = mDNSfalse; 7317 question->RequestUnicast = 0; 7318 question->LastQTxTime = m->timenow; 7319 question->CNAMEReferrals = 0; 7320 7321 // We'll create our question->LocalSocket on demand, if needed. 7322 // We won't need one for duplicate questions, or from questions answered immediately out of the cache. 7323 // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single 7324 // NAT mapping for receiving inbound add/remove events. 7325 question->LocalSocket = mDNSNULL; 7326 question->qDNSServer = mDNSNULL; 7327 question->unansweredQueries = 0; 7328 question->nta = mDNSNULL; 7329 question->servAddr = zeroAddr; 7330 question->servPort = zeroIPPort; 7331 question->tcp = mDNSNULL; 7332 question->NoAnswer = NoAnswer_Normal; 7333 7334 question->state = LLQ_InitialRequest; 7335 question->ReqLease = 0; 7336 question->expire = 0; 7337 question->ntries = 0; 7338 question->id = zeroOpaque64; 7339 7340 if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo; 7341 7342 for (i=0; i<DupSuppressInfoSize; i++) 7343 question->DupSuppress[i].InterfaceID = mDNSNULL; 7344 7345 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)", 7346 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow, 7347 question->LastQTime + question->ThisQInterval - m->timenow, 7348 question->DelayAnswering ? question->DelayAnswering - m->timenow : 0, 7349 question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf); 7350 7351 if (question->InterfaceID == mDNSInterface_LocalOnly) 7352 { 7353 if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question; 7354 } 7355 else 7356 { 7357 if (!m->NewQuestions) m->NewQuestions = question; 7358 7359 // If the question's id is non-zero, then it's Wide Area 7360 // MUST NOT do this Wide Area setup until near the end of 7361 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA, 7362 // NS, etc.) and if we haven't finished setting up our own question and setting 7363 // m->NewQuestions if necessary then we could end up recursively re-entering 7364 // this routine with the question list data structures in an inconsistent state. 7365 if (!mDNSOpaque16IsZero(question->TargetQID)) 7366 { 7367 question->qDNSServer = GetServerForName(m, &question->qname); 7368 ActivateUnicastQuery(m, question, mDNSfalse); 7369 7370 // If long-lived query, and we don't have our NAT mapping active, start it now 7371 if (question->LongLived && !m->LLQNAT.clientContext) 7372 { 7373 m->LLQNAT.Protocol = NATOp_MapUDP; 7374 m->LLQNAT.IntPort = m->UnicastPort4; 7375 m->LLQNAT.RequestedPort = m->UnicastPort4; 7376 m->LLQNAT.clientCallback = LLQNATCallback; 7377 m->LLQNAT.clientContext = (void*)1; // Means LLQ NAT Traversal is active 7378 mDNS_StartNATOperation_internal(m, &m->LLQNAT); 7379 } 7380 7381#if APPLE_OSX_mDNSResponder 7382 if (question->LongLived) 7383 UpdateAutoTunnelDomainStatuses(m); 7384#endif 7385 7386 } 7387 SetNextQueryTime(m,question); 7388 } 7389 7390 return(mStatus_NoError); 7391 } 7392 } 7393 7394// CancelGetZoneData is an internal routine (i.e. must be called with the lock already held) 7395mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta) 7396 { 7397 debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype)); 7398 mDNS_StopQuery_internal(m, &nta->question); 7399 mDNSPlatformMemFree(nta); 7400 } 7401 7402mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question) 7403 { 7404 const mDNSu32 slot = HashSlot(&question->qname); 7405 CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); 7406 CacheRecord *rr; 7407 DNSQuestion **qp = &m->Questions; 7408 7409 //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 7410 7411 if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions; 7412 while (*qp && *qp != question) qp=&(*qp)->next; 7413 if (*qp) *qp = (*qp)->next; 7414 else 7415 { 7416#if !ForceAlerts 7417 if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active 7418#endif 7419 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list", 7420 question->qname.c, DNSTypeName(question->qtype)); 7421#if ForceAlerts 7422 *(long*)0 = 0; 7423#endif 7424 return(mStatus_BadReferenceErr); 7425 } 7426 7427 // Take care to cut question from list *before* calling UpdateQuestionDuplicates 7428 UpdateQuestionDuplicates(m, question); 7429 // But don't trash ThisQInterval until afterwards. 7430 question->ThisQInterval = -1; 7431 7432 // If there are any cache records referencing this as their active question, then see if there is any 7433 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL. 7434 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 7435 { 7436 if (rr->CRActiveQuestion == question) 7437 { 7438 DNSQuestion *q; 7439 for (q = m->Questions; q; q=q->next) // Scan our list of questions 7440 if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) 7441 break; 7442 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr)); 7443 rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null 7444 if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count 7445 } 7446 } 7447 7448 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at, 7449 // bump its pointer forward one question. 7450 if (m->CurrentQuestion == question) 7451 { 7452 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)", 7453 question->qname.c, DNSTypeName(question->qtype)); 7454 m->CurrentQuestion = question->next; 7455 } 7456 7457 if (m->NewQuestions == question) 7458 { 7459 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)", 7460 question->qname.c, DNSTypeName(question->qtype)); 7461 m->NewQuestions = question->next; 7462 } 7463 7464 if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next; 7465 7466 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions 7467 question->next = mDNSNULL; 7468 7469 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype)); 7470 7471 // And finally, cancel any associated GetZoneData operation that's still running. 7472 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list, 7473 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already 7474 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary 7475 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query. 7476 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } 7477 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } 7478 if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; } 7479 if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived) 7480 { 7481 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal. 7482 DNSQuestion *q; 7483 for (q = m->Questions; q; q=q->next) 7484 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) break; 7485 if (!q) 7486 { 7487 if (!m->LLQNAT.clientContext) // Should never happen, but just in case... 7488 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL"); 7489 else 7490 { 7491 LogInfo("Stopping LLQNAT"); 7492 mDNS_StopNATOperation_internal(m, &m->LLQNAT); 7493 m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running 7494 } 7495 } 7496 7497 // If necessary, tell server it can delete this LLQ state 7498 if (question->state == LLQ_Established) 7499 { 7500 question->ReqLease = 0; 7501 sendLLQRefresh(m, question); 7502 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while. 7503 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't 7504 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself -- 7505 // we let that run out its natural course and complete asynchronously. 7506 if (question->tcp) 7507 { 7508 question->tcp->question = mDNSNULL; 7509 question->tcp = mDNSNULL; 7510 } 7511 } 7512#if APPLE_OSX_mDNSResponder 7513 UpdateAutoTunnelDomainStatuses(m); 7514#endif 7515 } 7516 7517 return(mStatus_NoError); 7518 } 7519 7520mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question) 7521 { 7522 mStatus status; 7523 mDNS_Lock(m); 7524 status = mDNS_StartQuery_internal(m, question); 7525 mDNS_Unlock(m); 7526 return(status); 7527 } 7528 7529mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) 7530 { 7531 mStatus status; 7532 mDNS_Lock(m); 7533 status = mDNS_StopQuery_internal(m, question); 7534 mDNS_Unlock(m); 7535 return(status); 7536 } 7537 7538// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs 7539// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls. 7540// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback 7541// specifically to catch and report if the client callback does try to make API calls 7542mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question) 7543 { 7544 mStatus status; 7545 DNSQuestion *qq; 7546 mDNS_Lock(m); 7547 7548 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet 7549 for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break; 7550 7551 status = mDNS_StopQuery_internal(m, question); 7552 if (status == mStatus_NoError && !qq) 7553 { 7554 const CacheRecord *rr; 7555 const mDNSu32 slot = HashSlot(&question->qname); 7556 CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); 7557 LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 7558 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 7559 if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question)) 7560 { 7561 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls 7562 if (question->QuestionCallback) 7563 question->QuestionCallback(m, question, &rr->resrec, mDNSfalse); 7564 } 7565 } 7566 mDNS_Unlock(m); 7567 return(status); 7568 } 7569 7570mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr) 7571 { 7572 mStatus status; 7573 mDNS_Lock(m); 7574 status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 7575 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); 7576 mDNS_Unlock(m); 7577 return(status); 7578 } 7579 7580mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr) 7581 { 7582 mStatus status = mStatus_BadReferenceErr; 7583 CacheRecord *cr; 7584 mDNS_Lock(m); 7585 cr = FindIdenticalRecordInCache(m, rr); 7586 debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr)); 7587 if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 7588 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); 7589 mDNS_Unlock(m); 7590 return(status); 7591 } 7592 7593mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question, 7594 const domainname *const srv, const domainname *const domain, 7595 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) 7596 { 7597 question->InterfaceID = InterfaceID; 7598 question->Target = zeroAddr; 7599 question->qtype = kDNSType_PTR; 7600 question->qclass = kDNSClass_IN; 7601 question->LongLived = mDNSfalse; 7602 question->ExpectUnique = mDNSfalse; 7603 question->ForceMCast = ForceMCast; 7604 question->ReturnIntermed = mDNSfalse; 7605 question->QuestionCallback = Callback; 7606 question->QuestionContext = Context; 7607 if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr); 7608 7609#ifndef UNICAST_DISABLED 7610 if (Question_uDNS(question)) 7611 { 7612 question->LongLived = mDNStrue; 7613 question->ThisQInterval = InitialQuestionInterval; 7614 question->LastQTime = m->timenow - question->ThisQInterval; 7615 } 7616#endif // UNICAST_DISABLED 7617 return(mDNS_StartQuery_internal(m, question)); 7618 } 7619 7620mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, 7621 const domainname *const srv, const domainname *const domain, 7622 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) 7623 { 7624 mStatus status; 7625 mDNS_Lock(m); 7626 status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context); 7627 mDNS_Unlock(m); 7628 return(status); 7629 } 7630 7631mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) 7632 { 7633 NetworkInterfaceInfo *intf; 7634 for (intf = m->HostInterfaces; intf; intf = intf->next) 7635 if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue); 7636 return(mDNSfalse); 7637 } 7638 7639mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 7640 { 7641 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 7642 mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port); 7643 if (!AddRecord) return; 7644 if (answer->rrtype != kDNSType_SRV) return; 7645 7646 query->info->port = answer->rdata->u.srv.port; 7647 7648 // If this is our first answer, then set the GotSRV flag and start the address query 7649 if (!query->GotSRV) 7650 { 7651 query->GotSRV = mDNStrue; 7652 query->qAv4.InterfaceID = answer->InterfaceID; 7653 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 7654 query->qAv6.InterfaceID = answer->InterfaceID; 7655 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 7656 mDNS_StartQuery(m, &query->qAv4); 7657 // Only do the AAAA query if this machine actually has IPv6 active 7658 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 7659 } 7660 // If this is not our first answer, only re-issue the address query if the target host name has changed 7661 else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) || 7662 !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target)) 7663 { 7664 mDNS_StopQuery(m, &query->qAv4); 7665 if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6); 7666 if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged) 7667 { 7668 // If we get here, it means: 7669 // 1. This is not our first SRV answer 7670 // 2. The interface ID is different, but the target host and port are the same 7671 // This implies that we're seeing the exact same SRV record on more than one interface, so we should 7672 // make our address queries at least as broad as the original SRV query so that we catch all the answers. 7673 query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface 7674 query->qAv6.InterfaceID = query->qSRV.InterfaceID; 7675 } 7676 else 7677 { 7678 query->qAv4.InterfaceID = answer->InterfaceID; 7679 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target); 7680 query->qAv6.InterfaceID = answer->InterfaceID; 7681 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); 7682 } 7683 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype)); 7684 mDNS_StartQuery(m, &query->qAv4); 7685 // Only do the AAAA query if this machine actually has IPv6 active 7686 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); 7687 } 7688 else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged) 7689 { 7690 if (++query->Answers >= 100) 7691 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u", 7692 query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c, 7693 mDNSVal16(answer->rdata->u.srv.port)); 7694 query->ServiceInfoQueryCallback(m, query); 7695 } 7696 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 7697 // callback function is allowed to do anything, including deleting this query and freeing its memory. 7698 } 7699 7700mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 7701 { 7702 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 7703 if (!AddRecord) return; 7704 if (answer->rrtype != kDNSType_TXT) return; 7705 if (answer->rdlength > sizeof(query->info->TXTinfo)) return; 7706 7707 query->GotTXT = mDNStrue; 7708 query->info->TXTlen = answer->rdlength; 7709 query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero 7710 mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength); 7711 7712 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD); 7713 7714 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 7715 // callback function is allowed to do anything, including deleting this query and freeing its memory. 7716 if (query->ServiceInfoQueryCallback && query->GotADD) 7717 { 7718 if (++query->Answers >= 100) 7719 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...", 7720 query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c); 7721 query->ServiceInfoQueryCallback(m, query); 7722 } 7723 } 7724 7725mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 7726 { 7727 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; 7728 //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); 7729 if (!AddRecord) return; 7730 7731 if (answer->rrtype == kDNSType_A) 7732 { 7733 query->info->ip.type = mDNSAddrType_IPv4; 7734 query->info->ip.ip.v4 = answer->rdata->u.ipv4; 7735 } 7736 else if (answer->rrtype == kDNSType_AAAA) 7737 { 7738 query->info->ip.type = mDNSAddrType_IPv6; 7739 query->info->ip.ip.v6 = answer->rdata->u.ipv6; 7740 } 7741 else 7742 { 7743 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype)); 7744 return; 7745 } 7746 7747 query->GotADD = mDNStrue; 7748 query->info->InterfaceID = answer->InterfaceID; 7749 7750 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT); 7751 7752 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's 7753 // callback function is allowed to do anything, including deleting this query and freeing its memory. 7754 if (query->ServiceInfoQueryCallback && query->GotTXT) 7755 { 7756 if (++query->Answers >= 100) 7757 debugf(answer->rrtype == kDNSType_A ? 7758 "**** WARNING **** have given %lu answers for %##s (A) %.4a" : 7759 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", 7760 query->Answers, query->qSRV.qname.c, &answer->rdata->u.data); 7761 query->ServiceInfoQueryCallback(m, query); 7762 } 7763 } 7764 7765// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure 7766// If the query is not interface-specific, then InterfaceID may be zero 7767// Each time the Callback is invoked, the remainder of the fields will have been filled in 7768// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response 7769mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, 7770 ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context) 7771 { 7772 mStatus status; 7773 mDNS_Lock(m); 7774 7775 query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 7776 query->qSRV.InterfaceID = info->InterfaceID; 7777 query->qSRV.Target = zeroAddr; 7778 AssignDomainName(&query->qSRV.qname, &info->name); 7779 query->qSRV.qtype = kDNSType_SRV; 7780 query->qSRV.qclass = kDNSClass_IN; 7781 query->qSRV.LongLived = mDNSfalse; 7782 query->qSRV.ExpectUnique = mDNStrue; 7783 query->qSRV.ForceMCast = mDNSfalse; 7784 query->qSRV.ReturnIntermed = mDNSfalse; 7785 query->qSRV.QuestionCallback = FoundServiceInfoSRV; 7786 query->qSRV.QuestionContext = query; 7787 7788 query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 7789 query->qTXT.InterfaceID = info->InterfaceID; 7790 query->qTXT.Target = zeroAddr; 7791 AssignDomainName(&query->qTXT.qname, &info->name); 7792 query->qTXT.qtype = kDNSType_TXT; 7793 query->qTXT.qclass = kDNSClass_IN; 7794 query->qTXT.LongLived = mDNSfalse; 7795 query->qTXT.ExpectUnique = mDNStrue; 7796 query->qTXT.ForceMCast = mDNSfalse; 7797 query->qTXT.ReturnIntermed = mDNSfalse; 7798 query->qTXT.QuestionCallback = FoundServiceInfoTXT; 7799 query->qTXT.QuestionContext = query; 7800 7801 query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 7802 query->qAv4.InterfaceID = info->InterfaceID; 7803 query->qAv4.Target = zeroAddr; 7804 query->qAv4.qname.c[0] = 0; 7805 query->qAv4.qtype = kDNSType_A; 7806 query->qAv4.qclass = kDNSClass_IN; 7807 query->qAv4.LongLived = mDNSfalse; 7808 query->qAv4.ExpectUnique = mDNStrue; 7809 query->qAv4.ForceMCast = mDNSfalse; 7810 query->qAv4.ReturnIntermed = mDNSfalse; 7811 query->qAv4.QuestionCallback = FoundServiceInfo; 7812 query->qAv4.QuestionContext = query; 7813 7814 query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question 7815 query->qAv6.InterfaceID = info->InterfaceID; 7816 query->qAv6.Target = zeroAddr; 7817 query->qAv6.qname.c[0] = 0; 7818 query->qAv6.qtype = kDNSType_AAAA; 7819 query->qAv6.qclass = kDNSClass_IN; 7820 query->qAv6.LongLived = mDNSfalse; 7821 query->qAv6.ExpectUnique = mDNStrue; 7822 query->qAv6.ForceMCast = mDNSfalse; 7823 query->qAv6.ReturnIntermed = mDNSfalse; 7824 query->qAv6.QuestionCallback = FoundServiceInfo; 7825 query->qAv6.QuestionContext = query; 7826 7827 query->GotSRV = mDNSfalse; 7828 query->GotTXT = mDNSfalse; 7829 query->GotADD = mDNSfalse; 7830 query->Answers = 0; 7831 7832 query->info = info; 7833 query->ServiceInfoQueryCallback = Callback; 7834 query->ServiceInfoQueryContext = Context; 7835 7836// info->name = Must already be set up by client 7837// info->interface = Must already be set up by client 7838 info->ip = zeroAddr; 7839 info->port = zeroIPPort; 7840 info->TXTlen = 0; 7841 7842 // We use mDNS_StartQuery_internal here because we're already holding the lock 7843 status = mDNS_StartQuery_internal(m, &query->qSRV); 7844 if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT); 7845 if (status != mStatus_NoError) mDNS_StopResolveService(m, query); 7846 7847 mDNS_Unlock(m); 7848 return(status); 7849 } 7850 7851mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q) 7852 { 7853 mDNS_Lock(m); 7854 // We use mDNS_StopQuery_internal here because we're already holding the lock 7855 if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV); 7856 if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT); 7857 if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4); 7858 if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6); 7859 mDNS_Unlock(m); 7860 } 7861 7862mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom, 7863 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context) 7864 { 7865 question->InterfaceID = InterfaceID; 7866 question->Target = zeroAddr; 7867 question->qtype = kDNSType_PTR; 7868 question->qclass = kDNSClass_IN; 7869 question->LongLived = mDNSfalse; 7870 question->ExpectUnique = mDNSfalse; 7871 question->ForceMCast = mDNSfalse; 7872 question->ReturnIntermed = mDNSfalse; 7873 question->QuestionCallback = Callback; 7874 question->QuestionContext = Context; 7875 if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); 7876 if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 7877 if (!dom) dom = &localdomain; 7878 if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr); 7879 return(mDNS_StartQuery(m, question)); 7880 } 7881 7882// *************************************************************************** 7883#if COMPILER_LIKES_PRAGMA_MARK 7884#pragma mark - 7885#pragma mark - Responder Functions 7886#endif 7887 7888mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) 7889 { 7890 mStatus status; 7891 mDNS_Lock(m); 7892 status = mDNS_Register_internal(m, rr); 7893 mDNS_Unlock(m); 7894 return(status); 7895 } 7896 7897mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl, 7898 const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback) 7899 { 7900#ifndef UNICAST_DISABLED 7901 mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name)); 7902#else 7903 mDNSBool unicast = mDNSfalse; 7904#endif 7905 7906 if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata)) 7907 { 7908 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); 7909 return(mStatus_Invalid); 7910 } 7911 7912 mDNS_Lock(m); 7913 7914 // If TTL is unspecified, leave TTL unchanged 7915 if (newttl == 0) newttl = rr->resrec.rroriginalttl; 7916 7917 // If we already have an update queued up which has not gone through yet, 7918 // give the client a chance to free that memory 7919 if (!unicast && rr->NewRData) 7920 { 7921 RData *n = rr->NewRData; 7922 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ... 7923 if (rr->UpdateCallback) 7924 rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary 7925 } 7926 7927 rr->NewRData = newrdata; 7928 rr->newrdlength = newrdlength; 7929 rr->UpdateCallback = Callback; 7930 7931 if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); } 7932 7933 if (rr->resrec.rroriginalttl == newttl && 7934 rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength)) 7935 CompleteRDataUpdate(m, rr); 7936 else 7937 { 7938 domainlabel name; 7939 domainname type, domain; 7940 DeconstructServiceName(rr->resrec.name, &name, &type, &domain); 7941 rr->AnnounceCount = InitialAnnounceCount; 7942 // iChat often does suprious record updates where no data has changed. For the _presence service type, using 7943 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful 7944 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data 7945 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us. 7946 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement. 7947 if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1; 7948 InitializeLastAPTime(m, rr); 7949 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); 7950 if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--; 7951 if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval); 7952 if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1); 7953 if (rr->UpdateCredits <= 5) 7954 { 7955 mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum 7956 if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond); 7957 rr->ThisAPInterval *= 4; 7958 rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval; 7959 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", 7960 rr->resrec.name->c, delay, delay > 1 ? "s" : ""); 7961 } 7962 rr->resrec.rroriginalttl = newttl; 7963 } 7964 7965 mDNS_Unlock(m); 7966 return(mStatus_NoError); 7967 } 7968 7969// Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change 7970// the record list and/or question list. 7971// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 7972mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) 7973 { 7974 mStatus status; 7975 mDNS_Lock(m); 7976 status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 7977 mDNS_Unlock(m); 7978 return(status); 7979 } 7980 7981// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface 7982mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); 7983 7984mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) 7985 { 7986 NetworkInterfaceInfo *intf; 7987 for (intf = m->HostInterfaces; intf; intf = intf->next) 7988 if (intf->Advertise) break; 7989 return(intf); 7990 } 7991 7992mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 7993 { 7994 char buffer[MAX_REVERSE_MAPPING_NAME]; 7995 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 7996 if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary 7997 7998 // Send dynamic update for non-linklocal IPv4 Addresses 7999 mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, mDNS_HostNameCallback, set); 8000 mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); 8001 mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL); 8002 8003#if ANSWER_REMOTE_HOSTNAME_QUERIES 8004 set->RR_A .AllowRemoteQuery = mDNStrue; 8005 set->RR_PTR .AllowRemoteQuery = mDNStrue; 8006 set->RR_HINFO.AllowRemoteQuery = mDNStrue; 8007#endif 8008 // 1. Set up Address record to map from host name ("foo.local.") to IP address 8009 // 2. Set up reverse-lookup PTR record to map from our address back to our host name 8010 AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname); 8011 if (set->ip.type == mDNSAddrType_IPv4) 8012 { 8013 set->RR_A.resrec.rrtype = kDNSType_A; 8014 set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4; 8015 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code 8016 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", 8017 set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]); 8018 } 8019 else if (set->ip.type == mDNSAddrType_IPv6) 8020 { 8021 int i; 8022 set->RR_A.resrec.rrtype = kDNSType_AAAA; 8023 set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6; 8024 for (i = 0; i < 16; i++) 8025 { 8026 static const char hexValues[] = "0123456789ABCDEF"; 8027 buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F]; 8028 buffer[i * 4 + 1] = '.'; 8029 buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4]; 8030 buffer[i * 4 + 3] = '.'; 8031 } 8032 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); 8033 } 8034 8035 MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer); 8036 set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name 8037 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 8038 8039 set->RR_A.RRSet = &primary->RR_A; // May refer to self 8040 8041 mDNS_Register_internal(m, &set->RR_A); 8042 mDNS_Register_internal(m, &set->RR_PTR); 8043 8044 if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254) 8045 { 8046 mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data; 8047 AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname); 8048 set->RR_HINFO.DependentOn = &set->RR_A; 8049 mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]); 8050 p += 1 + (int)p[0]; 8051 mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]); 8052 mDNS_Register_internal(m, &set->RR_HINFO); 8053 } 8054 else 8055 { 8056 debugf("Not creating HINFO record: platform support layer provided no information"); 8057 set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered; 8058 } 8059 } 8060 8061mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) 8062 { 8063 NetworkInterfaceInfo *intf; 8064 8065 // If we still have address records referring to this one, update them 8066 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); 8067 AuthRecord *A = primary ? &primary->RR_A : mDNSNULL; 8068 for (intf = m->HostInterfaces; intf; intf = intf->next) 8069 if (intf->RR_A.RRSet == &set->RR_A) 8070 intf->RR_A.RRSet = A; 8071 8072 // Unregister these records. 8073 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform 8074 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it. 8075 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered. 8076 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal(). 8077 if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal); 8078 if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal); 8079 if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal); 8080 } 8081 8082mDNSexport void mDNS_SetFQDN(mDNS *const m) 8083 { 8084 domainname newmname; 8085 NetworkInterfaceInfo *intf; 8086 AuthRecord *rr; 8087 newmname.c[0] = 0; 8088 8089 if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 8090 if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } 8091 8092 mDNS_Lock(m); 8093 8094 if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged"); 8095 else 8096 { 8097 AssignDomainName(&m->MulticastHostname, &newmname); 8098 8099 // 1. Stop advertising our address records on all interfaces 8100 for (intf = m->HostInterfaces; intf; intf = intf->next) 8101 if (intf->Advertise) DeadvertiseInterface(m, intf); 8102 8103 // 2. Start advertising our address records using the new name 8104 for (intf = m->HostInterfaces; intf; intf = intf->next) 8105 if (intf->Advertise) AdvertiseInterface(m, intf); 8106 } 8107 8108 // 3. Make sure that any AutoTarget SRV records (and the like) get updated 8109 for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); 8110 for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); 8111 8112 mDNS_Unlock(m); 8113 } 8114 8115mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 8116 { 8117 (void)rr; // Unused parameter 8118 8119 #if MDNS_DEBUGMSGS 8120 { 8121 char *msg = "Unknown result"; 8122 if (result == mStatus_NoError) msg = "Name registered"; 8123 else if (result == mStatus_NameConflict) msg = "Name conflict"; 8124 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 8125 } 8126 #endif 8127 8128 if (result == mStatus_NoError) 8129 { 8130 // Notify the client that the host name is successfully registered 8131 if (m->MainCallback) 8132 m->MainCallback(m, mStatus_NoError); 8133 } 8134 else if (result == mStatus_NameConflict) 8135 { 8136 domainlabel oldlabel = m->hostlabel; 8137 8138 // 1. First give the client callback a chance to pick a new name 8139 if (m->MainCallback) 8140 m->MainCallback(m, mStatus_NameConflict); 8141 8142 // 2. If the client callback didn't do it, add (or increment) an index ourselves 8143 // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to 8144 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again. 8145 if (SameDomainLabel(m->hostlabel.c, oldlabel.c)) 8146 IncrementLabelSuffix(&m->hostlabel, mDNSfalse); 8147 8148 // 3. Generate the FQDNs from the hostlabel, 8149 // and make sure all SRV records, etc., are updated to reference our new hostname 8150 mDNS_SetFQDN(m); 8151 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c); 8152 } 8153 else if (result == mStatus_MemFree) 8154 { 8155 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by 8156 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface 8157 debugf("mDNS_HostNameCallback: MemFree (ignored)"); 8158 } 8159 else 8160 LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c); 8161 } 8162 8163mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active) 8164 { 8165 NetworkInterfaceInfo *intf; 8166 active->IPv4Available = mDNSfalse; 8167 active->IPv6Available = mDNSfalse; 8168 for (intf = m->HostInterfaces; intf; intf = intf->next) 8169 if (intf->InterfaceID == active->InterfaceID) 8170 { 8171 if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue; 8172 if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue; 8173 } 8174 } 8175 8176mDNSlocal void RestartRecordGetZoneData(mDNS * const m) 8177 { 8178 AuthRecord *rr; 8179 ServiceRecordSet *s; 8180 8181 for (rr = m->ResourceRecords; rr; rr=rr->next) 8182 if (AuthRecord_uDNS(rr)) 8183 { 8184 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c); 8185 if (rr->nta) CancelGetZoneData(m, rr->nta); 8186 rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); 8187 } 8188 8189 for (s = m->ServiceRegistrations; s; s = s->uDNS_next) 8190 { 8191 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c); 8192 if (s->srs_nta) CancelGetZoneData(m, s->srs_nta); 8193 s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s); 8194 } 8195 } 8196 8197mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set) 8198 { 8199 int i; 8200 set->NetWakeBrowse.ThisQInterval = -1; 8201 for (i=0; i<3; i++) 8202 { 8203 set->NetWakeResolve[i].ThisQInterval = -1; 8204 set->SPSAddr[i].type = mDNSAddrType_None; 8205 } 8206 set->NextSPSAttempt = -1; 8207 set->NextSPSAttemptTime = m->timenow; 8208 } 8209 8210mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) 8211 { 8212 NetworkInterfaceInfo *p = m->HostInterfaces; 8213 while (p && p != set) p=p->next; 8214 if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } 8215 8216 if (set->InterfaceActive) 8217 { 8218 LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip); 8219 mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set); 8220 } 8221 } 8222 8223mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) 8224 { 8225 NetworkInterfaceInfo *p = m->HostInterfaces; 8226 while (p && p != set) p=p->next; 8227 if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } 8228 8229 if (set->NetWakeBrowse.ThisQInterval >= 0) 8230 { 8231 int i; 8232 LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip); 8233 8234 // Stop our browse and resolve operations 8235 mDNS_StopQuery_internal(m, &set->NetWakeBrowse); 8236 for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]); 8237 8238 // Make special call to the browse callback to let it know it can to remove all records for this interface 8239 if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse); 8240 8241 // Reset our variables back to initial state, so we're ready for when NetWake is turned back on 8242 // (includes resetting NetWakeBrowse.ThisQInterval back to -1) 8243 InitializeNetWakeState(m, set); 8244 } 8245 } 8246 8247mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 8248 { 8249 AuthRecord *rr; 8250 mDNSBool FirstOfType = mDNStrue; 8251 NetworkInterfaceInfo **p = &m->HostInterfaces; 8252 8253 if (!set->InterfaceID) 8254 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); } 8255 8256 if (!mDNSAddressIsValidNonZero(&set->mask)) 8257 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); } 8258 8259 mDNS_Lock(m); 8260 8261 // Assume this interface will be active now, unless we find a duplicate already in the list 8262 set->InterfaceActive = mDNStrue; 8263 set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx); 8264 set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx); 8265 8266 InitializeNetWakeState(m, set); 8267 8268 // Scan list to see if this InterfaceID is already represented 8269 while (*p) 8270 { 8271 if (*p == set) 8272 { 8273 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list"); 8274 mDNS_Unlock(m); 8275 return(mStatus_AlreadyRegistered); 8276 } 8277 8278 if ((*p)->InterfaceID == set->InterfaceID) 8279 { 8280 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now 8281 set->InterfaceActive = mDNSfalse; 8282 if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse; 8283 if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue; 8284 if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue; 8285 } 8286 8287 p=&(*p)->next; 8288 } 8289 8290 set->next = mDNSNULL; 8291 *p = set; 8292 8293 if (set->Advertise) 8294 AdvertiseInterface(m, set); 8295 8296 LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip, 8297 set->InterfaceActive ? 8298 "not represented in list; marking active and retriggering queries" : 8299 "already represented in list; marking inactive for now"); 8300 8301 if (set->NetWake) mDNS_ActivateNetWake_internal(m, set); 8302 8303 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 8304 // giving the false impression that there's an active representative of this interface when there really isn't. 8305 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records, 8306 // even if we believe that we previously had an active representative of this interface. 8307 if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive)) 8308 { 8309 DNSQuestion *q; 8310 // If flapping, delay between first and second queries is eight seconds instead of one 8311 mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0; 8312 mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount; 8313 mDNSs32 newSS = 0; 8314 8315 // Use a small amount of randomness: 8316 // In the case of a network administrator turning on an Ethernet hub so that all the 8317 // connected machines establish link at exactly the same time, we don't want them all 8318 // to go and hit the network with identical queries at exactly the same moment. 8319 newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); 8320#if APPLE_OSX_mDNSResponder 8321 // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots 8322 // of network change notifications in a row, and we don't know when we're done getting notified. 8323 // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx). 8324 newSS += mDNSPlatformOneSecond * 2; 8325#endif 8326 if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS; 8327 8328 if (flapping) 8329 { 8330 LogMsg("Note: RegisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", 8331 set->ifname, &set->ip); 8332 if (!m->SuppressProbes || 8333 m->SuppressProbes - (m->timenow + delay) < 0) 8334 m->SuppressProbes = (m->timenow + delay); 8335 } 8336 8337 for (q = m->Questions; q; q=q->next) // Scan our list of questions 8338 if (mDNSOpaque16IsZero(q->TargetQID)) 8339 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, 8340 { // then reactivate this question 8341 mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); 8342 mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval; 8343 mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0; 8344 if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); 8345 8346 if (!q->ThisQInterval || q->ThisQInterval > initial) 8347 { 8348 q->ThisQInterval = initial; 8349 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it 8350 } 8351 q->LastQTime = m->timenow - q->ThisQInterval + qdelay; 8352 q->RecentAnswerPkts = 0; 8353 SetNextQueryTime(m,q); 8354 } 8355 8356 // For all our non-specific authoritative resource records (and any dormant records specific to this interface) 8357 // we now need them to re-probe if necessary, and then re-announce. 8358 for (rr = m->ResourceRecords; rr; rr=rr->next) 8359 if (!AuthRecord_uDNS(rr)) 8360 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID) 8361 { 8362 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; 8363 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); 8364 if (rr->AnnounceCount < announce) rr->AnnounceCount = announce; 8365 InitializeLastAPTime(m, rr); 8366 } 8367 } 8368 8369 RestartRecordGetZoneData(m); 8370 8371 mDNS_Unlock(m); 8372 return(mStatus_NoError); 8373 } 8374 8375// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change 8376// the record list and/or question list. 8377// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 8378mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) 8379 { 8380 NetworkInterfaceInfo **p = &m->HostInterfaces; 8381 8382 mDNSBool revalidate = mDNSfalse; 8383 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every 8384 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it 8385 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion. 8386 if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue; 8387 8388 mDNS_Lock(m); 8389 8390 // Find this record in our list 8391 while (*p && *p != set) p=&(*p)->next; 8392 if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; } 8393 8394 mDNS_DeactivateNetWake_internal(m, set); 8395 8396 // Unlink this record from our list 8397 *p = (*p)->next; 8398 set->next = mDNSNULL; 8399 8400 if (!set->InterfaceActive) 8401 { 8402 // If this interface not the active member of its set, update the v4/v6Available flags for the active member 8403 NetworkInterfaceInfo *intf; 8404 for (intf = m->HostInterfaces; intf; intf = intf->next) 8405 if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID) 8406 UpdateInterfaceProtocols(m, intf); 8407 } 8408 else 8409 { 8410 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID); 8411 if (intf) 8412 { 8413 LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" 8414 " making it active", set->InterfaceID, set->ifname, &set->ip); 8415 if (intf->InterfaceActive) 8416 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip); 8417 intf->InterfaceActive = mDNStrue; 8418 UpdateInterfaceProtocols(m, intf); 8419 8420 if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf); 8421 8422 // See if another representative *of the same type* exists. If not, we mave have gone from 8423 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid. 8424 for (intf = m->HostInterfaces; intf; intf = intf->next) 8425 if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type) 8426 break; 8427 if (!intf) revalidate = mDNStrue; 8428 } 8429 else 8430 { 8431 mDNSu32 slot; 8432 CacheGroup *cg; 8433 CacheRecord *rr; 8434 DNSQuestion *q; 8435 DNSServer *s; 8436 8437 LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" 8438 " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip); 8439 8440 if (flapping) 8441 LogMsg("Note: DeregisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", 8442 set->ifname, &set->ip); 8443 8444 // 1. Deactivate any questions specific to this interface, and tag appropriate questions 8445 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them 8446 for (q = m->Questions; q; q=q->next) 8447 { 8448 if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0; 8449 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) 8450 { 8451 q->FlappingInterface2 = q->FlappingInterface1; 8452 q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away 8453 } 8454 } 8455 8456 // 2. Flush any cache records received on this interface 8457 revalidate = mDNSfalse; // Don't revalidate if we're flushing the records 8458 FORALL_CACHERECORDS(slot, cg, rr) 8459 if (rr->resrec.InterfaceID == set->InterfaceID) 8460 { 8461 // If this interface is deemed flapping, 8462 // postpone deleting the cache records in case the interface comes back again 8463 if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr); 8464 else 8465 { 8466 // We want these record to go away in 30 seconds 8467 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them -- 8468 // if the interface does come back, any relevant questions will be reactivated anyway 8469 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 8470 rr->UnansweredQueries = MaxUnansweredQueries; 8471 } 8472 } 8473 8474 // 3. Any DNS servers specific to this interface are now unusable 8475 for (s = m->DNSServers; s; s = s->next) 8476 if (s->interface == set->InterfaceID) 8477 { 8478 s->interface = mDNSInterface_Any; 8479 s->teststate = DNSServer_Disabled; 8480 } 8481 } 8482 } 8483 8484 // If we were advertising on this interface, deregister those address and reverse-lookup records now 8485 if (set->Advertise) DeadvertiseInterface(m, set); 8486 8487 // If we have any cache records received on this interface that went away, then re-verify them. 8488 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off, 8489 // giving the false impression that there's an active representative of this interface when there really isn't. 8490 // Don't need to do this when shutting down, because *all* interfaces are about to go away 8491 if (revalidate && !m->ShutdownTime) 8492 { 8493 mDNSu32 slot; 8494 CacheGroup *cg; 8495 CacheRecord *rr; 8496 m->NextCacheCheck = m->timenow; 8497 FORALL_CACHERECORDS(slot, cg, rr) 8498 if (rr->resrec.InterfaceID == set->InterfaceID) 8499 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); 8500 } 8501 8502 mDNS_Unlock(m); 8503 } 8504 8505mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 8506 { 8507 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 8508 (void)m; // Unused parameter 8509 8510 #if MDNS_DEBUGMSGS 8511 { 8512 char *msg = "Unknown result"; 8513 if (result == mStatus_NoError) msg = "Name Registered"; 8514 else if (result == mStatus_NameConflict) msg = "Name Conflict"; 8515 else if (result == mStatus_MemFree) msg = "Memory Free"; 8516 debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); 8517 } 8518 #endif 8519 8520 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing) 8521 if (result == mStatus_NoError && rr != &sr->RR_SRV) return; 8522 8523 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that 8524 if (result == mStatus_NameConflict) 8525 { 8526 sr->Conflict = mDNStrue; // Record that this service set had a conflict 8527 mDNS_DeregisterService(m, sr); // Unlink the records from our list 8528 return; 8529 } 8530 8531 if (result == mStatus_MemFree) 8532 { 8533 // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records, 8534 // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until 8535 // every record is finished cleaning up. 8536 mDNSu32 i; 8537 if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return; 8538 if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return; 8539 if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return; 8540 if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return; 8541 for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return; 8542 8543 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse, 8544 // then we can now report the NameConflict to the client 8545 if (sr->Conflict) result = mStatus_NameConflict; 8546 8547 if (sr->srs_nta) 8548 { 8549 LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV)); 8550 CancelGetZoneData(m, sr->srs_nta); 8551 sr->srs_nta = mDNSNULL; 8552 } 8553 } 8554 8555 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback 8556 // function is allowed to do anything, including deregistering this service and freeing its memory. 8557 if (sr->ServiceCallback) 8558 sr->ServiceCallback(m, sr, result); 8559 } 8560 8561mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 8562 { 8563 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext; 8564 if (sr->ServiceCallback) 8565 sr->ServiceCallback(m, sr, result); 8566 } 8567 8568#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST 8569mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) 8570 { 8571 mDNSu32 i; 8572 ServiceRecordSet **p = &m->ServiceRegistrations; 8573 while (*p && *p != srs) p=&(*p)->uDNS_next; 8574 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); } 8575 8576 srs->uDNS_next = mDNSNULL; 8577 *p = srs; 8578 8579 srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL; 8580 srs->RR_TXT.resrec.rroriginalttl = kStandardTTL; 8581 srs->RR_PTR.resrec.rroriginalttl = kStandardTTL; 8582 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL; 8583 8584 srs->srs_uselease = mDNStrue; 8585 8586 if (srs->RR_SRV.AutoTarget) 8587 { 8588 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other 8589 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, 8590 // with the port number in our advertised SRV record automatically tracking the external mapped port. 8591 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name); 8592 if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP; 8593 } 8594 8595 if (!GetServiceTarget(m, &srs->RR_SRV)) 8596 { 8597 // defer registration until we've got a target 8598 LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); 8599 srs->state = regState_NoTarget; 8600 return mStatus_NoError; 8601 } 8602 8603 ActivateUnicastRegistration(m, &srs->RR_SRV); 8604 srs->state = regState_FetchingZoneData; 8605 return mStatus_NoError; 8606 } 8607#endif 8608 8609// Note: 8610// Name is first label of domain name (any dots in the name are actual dots, not label separators) 8611// Type is service type (e.g. "_ipp._tcp.") 8612// Domain is fully qualified domain name (i.e. ending with a null label) 8613// We always register a TXT, even if it is empty (so that clients are not 8614// left waiting forever looking for a nonexistent record.) 8615// If the host parameter is mDNSNULL or the root domain (ASCII NUL), 8616// then the default host name (m->MulticastHostname) is automatically used 8617// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration 8618mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, 8619 const domainlabel *const name, const domainname *const type, const domainname *const domain, 8620 const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, 8621 AuthRecord *SubTypes, mDNSu32 NumSubTypes, 8622 const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context) 8623 { 8624 mStatus err; 8625 mDNSu32 i; 8626 8627 sr->state = regState_Zero; 8628 sr->srs_uselease = 0; 8629 sr->TestForSelfConflict = 0; 8630 sr->Private = 0; 8631 sr->id = zeroID; 8632 sr->zone.c[0] = 0; 8633 sr->SRSUpdateServer = zeroAddr; 8634 sr->SRSUpdatePort = zeroIPPort; 8635 mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo)); 8636 sr->NATinfo.IntPort = port; // Record originally-requested port 8637 sr->ClientCallbackDeferred = 0; 8638 sr->DeferredStatus = 0; 8639 sr->SRVUpdateDeferred = 0; 8640 sr->SRVChanged = 0; 8641 sr->tcp = mDNSNULL; 8642 8643 sr->ServiceCallback = Callback; 8644 sr->ServiceContext = Context; 8645 sr->Conflict = mDNSfalse; 8646 8647 sr->Extras = mDNSNULL; 8648 sr->NumSubTypes = NumSubTypes; 8649 sr->SubTypes = SubTypes; 8650 8651 // Initialize the AuthRecord objects to sane values 8652 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out 8653 mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr); 8654 mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); 8655 mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr); 8656 mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr); 8657 8658 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService 8659 if (mDNSIPPortIsZero(port)) 8660 return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr)); 8661 8662 // If the client is registering an oversized TXT record, 8663 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it 8664 if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen) 8665 sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen; 8666 8667 // Set up the record names 8668 // For now we only create an advisory record for the main type, not for subtypes 8669 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too 8670 if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL) 8671 return(mStatus_BadParamErr); 8672 if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 8673 if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 8674 AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name); 8675 8676 // 1. Set up the ADV record rdata to advertise our service type 8677 AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name); 8678 8679 // 2. Set up the PTR record rdata to point to our service name 8680 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too 8681 AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name); 8682 sr->RR_PTR.Additional1 = &sr->RR_SRV; 8683 sr->RR_PTR.Additional2 = &sr->RR_TXT; 8684 8685 // 2a. Set up any subtype PTRs to point to our service name 8686 // If the client is using subtypes, it is the client's responsibility to have 8687 // already set the first label of the record name to the subtype being registered 8688 for (i=0; i<NumSubTypes; i++) 8689 { 8690 domainname st; 8691 AssignDomainName(&st, sr->SubTypes[i].resrec.name); 8692 st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService()) 8693 AppendDomainName(&st, type); 8694 mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); 8695 if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr); 8696 AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage); 8697 sr->SubTypes[i].Additional1 = &sr->RR_SRV; 8698 sr->SubTypes[i].Additional2 = &sr->RR_TXT; 8699 } 8700 8701 // 3. Set up the SRV record rdata. 8702 sr->RR_SRV.resrec.rdata->u.srv.priority = 0; 8703 sr->RR_SRV.resrec.rdata->u.srv.weight = 0; 8704 sr->RR_SRV.resrec.rdata->u.srv.port = port; 8705 8706 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name 8707 if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host); 8708 else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; } 8709 8710 // 4. Set up the TXT record rdata, 8711 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us 8712 if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0; 8713 else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c) 8714 { 8715 sr->RR_TXT.resrec.rdlength = txtlen; 8716 if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr); 8717 mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen); 8718 } 8719 sr->RR_TXT.DependentOn = &sr->RR_SRV; 8720 8721 sr->srs_nta = mDNSNULL; 8722 8723#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST 8724 // If the client has specified an explicit InterfaceID, 8725 // then we do a multicast registration on that interface, even for unicast domains. 8726 if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage))) 8727 { 8728 mStatus status; 8729 mDNS_Lock(m); 8730 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 8731 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 8732 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 8733 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck) 8734 if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; } 8735 8736 status = uDNS_RegisterService(m, sr); 8737 mDNS_Unlock(m); 8738 return(status); 8739 } 8740#endif 8741 8742 mDNS_Lock(m); 8743 err = mDNS_Register_internal(m, &sr->RR_SRV); 8744 if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT); 8745 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to 8746 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers 8747 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to 8748 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to 8749 // make sure we've deregistered all our records and done any other necessary cleanup before that happens. 8750 if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV); 8751 for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]); 8752 if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR); 8753 8754 mDNS_Unlock(m); 8755 8756 if (err) mDNS_DeregisterService(m, sr); 8757 return(err); 8758 } 8759 8760mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result) 8761 { 8762 (void)m; // Unused 8763 (void)rr; // Unused 8764 (void)result; // Unused 8765 LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr)); 8766 } 8767 8768mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, 8769 ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl) 8770 { 8771 ExtraResourceRecord **e; 8772 mStatus status; 8773 8774 extra->next = mDNSNULL; 8775 mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, 8776 extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr); 8777 AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name); 8778 8779 mDNS_Lock(m); 8780 e = &sr->Extras; 8781 while (*e) e = &(*e)->next; 8782 8783 if (ttl == 0) ttl = kStandardTTL; 8784 8785 extra->r.DependentOn = &sr->RR_SRV; 8786 8787 debugf("mDNS_AddRecordToService adding record to %##s %s %d", 8788 extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength); 8789 8790 status = mDNS_Register_internal(m, &extra->r); 8791 if (status == mStatus_NoError) 8792 { 8793 *e = extra; 8794#ifndef UNICAST_DISABLED 8795 if (AuthRecord_uDNS(&sr->RR_SRV)) 8796 { 8797 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???) 8798 extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????) 8799 if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued; 8800 } 8801#endif 8802 } 8803 8804 mDNS_Unlock(m); 8805 return(status); 8806 } 8807 8808mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, 8809 mDNSRecordCallback MemFreeCallback, void *Context) 8810 { 8811 ExtraResourceRecord **e; 8812 mStatus status; 8813 8814 mDNS_Lock(m); 8815 e = &sr->Extras; 8816 while (*e && *e != extra) e = &(*e)->next; 8817 if (!*e) 8818 { 8819 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c); 8820 status = mStatus_BadReferenceErr; 8821 } 8822 else 8823 { 8824 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c); 8825 extra->r.RecordCallback = MemFreeCallback; 8826 extra->r.RecordContext = Context; 8827 *e = (*e)->next; 8828 status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal); 8829 } 8830 mDNS_Unlock(m); 8831 return(status); 8832 } 8833 8834mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname) 8835 { 8836 // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines 8837 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally. 8838 domainlabel name1, name2; 8839 domainname type, domain; 8840 const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target; 8841 ExtraResourceRecord *extras = sr->Extras; 8842 mStatus err; 8843 8844 DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain); 8845 if (!newname) 8846 { 8847 name2 = name1; 8848 IncrementLabelSuffix(&name2, mDNStrue); 8849 newname = &name2; 8850 } 8851 8852 if (SameDomainName(&domain, &localdomain)) 8853 debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c); 8854 else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c); 8855 8856 err = mDNS_RegisterService(m, sr, newname, &type, &domain, 8857 host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, 8858 sr->SubTypes, sr->NumSubTypes, 8859 sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext); 8860 8861 // mDNS_RegisterService() just reset sr->Extras to NULL. 8862 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run 8863 // through the old list of extra records, and re-add them to our freshly created service registration 8864 while (!err && extras) 8865 { 8866 ExtraResourceRecord *e = extras; 8867 extras = extras->next; 8868 err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl); 8869 } 8870 8871 return(err); 8872 } 8873 8874// Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback, 8875// which may change the record list and/or question list. 8876// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. 8877mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) 8878 { 8879 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService() 8880 if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); 8881 8882#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST 8883 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) 8884 { 8885 mStatus status; 8886 mDNS_Lock(m); 8887 status = uDNS_DeregisterService(m, sr); 8888 mDNS_Unlock(m); 8889 return(status); 8890 } 8891#endif 8892 if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered) 8893 { 8894 debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c); 8895 return(mStatus_BadReferenceErr); 8896 } 8897 else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering) 8898 { 8899 debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c); 8900 // Avoid race condition: 8901 // If a service gets a conflict, then we set the Conflict flag to tell us to generate 8902 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record. 8903 // If the client happens to deregister the service in the middle of that process, then 8904 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree 8905 // instead of incorrectly promoting it to mStatus_NameConflict. 8906 // This race condition is exposed particularly when the conformance test generates 8907 // a whole batch of simultaneous conflicts across a range of services all advertised 8908 // using the same system default name, and if we don't take this precaution then 8909 // we end up incrementing m->nicelabel multiple times instead of just once. 8910 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision 8911 sr->Conflict = mDNSfalse; 8912 return(mStatus_NoError); 8913 } 8914 else 8915 { 8916 mDNSu32 i; 8917 mStatus status; 8918 ExtraResourceRecord *e; 8919 mDNS_Lock(m); 8920 e = sr->Extras; 8921 8922 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the 8923 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay 8924 mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat); 8925 mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat); 8926 8927 mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal); 8928 8929 // We deregister all of the extra records, but we leave the sr->Extras list intact 8930 // in case the client wants to do a RenameAndReregister and reinstate the registration 8931 while (e) 8932 { 8933 mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat); 8934 e = e->next; 8935 } 8936 8937 for (i=0; i<sr->NumSubTypes; i++) 8938 mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal); 8939 8940 // Be sure to deregister the PTR last! 8941 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback, 8942 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback, 8943 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure 8944 // we've deregistered all our records and done any other necessary cleanup before that happens. 8945 status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal); 8946 mDNS_Unlock(m); 8947 return(status); 8948 } 8949 } 8950 8951// Create a registration that asserts that no such service exists with this name. 8952// This can be useful where there is a given function is available through several protocols. 8953// For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP" 8954// protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an 8955// "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing 8956// could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users. 8957mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr, 8958 const domainlabel *const name, const domainname *const type, const domainname *const domain, 8959 const domainname *const host, 8960 const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context) 8961 { 8962 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context); 8963 if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); 8964 rr->resrec.rdata->u.srv.priority = 0; 8965 rr->resrec.rdata->u.srv.weight = 0; 8966 rr->resrec.rdata->u.srv.port = zeroIPPort; 8967 if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host); 8968 else rr->AutoTarget = Target_AutoHost; 8969 return(mDNS_Register(m, rr)); 8970 } 8971 8972mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, 8973 mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname) 8974 { 8975 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL); 8976 if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); 8977 if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr); 8978 return(mDNS_Register(m, rr)); 8979 } 8980 8981mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m) 8982 { 8983 mDNSOpaque16 id; 8984 int i; 8985 for (i=0; i<10; i++) 8986 { 8987 AuthRecord *r; 8988 DNSQuestion *q; 8989 id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE)); 8990 for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue; 8991 for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue; 8992 break; 8993 } 8994 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id)); 8995 return id; 8996 } 8997 8998// *************************************************************************** 8999#if COMPILER_LIKES_PRAGMA_MARK 9000#pragma mark - 9001#pragma mark - Sleep Proxy Server 9002#endif 9003 9004mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr) 9005 { 9006 // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine. 9007 // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine. 9008 // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep) 9009 // then we'll transition out of probing state and start answering ARPs again. 9010 rr->resrec.RecordType = kDNSRecordTypeUnique; 9011 rr->ProbeCount = DefaultProbeCountForTypeUnique; 9012 rr->AnnounceCount = InitialAnnounceCount; 9013 InitializeLastAPTime(m, rr); 9014 } 9015 9016mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID) 9017 { 9018 static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } }; 9019 static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1) 9020 static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen 9021 static const mDNSOpaque16 ARP_op_request = { { 0, 1 } }; 9022 const EthernetHeader *const eth = (const EthernetHeader *)p; 9023 const ARP_EthIP *const arp = (const ARP_EthIP *)(eth+1); 9024 const IPv4Header *const v4 = (const IPv4Header *)(eth+1); 9025 const IPv6Header *const v6 = (const IPv6Header *)(eth+1); 9026 if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger) 9027 { 9028 AuthRecord *rr; 9029 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); 9030 if (!intf) return; 9031 9032 debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa); 9033 9034 mDNS_Lock(m); 9035 9036 // Pass 1: 9037 // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary. 9038 // We also process and answer ARPs from our own kernel (no special treatment for localhost). 9039 // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them. 9040 // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below. 9041 if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa)) 9042 for (rr = m->ResourceRecords; rr; rr=rr->next) 9043 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa)) 9044 { 9045 static const char msg1[] = "ARP Req from owner -- re-probing"; 9046 static const char msg2[] = "Ignoring ARP Request from "; 9047 static const char msg3[] = "Creating Local ARP Cache entry "; 9048 static const char msg4[] = "Answering ARP Request from "; 9049 const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 : 9050 (rr->AnnounceCount == InitialAnnounceCount) ? msg2 : 9051 mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4; 9052 LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s", 9053 InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 9054 if (msg == msg1) RestartProbing(m, rr); 9055 else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID); 9056 else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b); 9057 } 9058 9059 // Pass 2: 9060 // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding. 9061 // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address, 9062 // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address). 9063 // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle. 9064 // If we see an apparently conflicting ARP, we check the sender hardware address: 9065 // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer. 9066 // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it. 9067 if (mDNSSameEthAddress(&arp->sha, &intf->MAC)) 9068 debugf("ARP from self for %.4a", &arp->tpa); 9069 else 9070 { 9071 if (!mDNSSameIPv4Address(arp->spa, zerov4Addr)) 9072 for (rr = m->ResourceRecords; rr; rr=rr->next) 9073 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa)) 9074 { 9075 RestartProbing(m, rr); 9076 if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC)) 9077 LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s", 9078 InterfaceNameForID(m, InterfaceID), 9079 mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ", 9080 &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr)); 9081 else 9082 { 9083 LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s", 9084 InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); 9085 SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); 9086 } 9087 } 9088 } 9089 9090 mDNS_Unlock(m); 9091 } 9092 else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0) 9093 { 9094 const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4; 9095 const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0); 9096 debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst); 9097 if (end >= required) 9098 { 9099 #define SSH_AsNumber 22 9100 #define ARD_AsNumber 3283 9101 #define IPSEC_AsNumber 4500 9102 static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } }; 9103 static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } }; 9104 static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } }; 9105 9106 mDNSBool wake = mDNSfalse; 9107 mDNSIPPort port = zeroIPPort; 9108 9109 switch (v4->protocol) 9110 { 9111 #define XX wake ? "Received" : "Ignoring", end-p 9112 case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst); 9113 break; 9114 9115 case 6: { 9116 const TCPHeader *const tcp = (const TCPHeader *)trans; 9117 port = tcp->dst; 9118 9119 // Plan to wake if 9120 // (a) RST is not set, AND 9121 // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone. 9122 wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1); 9123 9124 // For now, to reduce spurious wakeups, we wake only for TCP SYN, 9125 // except for ssh connections, where we'll wake for plain data packets too 9126 if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse; 9127 9128 LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX, 9129 &v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port), 9130 (tcp->flags & 2) ? " SYN" : "", 9131 (tcp->flags & 1) ? " FIN" : "", 9132 (tcp->flags & 4) ? " RST" : ""); 9133 } 9134 break; 9135 9136 case 17: { 9137 const UDPHeader *const udp = (const UDPHeader *)trans; 9138 mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]); 9139 port = udp->dst; 9140 wake = mDNStrue; 9141 9142 // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets 9143 if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF); 9144 9145 // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the 9146 // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port), 9147 // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this: 9148 // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total 9149 if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88); 9150 9151 LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port)); 9152 } 9153 break; 9154 9155 default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst); 9156 break; 9157 } 9158 9159 if (wake) 9160 { 9161 AuthRecord *rr, *r2; 9162 9163 mDNS_Lock(m); 9164 for (rr = m->ResourceRecords; rr; rr=rr->next) 9165 if (rr->resrec.InterfaceID == InterfaceID && 9166 rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst)) 9167 { 9168 const mDNSu8 *const tp = (v4->protocol == 6) ? (mDNSu8 *)"\x4_tcp" : (mDNSu8 *)"\x4_udp"; 9169 for (r2 = m->ResourceRecords; r2; r2=r2->next) 9170 if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) && 9171 r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) && 9172 SameDomainLabel(SkipLeadingLabels(r2->resrec.name, 2)->c, tp)) 9173 break; 9174 if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record 9175 if (r2) 9176 { 9177 rr->AnnounceCount = 0; 9178 LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s", 9179 InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2)); 9180 SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); 9181 } 9182 else 9183 LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d", 9184 InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port)); 9185 } 9186 mDNS_Unlock(m); 9187 } 9188 } 9189 } 9190 else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0) 9191 { 9192 debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst); 9193 (void)v6; 9194 } 9195 } 9196 9197mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name) 9198 { 9199 name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s", 9200 m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel); 9201 } 9202 9203mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) 9204 { 9205 if (result == mStatus_NameConflict) 9206 mDNS_RenameAndReregisterService(m, srs, mDNSNULL); 9207 else if (result == mStatus_MemFree) 9208 { 9209 if (m->SleepState) 9210 m->SPSState = 3; 9211 else 9212 { 9213 m->SPSState = (m->SPSSocket != mDNSNULL); 9214 if (m->SPSState) 9215 { 9216 domainlabel name; 9217 ConstructSleepProxyServerName(m, &name); 9218 mDNS_RegisterService(m, srs, 9219 &name, &SleepProxyServiceType, &localdomain, 9220 mDNSNULL, m->SPSSocket->port, // Host, port 9221 (mDNSu8 *)"", 1, // TXT data, length 9222 mDNSNULL, 0, // Subtypes (none) 9223 mDNSInterface_Any, // Interface ID 9224 SleepProxyServerCallback, mDNSNULL); // Callback and context 9225 } 9226 LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped"); 9227 } 9228 } 9229 } 9230 9231mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower) 9232 { 9233 // If turning off SPS, close our socket 9234 // (Do this first, BEFORE calling mDNS_DeregisterService below) 9235 if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; } 9236 9237 // If turning off, or changing type, deregister old name 9238 if (m->SPSState == 1 && sps != m->SPSType) 9239 { m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); } 9240 9241 // Record our new SPS parameters 9242 m->SPSType = sps; 9243 m->SPSPortability = port; 9244 m->SPSMarginalPower = marginalpower; 9245 m->SPSTotalPower = totpower; 9246 9247 // If turning on, open socket and advertise service 9248 if (sps) 9249 { 9250 if (!m->SPSSocket) 9251 { 9252 m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort); 9253 if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; } 9254 } 9255 if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree); 9256 } 9257 } 9258 9259// *************************************************************************** 9260#if COMPILER_LIKES_PRAGMA_MARK 9261#pragma mark - 9262#pragma mark - Startup and Shutdown 9263#endif 9264 9265mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 9266 { 9267 if (storage && numrecords) 9268 { 9269 mDNSu32 i; 9270 debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity)); 9271 for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1]; 9272 storage[numrecords-1].next = m->rrcache_free; 9273 m->rrcache_free = storage; 9274 m->rrcache_size += numrecords; 9275 } 9276 } 9277 9278mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords) 9279 { 9280 mDNS_Lock(m); 9281 mDNS_GrowCache_internal(m, storage, numrecords); 9282 mDNS_Unlock(m); 9283 } 9284 9285mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, 9286 CacheEntity *rrcachestorage, mDNSu32 rrcachesize, 9287 mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context) 9288 { 9289 mDNSu32 slot; 9290 mDNSs32 timenow; 9291 mStatus result; 9292 9293 if (!rrcachestorage) rrcachesize = 0; 9294 9295 m->p = p; 9296 m->KnownBugs = 0; 9297 m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise 9298 m->AdvertiseLocalAddresses = AdvertiseLocalAddresses; 9299 m->DivertMulticastAdvertisements = mDNSfalse; 9300 m->mDNSPlatformStatus = mStatus_Waiting; 9301 m->UnicastPort4 = zeroIPPort; 9302 m->UnicastPort6 = zeroIPPort; 9303 m->PrimaryMAC = zeroEthAddr; 9304 m->MainCallback = Callback; 9305 m->MainContext = Context; 9306 m->rec.r.resrec.RecordType = 0; 9307 9308 // For debugging: To catch and report locking failures 9309 m->mDNS_busy = 0; 9310 m->mDNS_reentrancy = 0; 9311 m->ShutdownTime = 0; 9312 m->lock_rrcache = 0; 9313 m->lock_Questions = 0; 9314 m->lock_Records = 0; 9315 9316 // Task Scheduling variables 9317 result = mDNSPlatformTimeInit(); 9318 if (result != mStatus_NoError) return(result); 9319 m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF); 9320 timenow = mDNS_TimeNow_NoLock(m); 9321 9322 m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section 9323 m->timenow_last = timenow; 9324 m->NextScheduledEvent = timenow; 9325 m->SuppressSending = timenow; 9326 m->NextCacheCheck = timenow + 0x78000000; 9327 m->NextScheduledQuery = timenow + 0x78000000; 9328 m->NextScheduledProbe = timenow + 0x78000000; 9329 m->NextScheduledResponse = timenow + 0x78000000; 9330 m->NextScheduledNATOp = timenow + 0x78000000; 9331 m->NextScheduledSPS = timenow + 0x78000000; 9332 m->RandomQueryDelay = 0; 9333 m->RandomReconfirmDelay = 0; 9334 m->PktNum = 0; 9335 m->SleepState = SleepState_Awake; 9336 m->SleepSeqNum = 0; 9337 m->SystemWakeOnLANEnabled = mDNSfalse; 9338 m->DelaySleep = 0; 9339 m->SleepLimit = 0; 9340 9341 // These fields only required for mDNS Searcher... 9342 m->Questions = mDNSNULL; 9343 m->NewQuestions = mDNSNULL; 9344 m->CurrentQuestion = mDNSNULL; 9345 m->LocalOnlyQuestions = mDNSNULL; 9346 m->NewLocalOnlyQuestions = mDNSNULL; 9347 m->rrcache_size = 0; 9348 m->rrcache_totalused = 0; 9349 m->rrcache_active = 0; 9350 m->rrcache_report = 10; 9351 m->rrcache_free = mDNSNULL; 9352 9353 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL; 9354 9355 mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize); 9356 9357 // Fields below only required for mDNS Responder... 9358 m->hostlabel.c[0] = 0; 9359 m->nicelabel.c[0] = 0; 9360 m->MulticastHostname.c[0] = 0; 9361 m->HIHardware.c[0] = 0; 9362 m->HISoftware.c[0] = 0; 9363 m->ResourceRecords = mDNSNULL; 9364 m->DuplicateRecords = mDNSNULL; 9365 m->NewLocalRecords = mDNSNULL; 9366 m->CurrentRecord = mDNSNULL; 9367 m->HostInterfaces = mDNSNULL; 9368 m->ProbeFailTime = 0; 9369 m->NumFailedProbes = 0; 9370 m->SuppressProbes = 0; 9371 9372#ifndef UNICAST_DISABLED 9373 m->NextuDNSEvent = timenow + 0x78000000; 9374 m->NextSRVUpdate = timenow + 0x78000000; 9375 m->SuppressStdPort53Queries = 0; 9376 9377 m->ServiceRegistrations = mDNSNULL; 9378 m->DNSServers = mDNSNULL; 9379 9380 m->Router = zeroAddr; 9381 m->AdvertisedV4 = zeroAddr; 9382 m->AdvertisedV6 = zeroAddr; 9383 9384 m->AuthInfoList = mDNSNULL; 9385 9386 m->ReverseMap.ThisQInterval = -1; 9387 m->StaticHostname.c[0] = 0; 9388 m->FQDN.c[0] = 0; 9389 m->Hostnames = mDNSNULL; 9390 m->AutoTunnelHostAddr.b[0] = 0; 9391 m->AutoTunnelHostAddrActive = mDNSfalse; 9392 m->AutoTunnelLabel.c[0] = 0; 9393 9394 m->RegisterSearchDomains = mDNSfalse; 9395 9396 // NAT traversal fields 9397 m->NATTraversals = mDNSNULL; 9398 m->CurrentNATTraversal = mDNSNULL; 9399 m->retryIntervalGetAddr = 0; // delta between time sent and retry 9400 m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry 9401 m->ExternalAddress = zerov4Addr; 9402 9403 m->NATMcastRecvskt = mDNSNULL; 9404 m->LastNATupseconds = 0; 9405 m->LastNATReplyLocalTime = timenow; 9406 m->LastNATMapResultCode = NATErr_None; 9407 9408 m->UPnPInterfaceID = 0; 9409 m->SSDPSocket = mDNSNULL; 9410 m->SSDPWANPPPConnection = mDNSfalse; 9411 m->UPnPRouterPort = zeroIPPort; 9412 m->UPnPSOAPPort = zeroIPPort; 9413 m->UPnPRouterURL = mDNSNULL; 9414 m->UPnPWANPPPConnection = mDNSfalse; 9415 m->UPnPSOAPURL = mDNSNULL; 9416 m->UPnPRouterAddressString = mDNSNULL; 9417 m->UPnPSOAPAddressString = mDNSNULL; 9418 m->SPSType = 0; 9419 m->SPSPortability = 0; 9420 m->SPSMarginalPower = 0; 9421 m->SPSTotalPower = 0; 9422 m->SPSState = 0; 9423 m->SPSProxyListChanged = mDNSNULL; 9424 m->SPSSocket = mDNSNULL; 9425 m->SPSBrowseCallback = mDNSNULL; 9426 m->ProxyRecords = 0; 9427 9428#endif 9429 9430#if APPLE_OSX_mDNSResponder 9431 m->TunnelClients = mDNSNULL; 9432#endif 9433 9434 result = mDNSPlatformInit(m); 9435 9436#ifndef UNICAST_DISABLED 9437 // It's better to do this *after* the platform layer has set up the 9438 // interface list and security credentials 9439 uDNS_SetupDNSConfig(m); // Get initial DNS configuration 9440#endif 9441 9442 return(result); 9443 } 9444 9445mDNSexport void mDNS_ConfigChanged(mDNS *const m) 9446 { 9447 if (m->SPSState == 1) 9448 { 9449 domainlabel name, newname; 9450 domainname type, domain; 9451 DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain); 9452 ConstructSleepProxyServerName(m, &newname); 9453 if (!SameDomainLabelCS(name.c, newname.c)) 9454 { 9455 LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c); 9456 // When SleepProxyServerCallback gets the mStatus_MemFree message, 9457 // it will reregister the service under the new name 9458 m->SPSState = 2; 9459 mDNS_DeregisterService(m, &m->SPSRecords); 9460 } 9461 } 9462 9463 if (m->MainCallback) 9464 m->MainCallback(m, mStatus_ConfigChanged); 9465 } 9466 9467mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) 9468 { 9469 (void)m; // unused 9470 debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c); 9471 mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result); 9472 } 9473 9474mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck) 9475 { 9476 mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative || 9477 cr->resrec.rrtype == kDNSType_A || 9478 cr->resrec.rrtype == kDNSType_AAAA || 9479 cr->resrec.rrtype == kDNSType_SRV; 9480 9481 (void) lameduck; 9482 (void) ptr; 9483 debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr)); 9484 9485 if (purge) mDNS_PurgeCacheResourceRecord(m, cr); 9486 else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); 9487 } 9488 9489mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) 9490 { 9491 mDNSu32 slot; 9492 CacheGroup *cg; 9493 CacheRecord *cr; 9494 9495 mDNSAddr v4, v6, r; 9496 domainname fqdn; 9497 DNSServer *ptr, **p = &m->DNSServers; 9498 const DNSServer *oldServers = m->DNSServers; 9499 DNSQuestion *q; 9500 9501 debugf("uDNS_SetupDNSConfig: entry"); 9502 9503 if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m); 9504 9505 mDNS_Lock(m); 9506 9507 // Let the platform layer get the current DNS information 9508 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand 9509 // (no need to hit the network with domain enumeration queries until we actually need that information). 9510 for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete; 9511 9512 mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL); 9513 9514 // Update our qDNSServer pointers before we go and free the DNSServer object memory 9515 for (q = m->Questions; q; q=q->next) 9516 if (!mDNSOpaque16IsZero(q->TargetQID)) 9517 { 9518 DNSServer *s = GetServerForName(m, &q->qname); 9519 DNSServer *t = q->qDNSServer; 9520 if (t != s) 9521 { 9522 // If DNS Server for this question has changed, reactivate it 9523 debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)", 9524 t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"", 9525 s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"", 9526 q->qname.c, DNSTypeName(q->qtype)); 9527 q->qDNSServer = s; 9528 q->unansweredQueries = 0; 9529 ActivateUnicastQuery(m, q, mDNStrue); 9530 } 9531 } 9532 9533 // Flush all records that match a new resolver 9534 FORALL_CACHERECORDS(slot, cg, cr) 9535 { 9536 ptr = GetServerForName(m, cr->resrec.name); 9537 if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID) 9538 PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse); 9539 } 9540 9541 while (*p) 9542 { 9543 if (((*p)->flags & DNSServer_FlagDelete) != 0) 9544 { 9545 // Scan our cache, looking for uDNS records that we would have queried this server for. 9546 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc. 9547 // different DNS servers can give different answers to the same question. 9548 ptr = *p; 9549 ptr->flags &= ~DNSServer_FlagDelete; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted 9550 FORALL_CACHERECORDS(slot, cg, cr) 9551 if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr) 9552 PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue); 9553 *p = (*p)->next; 9554 debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); 9555 mDNSPlatformMemFree(ptr); 9556 } 9557 else 9558 { 9559 (*p)->flags &= ~DNSServer_FlagNew; 9560 p = &(*p)->next; 9561 } 9562 } 9563 9564 // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs). 9565 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless. 9566 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour. 9567 // Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated. 9568 if ((m->DNSServers != mDNSNULL) != (oldServers != mDNSNULL)) 9569 { 9570 int count = 0; 9571 FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; } 9572 LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache", 9573 m->DNSServers ? "DNS server became" : "No DNS servers", count); 9574 } 9575 9576 // If we no longer have any DNS servers, we need to force anything that needs to get zone data 9577 // to get that information again (which will fail, since we have no more DNS servers) 9578 if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL)) RestartRecordGetZoneData(m); 9579 9580 // Did our FQDN change? 9581 if (!SameDomainName(&fqdn, &m->FQDN)) 9582 { 9583 if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN); 9584 9585 AssignDomainName(&m->FQDN, &fqdn); 9586 9587 if (m->FQDN.c[0]) 9588 { 9589 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); 9590 mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL); 9591 } 9592 } 9593 9594 mDNS_Unlock(m); 9595 9596 // handle router and primary interface changes 9597 v4 = v6 = r = zeroAddr; 9598 v4.type = r.type = mDNSAddrType_IPv4; 9599 9600 if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4)) 9601 { 9602 mDNS_SetPrimaryInterfaceInfo(m, 9603 !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL, 9604 !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL, 9605 !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL); 9606 } 9607 else 9608 { 9609 mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL); 9610 if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure 9611 } 9612 9613 return mStatus_NoError; 9614 } 9615 9616mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) 9617 { 9618 m->mDNSPlatformStatus = result; 9619 if (m->MainCallback) 9620 { 9621 mDNS_Lock(m); 9622 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback 9623 m->MainCallback(m, mStatus_NoError); 9624 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again 9625 mDNS_Unlock(m); 9626 } 9627 } 9628 9629extern ServiceRecordSet *CurrentServiceRecordSet; 9630 9631mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start) 9632 { 9633 m->CurrentRecord = start; 9634 while (m->CurrentRecord) 9635 { 9636 AuthRecord *rr = m->CurrentRecord; 9637 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) 9638 { 9639 LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr)); 9640 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); 9641 } 9642 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because 9643 // the list may have been changed in that call. 9644 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now 9645 m->CurrentRecord = rr->next; 9646 } 9647 } 9648 9649mDNSexport void mDNS_StartExit(mDNS *const m) 9650 { 9651 NetworkInterfaceInfo *intf; 9652 AuthRecord *rr; 9653 9654 mDNS_Lock(m); 9655 9656 m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); 9657 9658 mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here 9659 mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0); 9660 mDNS_ReclaimLockAfterCallback(); 9661 9662#ifndef UNICAST_DISABLED 9663 { 9664 SearchListElem *s; 9665 SuspendLLQs(m); 9666 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here, 9667 // because we deregister all records and services later in this routine 9668 while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn); 9669 9670 // For each member of our SearchList, deregister any records it may have created, and cut them from the list. 9671 // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list) 9672 // and we may crash because the list still contains dangling pointers. 9673 for (s = SearchList; s; s = s->next) 9674 while (s->AuthRecs) 9675 { 9676 ARListElem *dereg = s->AuthRecs; 9677 s->AuthRecs = s->AuthRecs->next; 9678 mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal); // Memory will be freed in the FreeARElemCallback 9679 } 9680 } 9681#endif 9682 9683 for (intf = m->HostInterfaces; intf; intf = intf->next) 9684 if (intf->Advertise) 9685 DeadvertiseInterface(m, intf); 9686 9687 // Shut down all our active NAT Traversals 9688 while (m->NATTraversals) 9689 { 9690 NATTraversalInfo *t = m->NATTraversals; 9691 mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process 9692 9693 // After stopping the NAT Traversal, we zero out the fields. 9694 // This has particularly important implications for our AutoTunnel records -- 9695 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree 9696 // handlers to just turn around and attempt to re-register those same records. 9697 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this. 9698 t->ExternalAddress = zerov4Addr; 9699 t->ExternalPort = zeroIPPort; 9700 t->Lifetime = 0; 9701 t->Result = mStatus_NoError; 9702 } 9703 9704 // Make sure there are nothing but deregistering records remaining in the list 9705 if (m->CurrentRecord) 9706 LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); 9707 9708 // We're in the process of shutting down, so queries, etc. are no longer available. 9709 // Consequently, determining certain information, e.g. the uDNS update server's IP 9710 // address, will not be possible. The records on the main list are more likely to 9711 // already contain such information, so we deregister the duplicate records first. 9712 LogInfo("mDNS_StartExit: Deregistering duplicate resource records"); 9713 DeregLoop(m, m->DuplicateRecords); 9714 LogInfo("mDNS_StartExit: Deregistering resource records"); 9715 DeregLoop(m, m->ResourceRecords); 9716 9717 // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records, 9718 // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay. 9719 if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond) 9720 { 9721 m->NextScheduledResponse = m->timenow; 9722 m->SuppressSending = 0; 9723 } 9724 9725#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST 9726 CurrentServiceRecordSet = m->ServiceRegistrations; 9727 while (CurrentServiceRecordSet) 9728 { 9729 ServiceRecordSet *srs = CurrentServiceRecordSet; 9730 LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c); 9731 uDNS_DeregisterService(m, srs); 9732 if (CurrentServiceRecordSet == srs) 9733 CurrentServiceRecordSet = srs->uDNS_next; 9734 } 9735#endif 9736 9737 if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations"); 9738 else LogInfo("mDNS_StartExit: No deregistering records remain"); 9739 9740 if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations"); 9741 else LogInfo("mDNS_StartExit: No deregistering uDNS services remain"); 9742 9743 for (rr = m->DuplicateRecords; rr; rr = rr->next) 9744 LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); 9745 9746 // If any deregistering records remain, send their deregistration announcements before we exit 9747 if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); 9748 9749 mDNS_Unlock(m); 9750 9751 LogInfo("mDNS_StartExit: done"); 9752 } 9753 9754mDNSexport void mDNS_FinalExit(mDNS *const m) 9755 { 9756 mDNSu32 rrcache_active = 0; 9757 mDNSu32 rrcache_totalused = 0; 9758 mDNSu32 slot; 9759 AuthRecord *rr; 9760 ServiceRecordSet *srs; 9761 9762 LogInfo("mDNS_FinalExit: mDNSPlatformClose"); 9763 mDNSPlatformClose(m); 9764 9765 rrcache_totalused = m->rrcache_totalused; 9766 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) 9767 { 9768 while (m->rrcache_hash[slot]) 9769 { 9770 CacheGroup *cg = m->rrcache_hash[slot]; 9771 while (cg->members) 9772 { 9773 CacheRecord *cr = cg->members; 9774 cg->members = cg->members->next; 9775 if (cr->CRActiveQuestion) rrcache_active++; 9776 ReleaseCacheRecord(m, cr); 9777 } 9778 cg->rrcache_tail = &cg->members; 9779 ReleaseCacheGroup(m, &m->rrcache_hash[slot]); 9780 } 9781 } 9782 debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); 9783 if (rrcache_active != m->rrcache_active) 9784 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); 9785 9786 for (rr = m->ResourceRecords; rr; rr = rr->next) 9787 LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr)); 9788 9789 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) 9790 LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c); 9791 9792 LogInfo("mDNS_FinalExit: done"); 9793 } 9794