1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
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).
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.)
38 Change History (most recent first):
41 Revision 1.970.2.1 2009/07/23 23:36:04 cheshire
42 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
44 Revision 1.970 2009/07/11 01:59:27 cheshire
45 <rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
46 When going to sleep, try calling ActivateLocalProxy before registering with remote sleep proxy
48 Revision 1.969 2009/06/30 21:18:19 cheshire
49 <rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
51 1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
52 2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
54 Revision 1.968 2009/06/29 23:51:09 cheshire
55 <rdar://problem/6690034> Can't bind to Active Directory
57 Revision 1.967 2009/06/27 00:25:27 cheshire
58 <rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
59 Removed overly-complicate and ineffective multi-packet known-answer snooping code
60 (Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
62 Revision 1.966 2009/06/26 01:55:55 cheshire
63 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
64 Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
65 add additional NSEC records only when there's space to do that without having to generate an additional packet
67 Revision 1.965 2009/06/24 22:14:21 cheshire
68 <rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
70 Revision 1.964 2009/06/03 23:07:13 cheshire
71 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
72 Large records were not being added in cases where an NSEC record was also required
74 Revision 1.963 2009/05/28 00:39:19 cheshire
75 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
76 After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
78 Revision 1.962 2009/05/19 23:40:37 cheshire
79 <rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
80 Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
82 Revision 1.961 2009/05/19 23:00:43 cheshire
83 Improved comments and debugging messages
85 Revision 1.960 2009/05/13 17:25:33 mkrochma
86 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
87 Sleep proxy client should only look for services being advertised via Multicast
89 Revision 1.959 2009/05/12 23:10:31 cheshire
90 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
91 Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
93 Revision 1.958 2009/05/12 19:19:20 cheshire
94 <rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
96 Revision 1.957 2009/05/07 23:56:25 cheshire
97 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
98 To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
100 Revision 1.956 2009/05/07 23:46:27 cheshire
101 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
103 Revision 1.955 2009/05/07 23:40:54 cheshire
104 Minor code rearrangement in preparation for upcoming changes
106 Revision 1.954 2009/05/01 21:28:34 cheshire
107 <rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
108 No longer suspend network operations after we've acknowledged that the machine is going to sleep,
109 because other software may not have yet acknowledged the sleep event, and may be still trying
110 to do unicast DNS queries or other Bonjour operations.
112 Revision 1.953 2009/05/01 19:17:35 cheshire
113 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
115 Revision 1.952 2009/05/01 19:16:45 mcguire
116 <rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
118 Revision 1.951 2009/04/28 23:48:19 jessic2
119 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0
121 Revision 1.950 2009/04/25 01:17:10 mcguire
122 Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
124 Revision 1.949 2009/04/25 01:11:02 mcguire
125 Refactor: create separate function: RestartRecordGetZoneData
127 Revision 1.948 2009/04/24 21:25:16 cheshire
128 <rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
130 Revision 1.947 2009/04/24 19:41:12 mcguire
131 <rdar://problem/6791775> 4 second delay in DNS response
133 Revision 1.946 2009/04/24 19:28:39 mcguire
134 <rdar://problem/6791775> 4 second delay in DNS response
136 Revision 1.945 2009/04/24 00:30:30 cheshire
137 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
138 Added code to generate and process NSEC records
140 Revision 1.944 2009/04/23 22:06:29 cheshire
141 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
142 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
144 Revision 1.943 2009/04/22 01:19:56 jessic2
145 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
147 Revision 1.942 2009/04/21 02:13:29 cheshire
148 <rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
149 Made code less susceptible to being tricked by stale packets echoed back from the network.
151 Revision 1.941 2009/04/15 22:22:23 mcguire
152 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
153 Additional fix: protect against deref of NULL
155 Revision 1.940 2009/04/15 20:42:51 mcguire
156 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
158 Revision 1.939 2009/04/11 00:19:32 jessic2
159 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
161 Revision 1.938 2009/04/06 23:44:57 cheshire
162 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
164 Revision 1.937 2009/04/04 00:14:49 mcguire
165 fix logging in BeginSleepProcessing
167 Revision 1.936 2009/04/04 00:10:59 mcguire
168 don't ignore m->SystemWakeOnLANEnabled when going to sleep
170 Revision 1.935 2009/04/01 17:50:11 mcguire
173 Revision 1.934 2009/03/27 17:17:58 cheshire
174 Improved "Ignoring suspect uDNS response" debugging message
176 Revision 1.933 2009/03/21 02:40:21 cheshire
177 <rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
179 Revision 1.932 2009/03/20 23:53:03 jessic2
180 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
182 Revision 1.931 2009/03/18 19:08:15 cheshire
183 Show old/new sleep sequence numbers in logical order
185 Revision 1.930 2009/03/17 23:40:45 cheshire
186 For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
188 Revision 1.929 2009/03/17 21:55:56 cheshire
189 Fixed mistake in logic for decided when we're ready to go to sleep
191 Revision 1.928 2009/03/17 19:48:12 cheshire
192 <rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
194 Revision 1.927 2009/03/17 01:22:56 cheshire
195 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
196 Initial support for resolving up to three Sleep Proxies in parallel
198 Revision 1.926 2009/03/17 01:05:07 mcguire
199 <rdar://problem/6657640> Reachability fixes on DNS config change
201 Revision 1.925 2009/03/13 01:35:36 mcguire
202 <rdar://problem/6657640> Reachability fixes on DNS config change
204 Revision 1.924 2009/03/10 23:45:20 cheshire
205 Added comments explaining usage of SetSPSProxyListChanged()
207 Revision 1.923 2009/03/09 21:53:02 cheshire
208 <rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
210 Revision 1.922 2009/03/09 21:30:17 cheshire
211 Improved some LogSPS messages; made RestartProbing() subroutine
213 Revision 1.921 2009/03/06 22:53:31 cheshire
214 Don't bother registering with Sleep Proxy if we have no advertised services
216 Revision 1.920 2009/03/06 20:08:55 cheshire
217 <rdar://problem/6601429> Sleep Proxy: Return error responses to clients
219 Revision 1.919 2009/03/05 21:54:43 cheshire
220 Improved "Sleep Proxy Server started / stopped" message
222 Revision 1.918 2009/03/04 01:37:14 cheshire
223 <rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
225 Revision 1.917 2009/03/03 23:14:25 cheshire
226 Got rid of code duplication by making subroutine "SetupOwnerOpt"
228 Revision 1.916 2009/03/03 23:04:43 cheshire
229 For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
231 Revision 1.915 2009/03/03 22:51:53 cheshire
232 <rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
234 Revision 1.914 2009/03/03 00:46:09 cheshire
235 Additional debugging information in ResolveSimultaneousProbe
237 Revision 1.913 2009/02/27 03:08:47 cheshire
238 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
240 Revision 1.912 2009/02/27 02:31:28 cheshire
241 Improved "Record not found in list" debugging message
243 Revision 1.911 2009/02/21 01:42:11 cheshire
246 Revision 1.910 2009/02/19 01:50:53 cheshire
247 Converted some LogInfo messages to LogSPS
249 Revision 1.909 2009/02/14 00:04:59 cheshire
250 Left-justify interface names
252 Revision 1.908 2009/02/13 19:40:07 cheshire
253 Improved alignment of LogSPS messages
255 Revision 1.907 2009/02/13 18:16:05 cheshire
256 Fixed some compile warnings
258 Revision 1.906 2009/02/13 06:10:17 cheshire
259 Convert LogOperation messages to LogInfo
261 Revision 1.905 2009/02/12 20:57:24 cheshire
262 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
264 Revision 1.904 2009/02/11 02:37:29 cheshire
265 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
266 Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
267 so that it happens correctly even when we delay re-sleep due to a very short wakeup.
269 Revision 1.903 2009/02/09 23:34:31 cheshire
270 Additional logging for debugging unknown packets
272 Revision 1.902 2009/02/07 05:57:01 cheshire
273 Fixed debugging log message
275 Revision 1.901 2009/02/07 02:57:31 cheshire
276 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
278 Revision 1.900 2009/02/02 21:29:24 cheshire
279 <rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
280 If Negative response for our special Microsoft Active Directory "local SOA" check has no
281 SOA record in the authority section, assume we should cache the negative result for 24 hours
283 Revision 1.899 2009/01/31 00:37:50 cheshire
284 When marking cache records for deletion in response to a uDNS response,
285 make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
287 Revision 1.898 2009/01/30 23:49:20 cheshire
288 Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
290 Revision 1.897 2009/01/30 22:04:49 cheshire
291 Workaround to reduce load on root name servers when caching the SOA record for "."
293 Revision 1.896 2009/01/30 22:00:05 cheshire
294 Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
296 Revision 1.895 2009/01/30 17:46:39 cheshire
297 Improved debugging messages for working out why spurious name conflicts are happening
299 Revision 1.894 2009/01/30 00:22:09 cheshire
300 <rdar://problem/6540743> No announcement after probing & no conflict notice
302 Revision 1.893 2009/01/29 22:27:03 mcguire
303 <rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
305 Revision 1.892 2009/01/24 01:38:23 cheshire
306 Fixed error in logic for targeted queries
308 Revision 1.891 2009/01/22 02:14:25 cheshire
309 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
311 Revision 1.890 2009/01/22 00:45:02 cheshire
312 Improved SPS debugging log messages; we are eligible to start answering ARP requests
313 after we send our first announcement, not after we send our last probe
315 Revision 1.889 2009/01/21 03:43:56 mcguire
316 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
318 Revision 1.888 2009/01/20 00:27:43 mcguire
319 <rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
321 Revision 1.887 2009/01/17 05:14:37 cheshire
322 Convert SendQueries Probe messages to LogSPS messages
324 Revision 1.886 2009/01/17 03:43:09 cheshire
325 Added SPSLogging switch to facilitate Sleep Proxy Server debugging
327 Revision 1.885 2009/01/16 22:44:18 cheshire
328 <rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
330 Revision 1.884 2009/01/16 21:43:52 cheshire
331 Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
333 Revision 1.883 2009/01/16 21:11:18 cheshire
334 When purging expired Sleep Proxy records, need to check DuplicateRecords list too
336 Revision 1.882 2009/01/16 19:54:28 cheshire
337 Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
339 Revision 1.881 2009/01/14 01:38:38 mcguire
340 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
342 Revision 1.880 2009/01/10 01:51:19 cheshire
343 q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
345 Revision 1.879 2009/01/10 01:43:52 cheshire
346 Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
348 Revision 1.878 2009/01/10 01:38:10 cheshire
349 Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
351 Revision 1.877 2009/01/10 01:36:08 cheshire
352 Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
354 Revision 1.876 2009/01/09 22:56:06 cheshire
355 Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
357 Revision 1.875 2009/01/09 22:54:46 cheshire
358 When tranferring record from DuplicateRecords list to ResourceRecords list,
359 need to copy across state of 'Answered Local-Only-Questions' flag
361 Revision 1.874 2009/01/07 23:07:24 cheshire
362 <rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
364 Revision 1.873 2008/12/17 00:18:59 mkrochma
365 Change some LogMsg to LogOperation before submitting
367 Revision 1.872 2008/12/12 01:30:40 cheshire
368 Update platform-layer BPF filters when we add or remove AddressProxy records
370 Revision 1.871 2008/12/10 02:25:31 cheshire
371 Minor fixes to use of LogClientOperations symbol
373 Revision 1.870 2008/12/10 02:11:41 cheshire
374 ARMv5 compiler doesn't like uncommented stuff after #endif
376 Revision 1.869 2008/12/05 02:35:24 mcguire
377 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
379 Revision 1.868 2008/12/04 21:08:51 mcguire
380 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
382 Revision 1.867 2008/11/26 21:19:36 cheshire
383 <rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
385 Revision 1.866 2008/11/26 20:32:46 cheshire
386 <rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
387 Update advertised name when Sleep Proxy "intent" metric changes
389 Revision 1.865 2008/11/26 19:49:25 cheshire
390 Record originally-requested port in sr->NATinfo.IntPort
392 Revision 1.864 2008/11/26 19:02:37 cheshire
393 Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
395 Revision 1.863 2008/11/26 03:59:03 cheshire
396 Wait 30 seconds before starting ARP Announcements
398 Revision 1.862 2008/11/25 23:43:07 cheshire
399 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
400 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
402 Revision 1.861 2008/11/25 22:46:30 cheshire
403 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
405 Revision 1.860 2008/11/25 05:07:15 cheshire
406 <rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
408 Revision 1.859 2008/11/20 02:07:56 cheshire
409 <rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
411 Revision 1.858 2008/11/20 01:38:36 cheshire
412 For consistency with other parts of the code, changed code to only check
413 that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
415 Revision 1.857 2008/11/14 22:55:18 cheshire
418 Revision 1.856 2008/11/14 21:08:28 cheshire
419 Only put owner option in query packet if we have a non-zero MAC address to put
420 Only process owner options in received query packets if the MAC address in the option is non-zero
422 Revision 1.855 2008/11/14 02:29:54 cheshire
423 If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
425 Revision 1.854 2008/11/14 00:00:53 cheshire
426 After client machine wakes up, Sleep Proxy machine need to remove any records
427 it was temporarily holding as proxy for that client
429 Revision 1.853 2008/11/13 19:07:30 cheshire
430 Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
432 Revision 1.852 2008/11/12 23:23:11 cheshire
433 Before waking a host, check to see if it has an SRV record advertising
434 a service on the port in question, and if not, don't bother waking it.
436 Revision 1.851 2008/11/12 01:54:15 cheshire
437 <rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
438 It turns out it is beneficial to have the domain on the end, because it allows better name compression
440 Revision 1.850 2008/11/11 01:56:57 cheshire
441 Improved name conflict log messages
443 Revision 1.849 2008/11/06 23:50:43 cheshire
444 Allow plain (non-SYN) ssh data packets to wake sleeping host
446 Revision 1.848 2008/11/05 02:40:28 mkrochma
447 Change mDNS_SetFQDN syslog mesage to debugf
449 Revision 1.847 2008/11/04 23:06:50 cheshire
450 Split RDataBody union definition into RDataBody and RDataBody2, and removed
451 SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
453 Revision 1.846 2008/11/04 22:21:44 cheshire
454 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
456 Revision 1.845 2008/11/03 23:52:05 cheshire
457 Improved ARP debugging messages to differentiate ARP Announcements from Requests
459 Revision 1.844 2008/10/31 23:43:51 cheshire
460 Fixed compile error in Posix build
462 Revision 1.843 2008/10/31 22:55:04 cheshire
463 Initial support for structured SPS names
465 Revision 1.842 2008/10/30 00:12:07 cheshire
466 Fixed spin when PutSPSRec fails to put a record because it's too big to fit
468 Revision 1.841 2008/10/29 23:23:38 cheshire
469 Refined cache size reporting to go in steps of 1000 when number is above 1000
471 Revision 1.840 2008/10/29 21:34:10 cheshire
472 Removed some old debugging messages
474 Revision 1.839 2008/10/29 21:31:32 cheshire
475 Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
477 Revision 1.838 2008/10/28 18:30:37 cheshire
478 Added debugging message in mDNSCoreReceiveRawPacket
480 Revision 1.837 2008/10/24 23:58:05 cheshire
481 Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
483 Revision 1.836 2008/10/24 23:18:18 cheshire
484 If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
486 Revision 1.835 2008/10/24 23:07:59 cheshire
487 Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
489 Revision 1.834 2008/10/24 23:03:24 cheshire
490 Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
492 Revision 1.833 2008/10/24 23:01:26 cheshire
493 To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
495 Revision 1.832 2008/10/24 22:58:24 cheshire
496 For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
498 Revision 1.831 2008/10/24 22:50:41 cheshire
499 When waking SPS client, include interface name in syslog message
501 Revision 1.830 2008/10/24 20:50:34 cheshire
502 Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
504 Revision 1.829 2008/10/23 23:55:57 cheshire
505 Fixed some missing "const" declarations
507 Revision 1.828 2008/10/23 22:25:56 cheshire
508 Renamed field "id" to more descriptive "updateid"
510 Revision 1.827 2008/10/23 03:06:25 cheshire
511 Fixed "Waking host" log message
513 Revision 1.826 2008/10/22 23:21:30 cheshire
514 Make sure we have enough bytes before reading into the transport-level header
516 Revision 1.825 2008/10/22 22:31:53 cheshire
517 Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
519 Revision 1.824 2008/10/22 20:00:31 cheshire
520 If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
522 Revision 1.823 2008/10/22 19:55:35 cheshire
523 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
525 Revision 1.822 2008/10/22 01:41:39 cheshire
526 Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
528 Revision 1.821 2008/10/22 01:12:53 cheshire
529 Answer ARP Requests for any IP address we're proxying for
531 Revision 1.820 2008/10/21 01:11:11 cheshire
532 Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
534 Revision 1.819 2008/10/20 22:16:27 cheshire
535 Updated comments; increased cache shedding threshold from 3000 to 4000
537 Revision 1.818 2008/10/16 22:01:54 cheshire
538 Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
540 Revision 1.817 2008/10/16 21:40:49 cheshire
541 Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
543 Revision 1.816 2008/10/15 23:12:36 cheshire
544 On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
546 Revision 1.815 2008/10/15 20:46:38 cheshire
547 When transferring records to SPS, include Lease Option
549 Revision 1.814 2008/10/15 19:51:27 cheshire
550 Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
552 Revision 1.813 2008/10/15 00:09:23 cheshire
553 When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
555 Revision 1.812 2008/10/15 00:01:40 cheshire
556 When going to sleep, discover and resolve SPS, and if successful, transfer records to it
558 Revision 1.811 2008/10/14 23:51:57 cheshire
559 Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
561 Revision 1.810 2008/10/14 21:37:55 cheshire
562 Removed unnecessary m->BeSleepProxyServer variable
564 Revision 1.809 2008/10/10 23:45:48 cheshire
565 For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
566 not a wide-area unicast hostname
568 Revision 1.808 2008/10/09 18:59:19 cheshire
569 Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
571 Revision 1.807 2008/10/07 15:56:58 cheshire
572 Fixed "unused variable" warnings in non-debug builds
574 Revision 1.806 2008/10/04 00:53:37 cheshire
575 On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
577 Revision 1.805 2008/10/03 18:17:28 cheshire
578 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
579 Update advertised Sleep Proxy Server name if user changes computer name
581 Revision 1.804 2008/10/03 01:26:06 mcguire
582 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
583 Put back Duplicate Record check
585 Revision 1.803 2008/10/02 23:38:56 mcguire
586 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
588 Revision 1.802 2008/10/02 23:13:48 cheshire
589 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
590 Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
592 Revision 1.801 2008/10/02 22:51:04 cheshire
593 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
594 Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
596 Revision 1.800 2008/10/02 22:13:15 cheshire
597 <rdar://problem/6230680> 100ms delay on shutdown
598 Additional refinement: Also need to clear m->SuppressSending
600 Revision 1.799 2008/09/29 20:12:37 cheshire
601 Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
603 Revision 1.798 2008/09/26 19:53:14 cheshire
604 Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
606 Revision 1.797 2008/09/25 20:40:59 cheshire
607 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
608 In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
610 Revision 1.796 2008/09/25 20:17:10 cheshire
611 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
612 Added defensive code to make sure *all* records of a ServiceRecordSet have
613 completed deregistering before we pass on the mStatus_MemFree message
615 Revision 1.795 2008/09/25 00:30:11 cheshire
616 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
618 Revision 1.794 2008/09/24 23:48:05 cheshire
619 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
620 it only needs to access the embedded SRV member of the set
622 Revision 1.793 2008/09/23 04:11:53 cheshire
623 <rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
625 Revision 1.792 2008/09/23 02:30:07 cheshire
626 Get rid of PutResourceRecordCappedTTL()
628 Revision 1.791 2008/09/20 00:34:21 mcguire
629 <rdar://problem/6129039> BTMM: Add support for WANPPPConnection
631 Revision 1.790 2008/09/18 22:46:34 cheshire
632 <rdar://problem/6230680> 100ms delay on shutdown
634 Revision 1.789 2008/09/18 06:15:06 mkrochma
635 <rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
637 Revision 1.788 2008/09/16 21:11:41 cheshire
638 <rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
640 Revision 1.787 2008/09/05 22:53:24 cheshire
641 Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
643 Revision 1.786 2008/09/05 22:23:28 cheshire
644 Moved initialization of "question->LocalSocket" to more logical place
646 Revision 1.785 2008/08/14 19:20:55 cheshire
647 <rdar://problem/6143846> Negative responses over TCP incorrectly rejected
649 Revision 1.784 2008/08/13 00:47:53 mcguire
650 Handle failures when packet logging
652 Revision 1.783 2008/07/25 07:09:51 mcguire
653 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
655 Revision 1.782 2008/07/24 20:23:03 cheshire
656 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
658 Revision 1.781 2008/07/18 21:37:35 mcguire
659 <rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
661 Revision 1.780 2008/07/18 02:24:36 cheshire
662 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
663 Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
664 we're still on our first or second query after an interface registration or wake from sleep).
666 Revision 1.779 2008/07/18 01:05:23 cheshire
667 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
669 Revision 1.778 2008/06/26 17:24:11 mkrochma
670 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
672 Revision 1.777 2008/06/19 01:20:48 mcguire
673 <rdar://problem/4206534> Use all configured DNS servers
675 Revision 1.776 2008/04/17 20:14:14 cheshire
676 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
678 Revision 1.775 2008/03/26 01:53:34 mcguire
679 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
681 Revision 1.774 2008/03/17 17:46:08 mcguire
682 When activating an LLQ, reset all the important state and destroy any tcp connection,
683 so that everything will be restarted as if the question had just been asked.
684 Also reset servPort, so that the SOA query will be re-issued.
686 Revision 1.773 2008/03/14 22:52:36 mcguire
687 <rdar://problem/5321824> write status to the DS
688 Update status when any unicast LLQ is started
690 Revision 1.772 2008/03/06 02:48:34 mcguire
691 <rdar://problem/5321824> write status to the DS
693 Revision 1.771 2008/02/26 22:04:44 cheshire
694 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
695 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
696 question while it's still in our 'm->NewQuestions' section of the list
698 Revision 1.770 2008/02/22 23:09:02 cheshire
699 <rdar://problem/5338420> BTMM: Not processing additional records
701 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
702 2. Once we decide a record is acceptable, we can break out of the loop
704 Revision 1.769 2008/02/22 00:00:19 cheshire
705 <rdar://problem/5338420> BTMM: Not processing additional records
707 Revision 1.768 2008/02/19 23:26:50 cheshire
708 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
710 Revision 1.767 2007/12/22 02:25:29 cheshire
711 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
713 Revision 1.766 2007/12/15 01:12:27 cheshire
714 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
716 Revision 1.765 2007/12/15 00:18:51 cheshire
717 Renamed question->origLease to question->ReqLease
719 Revision 1.764 2007/12/14 00:49:53 cheshire
720 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
721 the CurrentServiceRecordSet mechanism to guard against services being deleted,
722 just like the record deregistration loop uses m->CurrentRecord.
724 Revision 1.763 2007/12/13 20:20:17 cheshire
725 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
726 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
727 inline a function defined in a different compilation unit) and therefore optimized better.
729 Revision 1.762 2007/12/13 00:13:03 cheshire
730 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
732 Revision 1.761 2007/12/13 00:03:31 cheshire
733 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
735 Revision 1.760 2007/12/08 00:36:19 cheshire
736 <rdar://problem/5636422> Updating TXT records is too slow
737 Remove unnecessary delays on announcing record updates, and on processing them on reception
739 Revision 1.759 2007/12/07 22:41:29 cheshire
740 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
741 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
743 Revision 1.758 2007/12/07 00:45:57 cheshire
744 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
746 Revision 1.757 2007/12/06 00:22:27 mcguire
747 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
749 Revision 1.756 2007/12/05 01:52:30 cheshire
750 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
751 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
753 Revision 1.755 2007/12/03 23:36:45 cheshire
754 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
755 Need to check GetServerForName() result is non-null before dereferencing pointer
757 Revision 1.754 2007/12/01 01:21:27 jgraessley
758 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
760 Revision 1.753 2007/12/01 00:44:15 cheshire
761 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
763 Revision 1.752 2007/11/14 01:10:51 cheshire
764 Fixed LogOperation() message wording
766 Revision 1.751 2007/10/30 23:49:41 cheshire
767 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
768 LLQ state was not being transferred properly between duplicate questions
770 Revision 1.750 2007/10/29 23:58:52 cheshire
771 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
772 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
774 Revision 1.749 2007/10/29 21:28:36 cheshire
775 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
777 Revision 1.748 2007/10/29 20:02:50 cheshire
778 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
780 Revision 1.747 2007/10/26 22:53:50 cheshire
781 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
782 instead of replicating the logic in both places
784 Revision 1.746 2007/10/25 22:48:50 cheshire
785 Added LogOperation message saying when we restart GetZoneData for record and service registrations
787 Revision 1.745 2007/10/25 20:48:47 cheshire
788 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
790 Revision 1.744 2007/10/25 20:06:14 cheshire
791 Don't try to do SOA queries using private DNS (TLS over TCP) queries
793 Revision 1.743 2007/10/25 00:12:46 cheshire
794 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
795 Retrigger service registrations whenever a new network interface is added
797 Revision 1.742 2007/10/24 22:40:06 cheshire
798 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
799 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
801 Revision 1.741 2007/10/24 00:50:29 cheshire
802 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
803 Retrigger record registrations whenever a new network interface is added
805 Revision 1.740 2007/10/23 00:38:03 cheshire
806 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
807 or code will spin sending the same cache expiration query repeatedly
809 Revision 1.739 2007/10/22 23:46:41 cheshire
810 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
811 Need to clear question->nta pointer after calling CancelGetZoneData()
813 Revision 1.738 2007/10/19 22:08:49 cheshire
814 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
815 Additional fixes and refinements
817 Revision 1.737 2007/10/18 23:06:42 cheshire
818 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
819 Additional fixes and refinements
821 Revision 1.736 2007/10/18 20:23:17 cheshire
822 Moved SuspendLLQs into mDNS.c, since it's only called from one place
824 Revision 1.735 2007/10/18 00:12:34 cheshire
825 Fixed "unused variable" compiler warning
827 Revision 1.734 2007/10/17 22:49:54 cheshire
828 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
830 Revision 1.733 2007/10/17 22:37:23 cheshire
831 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
833 Revision 1.732 2007/10/17 21:53:51 cheshire
834 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
836 Revision 1.731 2007/10/17 18:37:50 cheshire
837 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
838 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
840 Revision 1.730 2007/10/16 21:16:07 cheshire
841 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
843 Revision 1.729 2007/10/05 17:56:10 cheshire
844 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
846 Revision 1.728 2007/10/04 23:18:14 cheshire
847 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
849 Revision 1.727 2007/10/04 22:51:57 cheshire
850 Added debugging LogOperation message to show when we're sending cache expiration queries
852 Revision 1.726 2007/10/03 00:14:24 cheshire
853 Removed write to null to generate stack trace for SetNextQueryTime locking failure
855 Revision 1.725 2007/10/02 21:11:08 cheshire
856 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
858 Revision 1.724 2007/10/02 20:10:23 cheshire
859 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
861 Revision 1.723 2007/10/02 19:56:54 cheshire
862 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
864 Revision 1.722 2007/10/01 22:59:46 cheshire
865 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
866 Need to shut down NATTraversals on exit
868 Revision 1.721 2007/10/01 18:42:07 cheshire
869 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
871 Revision 1.720 2007/09/29 20:40:19 cheshire
872 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
874 Revision 1.719 2007/09/27 22:23:56 cheshire
875 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
876 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
878 Revision 1.718 2007/09/27 22:02:33 cheshire
879 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
881 Revision 1.717 2007/09/27 21:21:39 cheshire
882 Export CompleteDeregistration so it's callable from other files
884 Revision 1.716 2007/09/27 02:12:21 cheshire
885 Updated GrantCacheExtensions degugging message to show new record lifetime
887 Revision 1.715 2007/09/27 01:20:06 cheshire
888 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
890 Revision 1.714 2007/09/27 00:37:01 cheshire
891 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
893 Revision 1.713 2007/09/27 00:25:39 cheshire
894 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
895 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
897 Revision 1.712 2007/09/26 23:16:58 cheshire
898 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
900 Revision 1.711 2007/09/26 22:06:02 cheshire
901 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
903 Revision 1.710 2007/09/26 00:49:46 cheshire
904 Improve packet logging to show sent and received packets,
905 transport protocol (UDP/TCP/TLS) and source/destination address:port
907 Revision 1.709 2007/09/21 21:12:36 cheshire
908 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
910 Revision 1.708 2007/09/20 23:13:37 cheshire
911 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
912 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
914 Revision 1.707 2007/09/20 02:29:37 cheshire
915 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
917 Revision 1.706 2007/09/20 01:13:19 cheshire
918 Export CacheGroupForName so it's callable from other files
920 Revision 1.705 2007/09/20 01:12:06 cheshire
921 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
923 Revision 1.704 2007/09/19 22:47:25 cheshire
924 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
926 Revision 1.703 2007/09/14 01:46:59 cheshire
927 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
929 Revision 1.702 2007/09/13 22:06:46 cheshire
930 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
931 Need to accept DNS responses where the query ID field matches, even if the source address does not
933 Revision 1.701 2007/09/12 23:22:32 cheshire
934 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
936 Revision 1.700 2007/09/12 23:03:08 cheshire
937 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
939 Revision 1.699 2007/09/12 22:19:28 cheshire
940 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
942 Revision 1.698 2007/09/12 22:13:27 cheshire
943 Remove DynDNSHostNames cleanly on shutdown
945 Revision 1.697 2007/09/12 01:44:47 cheshire
946 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
948 Revision 1.696 2007/09/12 01:26:08 cheshire
949 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
951 Revision 1.695 2007/09/11 19:19:16 cheshire
952 Correct capitalization of "uPNP" to "UPnP"
954 Revision 1.694 2007/09/10 22:06:51 cheshire
955 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
957 Revision 1.693 2007/09/07 22:24:36 vazquez
958 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
960 Revision 1.692 2007/09/07 00:12:09 cheshire
961 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
963 Revision 1.691 2007/09/05 22:25:01 vazquez
964 <rdar://problem/5400521> update_record mDNSResponder leak
966 Revision 1.690 2007/09/05 21:48:01 cheshire
967 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
968 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
969 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
970 otherwise those records will expire and vanish from the cache.
972 Revision 1.689 2007/09/05 02:29:06 cheshire
973 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
974 Additional fixes to code implementing "NoAnswer" logic
976 Revision 1.688 2007/08/31 22:56:39 cheshire
977 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
979 Revision 1.687 2007/08/31 19:53:14 cheshire
980 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
981 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
983 Revision 1.686 2007/08/30 00:01:56 cheshire
984 Added comment about SetTargetToHostName()
986 Revision 1.685 2007/08/29 01:19:24 cheshire
987 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
988 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
990 Revision 1.684 2007/08/28 23:58:42 cheshire
991 Rename HostTarget -> AutoTarget
993 Revision 1.683 2007/08/28 23:53:21 cheshire
994 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
996 Revision 1.682 2007/08/27 20:28:19 cheshire
997 Improve "suspect uDNS response" log message
999 Revision 1.681 2007/08/24 23:37:23 cheshire
1000 Added debugging message to show when ExtraResourceRecord callback gets invoked
1002 Revision 1.680 2007/08/24 00:15:19 cheshire
1003 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
1005 Revision 1.679 2007/08/23 21:47:09 vazquez
1006 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
1007 make sure we clean up port mappings on base stations by sending a lease value of 0,
1008 and only send NAT-PMP packets on private networks; also save some memory by
1009 not using packet structs in NATTraversals.
1011 Revision 1.678 2007/08/01 16:09:13 cheshire
1012 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
1014 Revision 1.677 2007/08/01 01:58:24 cheshire
1015 Added RecordType sanity check in mDNS_Register_internal
1017 Revision 1.676 2007/08/01 00:04:13 cheshire
1018 <rdar://problem/5261696> Crash in tcpKQSocketCallback
1019 Half-open TCP connections were not being cancelled properly
1021 Revision 1.675 2007/07/31 02:28:35 vazquez
1022 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
1024 Revision 1.674 2007/07/31 01:57:23 cheshire
1025 Adding code to respect TTL received in uDNS responses turned out to
1026 expose other problems; backing out change for now.
1028 Revision 1.673 2007/07/30 23:31:26 cheshire
1029 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
1031 Revision 1.672 2007/07/28 01:25:56 cheshire
1032 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
1034 Revision 1.671 2007/07/27 22:32:54 cheshire
1035 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
1036 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
1038 Revision 1.670 2007/07/27 20:54:43 cheshire
1039 Fixed code to respect real record TTL received in uDNS responses
1041 Revision 1.669 2007/07/27 20:09:32 cheshire
1042 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
1044 Revision 1.668 2007/07/27 19:58:47 cheshire
1045 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
1047 Revision 1.667 2007/07/27 19:52:10 cheshire
1048 Don't increment m->rrcache_active for no-cache add events
1050 Revision 1.666 2007/07/27 19:30:39 cheshire
1051 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
1052 to properly reflect tri-state nature of the possible responses
1054 Revision 1.665 2007/07/27 18:44:01 cheshire
1055 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
1057 Revision 1.664 2007/07/27 18:38:56 cheshire
1058 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
1060 Revision 1.663 2007/07/25 03:05:02 vazquez
1062 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
1063 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
1064 and a myriad of other security problems
1066 Revision 1.662 2007/07/24 20:22:46 cheshire
1067 Make sure all fields of main mDNS object are initialized correctly
1069 Revision 1.661 2007/07/21 00:54:45 cheshire
1070 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
1072 Revision 1.660 2007/07/20 20:00:45 cheshire
1073 "Legacy Browse" is better called "Automatic Browse"
1075 Revision 1.659 2007/07/20 00:54:18 cheshire
1076 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
1078 Revision 1.658 2007/07/18 02:28:57 cheshire
1079 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
1081 Revision 1.657 2007/07/18 00:57:10 cheshire
1082 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1083 Only need to call AddNewClientTunnel() for IPv6 addresses
1085 Revision 1.656 2007/07/16 23:54:48 cheshire
1086 <rdar://problem/5338850> Crash when removing or changing DNS keys
1088 Revision 1.655 2007/07/16 20:11:37 vazquez
1089 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
1090 Init LNT stuff and handle SSDP packets
1092 Revision 1.654 2007/07/12 23:30:23 cheshire
1093 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
1095 Revision 1.653 2007/07/12 02:51:27 cheshire
1096 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1098 Revision 1.652 2007/07/11 23:43:42 cheshire
1099 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
1101 Revision 1.651 2007/07/11 22:44:40 cheshire
1102 <rdar://problem/5328801> SIGHUP should purge the cache
1104 Revision 1.650 2007/07/11 21:34:09 cheshire
1105 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
1106 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
1108 Revision 1.649 2007/07/11 02:52:52 cheshire
1109 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
1110 In uDNS_RegisterService, set HostTarget for AutoTunnel services
1112 Revision 1.648 2007/07/09 23:48:12 cheshire
1113 Add parentheses around bitwise operation for clarity
1115 Revision 1.647 2007/07/06 21:17:55 cheshire
1116 Initialize m->retryGetAddr to timenow + 0x78000000;
1118 Revision 1.646 2007/07/06 18:55:49 cheshire
1119 Initialize m->NextScheduledNATOp
1121 Revision 1.645 2007/06/29 22:55:54 cheshire
1122 Move declaration of DNSServer *s; Fixed incomplete comment.
1124 Revision 1.644 2007/06/29 00:07:29 vazquez
1125 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
1127 Revision 1.643 2007/06/20 01:10:12 cheshire
1128 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
1130 Revision 1.642 2007/06/15 21:54:50 cheshire
1131 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
1133 Revision 1.641 2007/05/25 00:30:24 cheshire
1134 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
1135 status matches. This is particularly important when doing a private query for an SOA record,
1136 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
1137 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
1139 Revision 1.640 2007/05/25 00:25:44 cheshire
1140 <rdar://problem/5227737> Need to enhance putRData to output all current known types
1142 Revision 1.639 2007/05/23 00:51:33 cheshire
1143 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
1144 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
1145 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
1147 Revision 1.638 2007/05/23 00:43:16 cheshire
1148 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
1150 Revision 1.637 2007/05/14 23:53:00 cheshire
1151 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
1153 Revision 1.636 2007/05/10 23:27:15 cheshire
1154 Update mDNS_Deregister_internal debugging messages
1156 Revision 1.635 2007/05/07 20:43:45 cheshire
1157 <rdar://problem/4241419> Reduce the number of queries and announcements
1159 Revision 1.634 2007/05/04 22:09:08 cheshire
1160 Only do "restarting exponential backoff sequence" for mDNS questions
1161 In mDNS_RegisterInterface, only retrigger mDNS questions
1162 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
1164 Revision 1.633 2007/05/04 21:45:12 cheshire
1165 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
1167 Revision 1.632 2007/05/04 20:20:50 cheshire
1168 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1169 Need to set srs->nta = mDNSNULL; when regState_NoTarget
1171 Revision 1.631 2007/05/04 00:39:42 cheshire
1172 <rdar://problem/4410011> Eliminate looping SOA lookups
1173 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
1174 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
1176 Revision 1.630 2007/05/03 22:40:38 cheshire
1177 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
1179 Revision 1.629 2007/05/03 00:15:51 cheshire
1180 <rdar://problem/4410011> Eliminate looping SOA lookups
1182 Revision 1.628 2007/05/02 22:21:33 cheshire
1183 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1185 Revision 1.627 2007/04/30 19:29:13 cheshire
1186 Fix display of port number in "Updating DNS Server" message
1188 Revision 1.626 2007/04/30 04:21:13 cheshire
1189 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
1191 Revision 1.625 2007/04/28 01:34:21 cheshire
1192 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
1193 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
1195 Revision 1.624 2007/04/27 21:04:30 cheshire
1196 On network configuration change, need to call uDNS_RegisterSearchDomains
1198 Revision 1.623 2007/04/27 19:28:01 cheshire
1199 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
1200 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
1201 -- it would start a query and then quickly cancel it, and then when
1202 StartGetZoneData completed, it had a dangling pointer and crashed.)
1204 Revision 1.622 2007/04/26 16:09:22 cheshire
1205 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
1207 Revision 1.621 2007/04/26 15:43:22 cheshire
1208 Make sure DNSServer *s is non-null before using value in LogOperation
1210 Revision 1.620 2007/04/26 13:11:05 cheshire
1211 Fixed crash when logging out of VPN
1213 Revision 1.619 2007/04/26 00:35:15 cheshire
1214 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
1215 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
1216 inside the firewall may give answers where a public one gives none, and vice versa.)
1218 Revision 1.618 2007/04/25 19:26:01 cheshire
1219 m->NextScheduledQuery was getting set too early in SendQueries()
1220 Improved "SendQueries didn't send all its queries" debugging message
1222 Revision 1.617 2007/04/25 17:48:22 cheshire
1223 Update debugging message
1225 Revision 1.616 2007/04/25 16:38:32 cheshire
1226 If negative cache entry already exists, reactivate it instead of creating a new one
1228 Revision 1.615 2007/04/25 02:14:38 cheshire
1229 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
1230 Additional fixes to make LLQs work properly
1232 Revision 1.614 2007/04/23 21:52:45 cheshire
1233 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
1235 Revision 1.613 2007/04/23 04:58:20 cheshire
1236 <rdar://problem/5072548> Crash when setting extremely large TXT records
1238 Revision 1.612 2007/04/22 20:39:38 cheshire
1239 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
1241 Revision 1.611 2007/04/22 18:16:29 cheshire
1242 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
1244 Revision 1.610 2007/04/22 06:02:02 cheshire
1245 <rdar://problem/4615977> Query should immediately return failure when no server
1247 Revision 1.609 2007/04/20 21:17:24 cheshire
1248 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
1250 Revision 1.608 2007/04/20 19:45:31 cheshire
1251 In LogClientOperations mode, dump out unknown DNS packets in their entirety
1253 Revision 1.607 2007/04/19 23:56:25 cheshire
1254 Don't do cache-flush processing for LLQ answers
1256 Revision 1.606 2007/04/19 22:50:53 cheshire
1257 <rdar://problem/4246187> Identical client queries should reference a single shared core query
1259 Revision 1.605 2007/04/19 20:06:41 cheshire
1260 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
1262 Revision 1.604 2007/04/19 18:03:04 cheshire
1263 Add "const" declaration
1265 Revision 1.603 2007/04/06 21:00:25 cheshire
1266 Fix log message typo
1268 Revision 1.602 2007/04/05 22:55:35 cheshire
1269 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1271 Revision 1.601 2007/04/04 21:48:52 cheshire
1272 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1274 Revision 1.600 2007/04/04 01:31:33 cheshire
1275 Improve debugging message
1277 Revision 1.599 2007/04/04 00:03:26 cheshire
1278 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
1280 Revision 1.598 2007/04/03 19:43:16 cheshire
1281 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1283 Revision 1.597 2007/03/31 00:32:32 cheshire
1284 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
1286 Revision 1.596 2007/03/28 20:59:26 cheshire
1287 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1289 Revision 1.595 2007/03/26 23:48:16 cheshire
1290 <rdar://problem/4848295> Advertise model information via Bonjour
1291 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
1293 Revision 1.594 2007/03/26 23:05:05 cheshire
1294 <rdar://problem/5089257> Don't cache TSIG records
1296 Revision 1.593 2007/03/23 17:40:08 cheshire
1297 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
1299 Revision 1.592 2007/03/22 18:31:48 cheshire
1300 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1302 Revision 1.591 2007/03/22 00:49:19 cheshire
1303 <rdar://problem/4848295> Advertise model information via Bonjour
1305 Revision 1.590 2007/03/21 23:05:59 cheshire
1306 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1308 Revision 1.589 2007/03/20 15:37:19 cheshire
1309 Delete unnecessary log message
1311 Revision 1.588 2007/03/20 00:24:44 cheshire
1312 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
1314 Revision 1.587 2007/03/16 22:10:56 cheshire
1315 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
1317 Revision 1.586 2007/03/10 03:26:44 cheshire
1318 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1320 Revision 1.585 2007/03/10 02:02:58 cheshire
1321 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1322 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1324 Revision 1.584 2007/02/28 01:51:27 cheshire
1325 Added comment about reverse-order IP address
1327 Revision 1.583 2007/01/27 03:19:33 cheshire
1328 Need to initialize question->sock
1330 Revision 1.582 2007/01/25 00:40:16 cheshire
1331 Unified CNAME-following functionality into cache management code (which means CNAME-following
1332 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1334 Revision 1.581 2007/01/23 02:56:11 cheshire
1335 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1337 Revision 1.580 2007/01/19 21:17:33 cheshire
1338 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1340 Revision 1.579 2007/01/19 18:39:10 cheshire
1341 Fix a bunch of parameters that should have been declared "const"
1343 Revision 1.578 2007/01/10 22:51:57 cheshire
1344 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1346 Revision 1.577 2007/01/10 02:05:21 cheshire
1347 Delay uDNS_SetupDNSConfig() until *after* the platform layer
1348 has set up the interface list and security credentials
1350 Revision 1.576 2007/01/09 02:40:57 cheshire
1351 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1352 moved it to mDNS_Init() in mDNS.c (core code)
1354 Revision 1.575 2007/01/09 00:17:25 cheshire
1355 Improve "ERROR m->CurrentRecord already set" debugging messages
1357 Revision 1.574 2007/01/05 08:30:41 cheshire
1358 Trim excessive "$Log" checkin history from before 2006
1359 (checkin history still available via "cvs log ..." of course)
1361 Revision 1.573 2007/01/05 06:34:03 cheshire
1362 Improve "ERROR m->CurrentQuestion already set" debugging messages
1364 Revision 1.572 2007/01/04 23:11:11 cheshire
1365 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1366 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1368 Revision 1.571 2007/01/04 21:45:20 cheshire
1369 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1370 to do additional lock sanity checking around callback invocations
1372 Revision 1.570 2007/01/04 20:57:47 cheshire
1373 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
1375 Revision 1.569 2007/01/04 20:27:27 cheshire
1376 Change a LogMsg() to debugf()
1378 Revision 1.568 2007/01/04 02:39:53 cheshire
1379 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1381 Revision 1.567 2006/12/21 00:01:37 cheshire
1382 Tidy up code alignment
1384 Revision 1.566 2006/12/20 04:07:34 cheshire
1385 Remove uDNS_info substructure from AuthRecord_struct
1387 Revision 1.565 2006/12/19 22:49:23 cheshire
1388 Remove uDNS_info substructure from ServiceRecordSet_struct
1390 Revision 1.564 2006/12/19 02:38:20 cheshire
1391 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1393 Revision 1.563 2006/12/19 02:18:48 cheshire
1394 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1396 Revision 1.562 2006/12/16 01:58:31 cheshire
1397 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1399 Revision 1.561 2006/12/01 07:38:53 herscher
1400 Only perform cache workaround fix if query is wide-area
1402 Revision 1.560 2006/11/30 23:07:56 herscher
1403 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1405 Revision 1.559 2006/11/27 08:20:57 cheshire
1406 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
1408 Revision 1.558 2006/11/10 07:44:03 herscher
1409 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1411 Revision 1.557 2006/11/10 01:12:51 cheshire
1412 <rdar://problem/4829718> Incorrect TTL corrections
1414 Revision 1.556 2006/11/10 00:54:14 cheshire
1415 <rdar://problem/4816598> Changing case of Computer Name doesn't work
1417 Revision 1.555 2006/10/30 20:03:37 cheshire
1418 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
1420 Revision 1.554 2006/10/20 05:35:04 herscher
1421 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1423 Revision 1.553 2006/10/05 03:42:43 herscher
1424 Remove embedded uDNS_info struct in DNSQuestion_struct
1426 Revision 1.552 2006/09/15 21:20:15 cheshire
1427 Remove uDNS_info substructure from mDNS_struct
1429 Revision 1.551 2006/08/14 23:24:22 cheshire
1430 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1432 Revision 1.550 2006/07/27 17:58:34 cheshire
1433 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
1435 Revision 1.549 2006/07/20 22:07:31 mkrochma
1436 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
1437 More fixes for uninitialized variables
1439 Revision 1.548 2006/07/20 19:30:19 mkrochma
1440 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
1442 Revision 1.547 2006/07/15 02:31:30 cheshire
1443 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
1445 Revision 1.546 2006/07/07 01:09:09 cheshire
1446 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
1447 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
1449 Revision 1.545 2006/07/05 23:10:30 cheshire
1450 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1451 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
1453 Revision 1.544 2006/06/29 07:42:14 cheshire
1454 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
1456 Revision 1.543 2006/06/29 01:38:43 cheshire
1457 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
1459 Revision 1.542 2006/06/27 23:40:29 cheshire
1460 Fix typo in comment: mis-spelled "compile"
1462 Revision 1.541 2006/06/27 19:46:24 cheshire
1463 Updated comments and debugging messages
1465 Revision 1.540 2006/06/15 21:35:16 cheshire
1466 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
1467 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
1469 Revision 1.539 2006/06/08 23:45:46 cheshire
1470 Change SimultaneousProbe messages from debugf() to LogOperation()
1472 Revision 1.538 2006/03/19 17:13:06 cheshire
1473 <rdar://problem/4483117> Need faster purging of stale records
1474 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
1475 and reconfirm whole chain of antecedents ot once
1477 Revision 1.537 2006/03/19 02:00:07 cheshire
1478 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1480 Revision 1.536 2006/03/08 23:29:53 cheshire
1481 <rdar://problem/4468716> Improve "Service Renamed" log message
1483 Revision 1.535 2006/03/02 20:41:17 cheshire
1484 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1485 Minor code tidying and comments to reduce the risk of similar programming errors in future
1487 Revision 1.534 2006/03/02 03:25:46 cheshire
1488 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1489 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
1491 Revision 1.533 2006/02/26 00:54:41 cheshire
1492 Fixes to avoid code generation warning/error on FreeBSD 7
1496 #include "DNSCommon.h" // Defines general DNS untility routines
1497 #include "uDNS.h" // Defines entry points into unicast-specific routines
1499 // Disable certain benign warnings with Microsoft compilers
1500 #if(defined(_MSC_VER))
1501 // Disable "conditional expression is constant" warning for debug macros.
1502 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1503 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1504 #pragma warning(disable:4127)
1506 // Disable "assignment within conditional expression".
1507 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1508 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1509 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1510 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1511 #pragma warning(disable:4706)
1514 // Forward declarations
1515 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
);
1516 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
);
1518 // ***************************************************************************
1519 #if COMPILER_LIKES_PRAGMA_MARK
1520 #pragma mark - Program Constants
1525 mDNSlocal
const mDNSInterfaceID mDNSInterfaceMark
= (mDNSInterfaceID
)~0;
1527 // Any records bigger than this are considered 'large' records
1528 #define SmallRecordLimit 1024
1530 #define kMaxUpdateCredits 10
1531 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1533 mDNSexport
const char *const mDNS_DomainTypeNames
[] =
1535 "b._dns-sd._udp.", // Browse
1536 "db._dns-sd._udp.", // Default Browse
1537 "lb._dns-sd._udp.", // Automatic Browse
1538 "r._dns-sd._udp.", // Registration
1539 "dr._dns-sd._udp." // Default Registration
1542 #ifdef UNICAST_DISABLED
1543 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1546 // ***************************************************************************
1547 #if COMPILER_LIKES_PRAGMA_MARK
1549 #pragma mark - General Utility Functions
1552 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
1553 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
1555 mDNSexport
void SetNextQueryTime(mDNS
*const m
, const DNSQuestion
*const q
)
1557 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1558 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1561 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1) *(long*)0 = 0;
1564 if (ActiveQuestion(q
))
1566 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
1568 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
1569 if (!mDNSOpaque16IsZero(q
->TargetQID
) && !q
->LongLived
&& m
->SuppressStdPort53Queries
&& (sendtime
- m
->SuppressStdPort53Queries
< 0))
1570 sendtime
= m
->SuppressStdPort53Queries
;
1572 if (m
->NextScheduledQuery
- sendtime
> 0)
1573 m
->NextScheduledQuery
= sendtime
;
1577 mDNSexport CacheGroup
*CacheGroupForName(const mDNS
*const m
, const mDNSu32 slot
, const mDNSu32 namehash
, const domainname
*const name
)
1580 for (cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1581 if (cg
->namehash
== namehash
&& SameDomainName(cg
->name
, name
))
1586 mDNSlocal CacheGroup
*CacheGroupForRecord(const mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
1588 return(CacheGroupForName(m
, slot
, rr
->namehash
, rr
->name
));
1591 mDNSlocal mDNSBool
AddressIsLocalSubnet(mDNS
*const m
, const mDNSInterfaceID InterfaceID
, const mDNSAddr
*addr
)
1593 NetworkInterfaceInfo
*intf
;
1595 if (addr
->type
== mDNSAddrType_IPv4
)
1597 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
1598 if (mDNSv4AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1599 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1600 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1601 if (((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) & intf
->mask
.ip
.v4
.NotAnInteger
) == 0)
1605 if (addr
->type
== mDNSAddrType_IPv6
)
1607 if (mDNSv6AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1608 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1609 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1610 if ((((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) & intf
->mask
.ip
.v6
.l
[0]) == 0) &&
1611 (((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) & intf
->mask
.ip
.v6
.l
[1]) == 0) &&
1612 (((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) & intf
->mask
.ip
.v6
.l
[2]) == 0) &&
1613 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) & intf
->mask
.ip
.v6
.l
[3]) == 0))
1620 mDNSlocal NetworkInterfaceInfo
*FirstInterfaceForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1622 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1623 while (intf
&& intf
->InterfaceID
!= InterfaceID
) intf
= intf
->next
;
1627 mDNSlocal
char *InterfaceNameForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1629 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
1630 return(intf
? intf
->ifname
: "<NULL InterfaceID>");
1633 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1634 // Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
1635 mDNSlocal
void AnswerLocalQuestionWithLocalAuthRecord(mDNS
*const m
, DNSQuestion
*q
, AuthRecord
*rr
, QC_result AddRecord
)
1637 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1638 if (AddRecord
) rr
->AnsweredLocalQ
= mDNStrue
;
1639 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1640 if (q
->QuestionCallback
&& !q
->NoAnswer
)
1642 q
->CurrentAnswers
+= AddRecord
? 1 : -1;
1643 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
1645 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1648 // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
1649 // all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
1650 // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1651 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1652 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1653 mDNSlocal
void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS
*const m
, AuthRecord
*rr
, QC_result AddRecord
)
1655 if (m
->CurrentQuestion
)
1656 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
1658 m
->CurrentQuestion
= m
->LocalOnlyQuestions
;
1659 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewLocalOnlyQuestions
)
1661 DNSQuestion
*q
= m
->CurrentQuestion
;
1662 m
->CurrentQuestion
= q
->next
;
1663 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1664 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1667 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1668 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
1670 m
->CurrentQuestion
= m
->Questions
;
1671 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
1673 DNSQuestion
*q
= m
->CurrentQuestion
;
1674 m
->CurrentQuestion
= q
->next
;
1675 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1676 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1680 m
->CurrentQuestion
= mDNSNULL
;
1683 // ***************************************************************************
1684 #if COMPILER_LIKES_PRAGMA_MARK
1686 #pragma mark - Resource Record Utility Functions
1689 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1691 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1692 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1693 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1694 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1696 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1697 (ResourceRecordIsValidAnswer(RR) && \
1698 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1700 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1701 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1703 #define InitialAnnounceCount ((mDNSu8)8)
1705 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1706 // This means that because the announce interval is doubled after sending the first packet, the first
1707 // observed on-the-wire inter-packet interval between announcements is actually one second.
1708 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1709 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1710 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1711 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1713 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1714 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1715 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1717 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1718 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1719 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1720 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1722 #define MaxUnansweredQueries 4
1724 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1725 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1726 // TTL and rdata may differ.
1727 // This is used for cache flush management:
1728 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1729 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1731 // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
1733 #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
1735 mDNSlocal mDNSBool
SameResourceRecordNameClassInterface(const AuthRecord
*const r1
, const AuthRecord
*const r2
)
1737 if (!r1
) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse
); }
1738 if (!r2
) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse
); }
1739 if (r1
->resrec
.InterfaceID
&&
1740 r2
->resrec
.InterfaceID
&&
1741 r1
->resrec
.InterfaceID
!= r2
->resrec
.InterfaceID
) return(mDNSfalse
);
1743 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
&&
1744 r1
->resrec
.namehash
== r2
->resrec
.namehash
&&
1745 SameDomainName(r1
->resrec
.name
, r2
->resrec
.name
));
1748 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1749 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1750 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1751 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1752 // so a response of any type should match, even if it is not actually the type the client plans to use.
1754 // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
1755 // and require the rrtypes to match for the rdata to be considered potentially conflicting
1756 mDNSlocal mDNSBool
PacketRRMatchesSignature(const CacheRecord
*const pktrr
, const AuthRecord
*const authrr
)
1758 if (!pktrr
) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse
); }
1759 if (!authrr
) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse
); }
1760 if (pktrr
->resrec
.InterfaceID
&&
1761 authrr
->resrec
.InterfaceID
&&
1762 pktrr
->resrec
.InterfaceID
!= authrr
->resrec
.InterfaceID
) return(mDNSfalse
);
1763 if (!(authrr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) || authrr
->WakeUp
.HMAC
.l
[0])
1764 if (pktrr
->resrec
.rrtype
!= authrr
->resrec
.rrtype
) return(mDNSfalse
);
1766 pktrr
->resrec
.rrclass
== authrr
->resrec
.rrclass
&&
1767 pktrr
->resrec
.namehash
== authrr
->resrec
.namehash
&&
1768 SameDomainName(pktrr
->resrec
.name
, authrr
->resrec
.name
));
1771 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1772 // This is the information that the requester believes to be correct.
1773 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1774 // This is the information that we believe to be correct.
1775 // We've already determined that we plan to give this answer on this interface
1776 // (either the record is non-specific, or it is specific to this interface)
1777 // so now we just need to check the name, type, class, rdata and TTL.
1778 mDNSlocal mDNSBool
ShouldSuppressKnownAnswer(const CacheRecord
*const ka
, const AuthRecord
*const rr
)
1780 // If RR signature is different, or data is different, then don't suppress our answer
1781 if (!IdenticalResourceRecord(&ka
->resrec
, &rr
->resrec
)) return(mDNSfalse
);
1783 // If the requester's indicated TTL is less than half the real TTL,
1784 // we need to give our answer before the requester's copy expires.
1785 // If the requester's indicated TTL is at least half the real TTL,
1786 // then we can suppress our answer this time.
1787 // If the requester's indicated TTL is greater than the TTL we believe,
1788 // then that's okay, and we don't need to do anything about it.
1789 // (If two responders on the network are offering the same information,
1790 // that's okay, and if they are offering the information with different TTLs,
1791 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1792 return(mDNSBool
)(ka
->resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/ 2);
1795 mDNSlocal
void SetNextAnnounceProbeTime(mDNS
*const m
, const AuthRecord
*const rr
)
1797 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1799 //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1800 if (m
->NextScheduledProbe
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1801 m
->NextScheduledProbe
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1803 else if (rr
->AnnounceCount
&& ResourceRecordIsValidAnswer(rr
))
1805 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1806 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1810 mDNSlocal
void InitializeLastAPTime(mDNS
*const m
, AuthRecord
*const rr
)
1812 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1813 rr
->ThisAPInterval
= rr
->AddressProxy
.type
? mDNSPlatformOneSecond
: DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
);
1815 // To allow us to aggregate probes when a group of services are registered together,
1816 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1817 // 1/4 second wait; probe
1818 // 1/4 second wait; probe
1819 // 1/4 second wait; probe
1820 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1824 // If we have no probe suppression time set, or it is in the past, set it now
1825 if (m
->SuppressProbes
== 0 || m
->SuppressProbes
- m
->timenow
< 0)
1827 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ DefaultProbeIntervalForTypeUnique
);
1828 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1829 if (m
->SuppressProbes
- m
->NextScheduledProbe
>= 0)
1830 m
->SuppressProbes
= m
->NextScheduledProbe
;
1831 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1832 if (m
->SuppressProbes
- m
->NextScheduledQuery
>= 0)
1833 m
->SuppressProbes
= m
->NextScheduledQuery
;
1837 rr
->LastAPTime
= m
->SuppressProbes
- rr
->ThisAPInterval
;
1838 // Set LastMCTime to now, to inhibit multicast responses
1839 // (no need to send additional multicast responses when we're announcing anyway)
1840 rr
->LastMCTime
= m
->timenow
;
1841 rr
->LastMCInterface
= mDNSInterfaceMark
;
1843 // If this is a record type that's not going to probe, then delay its first announcement so that
1844 // it will go out synchronized with the first announcement for the other records that *are* probing.
1845 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1846 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1847 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1848 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1849 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1850 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
)
1851 rr
->LastAPTime
+= DefaultProbeIntervalForTypeUnique
* DefaultProbeCountForTypeUnique
+ rr
->ThisAPInterval
/ 2;
1853 // The exception is unique records that have already been verified and are just being updated
1854 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1855 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
1856 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1858 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1859 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1860 // After three probes one second apart with no answer, we conclude the client is now sleeping
1861 // and we can begin broadcasting our announcements to take over ownership of that IP address.
1862 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1863 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1864 if (rr
->AddressProxy
.type
) rr
->LastAPTime
= m
->timenow
;
1866 // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
1867 if (rr
->WakeUp
.HMAC
.l
[0] && rr
->resrec
.rrtype
== kDNSType_AAAA
)
1868 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
+ mDNSPlatformOneSecond
* 10;
1870 SetNextAnnounceProbeTime(m
, rr
);
1873 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1874 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1875 mDNSlocal
void SetTargetToHostName(mDNS
*const m
, AuthRecord
*const rr
)
1877 domainname
*const target
= GetRRDomainNameTarget(&rr
->resrec
);
1878 const domainname
*newname
= &m
->MulticastHostname
;
1880 if (!target
) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr
->resrec
.rrtype
);
1882 if (!(rr
->ForceMCast
|| rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&rr
->namestorage
)))
1884 const domainname
*const n
= GetServiceTarget(m
, rr
);
1888 if (target
&& SameDomainName(target
, newname
))
1889 debugf("SetTargetToHostName: Target of %##s is already %##s", rr
->resrec
.name
->c
, target
->c
);
1891 if (target
&& !SameDomainName(target
, newname
))
1893 AssignDomainName(target
, newname
);
1894 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
1896 // If we're in the middle of probing this record, we need to start again,
1897 // because changing its rdata may change the outcome of the tie-breaker.
1898 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1899 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
1901 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1902 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1903 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1904 if (rr
->RequireGoodbye
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
)
1905 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1906 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1908 rr
->AnnounceCount
= InitialAnnounceCount
;
1909 rr
->RequireGoodbye
= mDNSfalse
;
1910 InitializeLastAPTime(m
, rr
);
1914 mDNSlocal
void AcknowledgeRecord(mDNS
*const m
, AuthRecord
*const rr
)
1916 if (rr
->RecordCallback
)
1918 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1919 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1920 rr
->Acknowledged
= mDNStrue
;
1921 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1922 rr
->RecordCallback(m
, rr
, mStatus_NoError
);
1923 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1927 mDNSlocal
void ActivateUnicastRegistration(mDNS
*const m
, AuthRecord
*const rr
)
1930 rr
->AnnounceCount
= 0;
1931 rr
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
1932 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1933 rr
->state
= regState_FetchingZoneData
;
1934 rr
->uselease
= mDNStrue
;
1937 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1938 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1939 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1940 #define RecordIsLocalDuplicate(A,B) \
1941 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1943 // Exported so uDNS.c can call this
1944 mDNSexport mStatus
mDNS_Register_internal(mDNS
*const m
, AuthRecord
*const rr
)
1946 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
1948 AuthRecord
**p
= &m
->ResourceRecords
;
1949 AuthRecord
**d
= &m
->DuplicateRecords
;
1951 if ((mDNSs32
)rr
->resrec
.rroriginalttl
<= 0)
1952 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1954 if (!rr
->resrec
.RecordType
)
1955 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1957 if (m
->ShutdownTime
)
1958 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m
, rr
)); return(mStatus_ServiceNotRunning
); }
1960 if (m
->DivertMulticastAdvertisements
&& !AuthRecord_uDNS(rr
))
1962 mDNSInterfaceID previousID
= rr
->resrec
.InterfaceID
;
1963 if (rr
->resrec
.InterfaceID
== mDNSInterface_Any
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1964 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
1966 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
1967 if (intf
&& !intf
->Advertise
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1969 if (rr
->resrec
.InterfaceID
!= previousID
)
1970 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m
, rr
));
1973 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
1974 while (*d
&& *d
!= rr
) d
=&(*d
)->next
;
1977 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1978 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1979 return(mStatus_AlreadyRegistered
);
1982 if (rr
->DependentOn
)
1984 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1985 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
1988 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1989 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1990 return(mStatus_Invalid
);
1992 if (!(rr
->DependentOn
->resrec
.RecordType
& (kDNSRecordTypeUnique
| kDNSRecordTypeVerified
)))
1994 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1995 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->DependentOn
->resrec
.RecordType
);
1996 return(mStatus_Invalid
);
2000 // If this resource record is referencing a specific interface, make sure it exists
2001 if (rr
->resrec
.InterfaceID
&& rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
2003 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2006 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr
->resrec
.InterfaceID
);
2007 return(mStatus_BadReferenceErr
);
2011 rr
->next
= mDNSNULL
;
2013 // Field Group 1: The actual information pertaining to this resource record
2014 // Set up by client prior to call
2016 // Field Group 2: Persistent metadata for Authoritative Records
2017 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2018 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2019 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2020 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2021 // rr->Callback = already set in mDNS_SetupResourceRecord
2022 // rr->Context = already set in mDNS_SetupResourceRecord
2023 // rr->RecordType = already set in mDNS_SetupResourceRecord
2024 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2025 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2026 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
2027 if (rr
->AutoTarget
&& target
) target
->c
[0] = 0;
2029 // Field Group 3: Transient state for Authoritative Records
2030 rr
->Acknowledged
= mDNSfalse
;
2031 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
2032 rr
->AnnounceCount
= InitialAnnounceCount
;
2033 rr
->RequireGoodbye
= mDNSfalse
;
2034 rr
->AnsweredLocalQ
= mDNSfalse
;
2035 rr
->IncludeInProbe
= mDNSfalse
;
2036 rr
->ImmedUnicast
= mDNSfalse
;
2037 rr
->SendNSECNow
= mDNSNULL
;
2038 rr
->ImmedAnswer
= mDNSNULL
;
2039 rr
->ImmedAdditional
= mDNSNULL
;
2040 rr
->SendRNow
= mDNSNULL
;
2041 rr
->v4Requester
= zerov4Addr
;
2042 rr
->v6Requester
= zerov6Addr
;
2043 rr
->NextResponse
= mDNSNULL
;
2044 rr
->NR_AnswerTo
= mDNSNULL
;
2045 rr
->NR_AdditionalTo
= mDNSNULL
;
2046 if (!rr
->AutoTarget
) InitializeLastAPTime(m
, rr
);
2047 // rr->LastAPTime = Set for us in InitializeLastAPTime()
2048 // rr->LastMCTime = Set for us in InitializeLastAPTime()
2049 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
2050 rr
->NewRData
= mDNSNULL
;
2051 rr
->newrdlength
= 0;
2052 rr
->UpdateCallback
= mDNSNULL
;
2053 rr
->UpdateCredits
= kMaxUpdateCredits
;
2054 rr
->NextUpdateCredit
= 0;
2055 rr
->UpdateBlocked
= 0;
2057 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
2058 if (rr
->WakeUp
.HMAC
.l
[0] && !rr
->AddressProxy
.type
) rr
->AnnounceCount
= 2;
2060 // Field Group 4: Transient uDNS state for Authoritative Records
2061 rr
->state
= regState_Zero
;
2065 rr
->updateid
= zeroID
;
2066 rr
->zone
= rr
->resrec
.name
;
2067 rr
->UpdateServer
= zeroAddr
;
2068 rr
->UpdatePort
= zeroIPPort
;
2073 rr
->InFlightRData
= 0;
2074 rr
->InFlightRDLen
= 0;
2075 rr
->QueuedRData
= 0;
2076 rr
->QueuedRDLen
= 0;
2078 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
2079 // rr->resrec.name->c = MUST be set by client
2080 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
2081 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
2082 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
2083 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2086 SetTargetToHostName(m
, rr
); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2089 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
2090 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
2093 if (!ValidateDomainName(rr
->resrec
.name
))
2094 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2096 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2097 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2098 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2099 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rr
->resrec
.rdlength
== 0) { rr
->resrec
.rdlength
= 1; rr
->resrec
.rdata
->u
.txt
.c
[0] = 0; }
2101 // Don't do this until *after* we've set rr->resrec.rdlength
2102 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
2103 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2105 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
2106 rr
->resrec
.rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(&rr
->resrec
);
2108 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
2110 // If this is supposed to be unique, make sure we don't have any name conflicts
2111 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2113 const AuthRecord
*s1
= rr
->RRSet
? rr
->RRSet
: rr
;
2114 for (r
= m
->ResourceRecords
; r
; r
=r
->next
)
2116 const AuthRecord
*s2
= r
->RRSet
? r
->RRSet
: r
;
2117 if (s1
!= s2
&& SameResourceRecordSignature(r
, rr
) && !IdenticalSameNameRecord(&r
->resrec
, &rr
->resrec
))
2120 if (r
) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2122 debugf("Name conflict %p %##s (%s)", rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2123 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2124 rr
->resrec
.rroriginalttl
= 0;
2125 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2126 m
->NextScheduledResponse
= m
->timenow
;
2131 // Now that we've finished building our new record, make sure it's not identical to one we already have
2132 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (RecordIsLocalDuplicate(r
, rr
)) break;
2136 debugf("Adding to duplicate list %p %s", rr
, ARDisplayString(m
,rr
));
2138 // If the previous copy of this record is already verified unique,
2139 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2140 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
2141 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2142 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& r
->resrec
.RecordType
== kDNSRecordTypeVerified
)
2147 debugf("Adding to active record list %p %s", rr
, ARDisplayString(m
,rr
));
2148 if (!m
->NewLocalRecords
) m
->NewLocalRecords
= rr
;
2152 if (!AuthRecord_uDNS(rr
))
2154 // For records that are not going to probe, acknowledge them right away
2155 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
&& rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
2156 AcknowledgeRecord(m
, rr
);
2158 #ifndef UNICAST_DISABLED
2161 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
2162 ActivateUnicastRegistration(m
, rr
);
2166 return(mStatus_NoError
);
2169 mDNSlocal
void RecordProbeFailure(mDNS
*const m
, const AuthRecord
*const rr
)
2171 m
->ProbeFailTime
= m
->timenow
;
2172 m
->NumFailedProbes
++;
2173 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2174 // If a bunch of hosts have all been configured with the same name, then they'll all
2175 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2176 // up to name-10. After that they'll start adding random increments in the range 1-100,
2177 // so they're more likely to branch out in the available namespace and settle on a set of
2178 // unique names quickly. If after five more tries the host is still conflicting, then we
2179 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
2180 if (m
->NumFailedProbes
>= 15)
2182 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
2183 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2184 m
->NumFailedProbes
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2188 mDNSlocal
void CompleteRDataUpdate(mDNS
*const m
, AuthRecord
*const rr
)
2190 RData
*OldRData
= rr
->resrec
.rdata
;
2191 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
); // Update our rdata
2192 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
2193 if (rr
->UpdateCallback
)
2194 rr
->UpdateCallback(m
, rr
, OldRData
); // ... and let the client know
2197 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2198 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2199 // Exported so uDNS.c can call this
2200 mDNSexport mStatus
mDNS_Deregister_internal(mDNS
*const m
, AuthRecord
*const rr
, mDNS_Dereg_type drt
)
2203 mDNSu8 RecordType
= rr
->resrec
.RecordType
;
2204 AuthRecord
**p
= &m
->ResourceRecords
; // Find this record in our list of active records
2206 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2210 // We found our record on the main list. See if there are any duplicates that need special handling.
2211 if (drt
== mDNS_Dereg_conflict
) // If this was a conflict, see that all duplicates get the same treatment
2213 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2214 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2215 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
) if (RecordIsLocalDuplicate(r2
, rr
)) r2
->ProbeCount
= 0xFF;
2219 // Before we delete the record (and potentially send a goodbye packet)
2220 // first see if we have a record on the duplicate list ready to take over from it.
2221 AuthRecord
**d
= &m
->DuplicateRecords
;
2222 while (*d
&& !RecordIsLocalDuplicate(*d
, rr
)) d
=&(*d
)->next
;
2225 AuthRecord
*dup
= *d
;
2226 debugf("Duplicate record %p taking over from %p %##s (%s)",
2227 dup
, rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2228 *d
= dup
->next
; // Cut replacement record from DuplicateRecords list
2229 dup
->next
= rr
->next
; // And then...
2230 rr
->next
= dup
; // ... splice it in right after the record we're about to delete
2231 dup
->resrec
.RecordType
= rr
->resrec
.RecordType
;
2232 dup
->ProbeCount
= rr
->ProbeCount
;
2233 dup
->AnnounceCount
= rr
->AnnounceCount
;
2234 dup
->RequireGoodbye
= rr
->RequireGoodbye
;
2235 dup
->AnsweredLocalQ
= rr
->AnsweredLocalQ
;
2236 dup
->ImmedAnswer
= rr
->ImmedAnswer
;
2237 dup
->ImmedUnicast
= rr
->ImmedUnicast
;
2238 dup
->ImmedAdditional
= rr
->ImmedAdditional
;
2239 dup
->v4Requester
= rr
->v4Requester
;
2240 dup
->v6Requester
= rr
->v6Requester
;
2241 dup
->ThisAPInterval
= rr
->ThisAPInterval
;
2242 dup
->LastAPTime
= rr
->LastAPTime
;
2243 dup
->LastMCTime
= rr
->LastMCTime
;
2244 dup
->LastMCInterface
= rr
->LastMCInterface
;
2245 dup
->UpdateServer
= rr
->UpdateServer
;
2246 dup
->UpdatePort
= rr
->UpdatePort
;
2247 dup
->Private
= rr
->Private
;
2248 dup
->state
= rr
->state
;
2249 rr
->RequireGoodbye
= mDNSfalse
;
2250 rr
->AnsweredLocalQ
= mDNSfalse
;
2256 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2257 p
= &m
->DuplicateRecords
;
2258 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2259 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2260 if (*p
) rr
->RequireGoodbye
= mDNSfalse
;
2261 if (*p
) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2262 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2267 // No need to log an error message if we already know this is a potentially repeated deregistration
2268 if (drt
!= mDNS_Dereg_repeat
)
2269 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr
, ARDisplayString(m
,rr
));
2270 return(mStatus_BadReferenceErr
);
2273 // If this is a shared record and we've announced it at least once,
2274 // we need to retract that announcement before we delete the record
2276 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2277 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
2278 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2279 // mechanism to cope with the client callback modifying the question list while that's happening.
2280 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2281 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2282 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2283 // records, thereby invoking yet more callbacks, without limit.
2284 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2285 // actual goodbye packets.
2287 #ifndef UNICAST_DISABLED
2288 if (AuthRecord_uDNS(rr
) && rr
->RequireGoodbye
)
2290 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2291 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2292 uDNS_DeregisterRecord(m
, rr
);
2293 // At this point unconditionally we bail out
2294 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2295 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2296 // process and will complete asynchronously. Either way we don't need to do anything more here.
2297 return(mStatus_NoError
);
2299 #endif // UNICAST_DISABLED
2301 if (RecordType
== kDNSRecordTypeShared
&& (rr
->RequireGoodbye
|| rr
->AnsweredLocalQ
))
2303 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m
, rr
));
2304 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2305 rr
->resrec
.rroriginalttl
= 0;
2306 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2307 if (m
->NextScheduledResponse
- (m
->timenow
+ mDNSPlatformOneSecond
/10) >= 0)
2308 m
->NextScheduledResponse
= (m
->timenow
+ mDNSPlatformOneSecond
/10);
2312 *p
= rr
->next
; // Cut this record from the list
2313 // If someone is about to look at this, bump the pointer forward
2314 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
2315 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
2316 rr
->next
= mDNSNULL
;
2318 if (RecordType
== kDNSRecordTypeUnregistered
)
2319 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m
, rr
));
2320 else if (RecordType
== kDNSRecordTypeDeregistering
)
2321 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m
, rr
));
2324 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m
, rr
));
2325 rr
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2328 if ((drt
== mDNS_Dereg_conflict
|| drt
== mDNS_Dereg_repeat
) && RecordType
== kDNSRecordTypeShared
)
2329 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2330 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2332 // If we have an update queued up which never executed, give the client a chance to free that memory
2333 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
2335 if (rr
->nta
) { CancelGetZoneData(m
, rr
->nta
); rr
->nta
= mDNSNULL
; }
2336 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2338 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2339 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2340 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2341 // so any attempt to touch rr after this is likely to lead to a crash.
2342 if (drt
!= mDNS_Dereg_conflict
)
2344 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2345 if (rr
->RecordCallback
)
2346 rr
->RecordCallback(m
, rr
, mStatus_MemFree
); // MUST NOT touch rr after this
2347 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2351 RecordProbeFailure(m
, rr
);
2352 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2353 if (rr
->RecordCallback
)
2354 rr
->RecordCallback(m
, rr
, mStatus_NameConflict
); // MUST NOT touch rr after this
2355 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2356 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2357 // Note that with all the client callbacks going on, by the time we get here all the
2358 // records we marked may have been explicitly deregistered by the client anyway.
2359 r2
= m
->DuplicateRecords
;
2362 if (r2
->ProbeCount
!= 0xFF) r2
= r2
->next
;
2363 else { mDNS_Deregister_internal(m
, r2
, mDNS_Dereg_conflict
); r2
= m
->DuplicateRecords
; }
2367 return(mStatus_NoError
);
2370 // ***************************************************************************
2371 #if COMPILER_LIKES_PRAGMA_MARK
2373 #pragma mark - Packet Sending Functions
2376 mDNSlocal
void AddRecordToResponseList(AuthRecord
***nrpp
, AuthRecord
*rr
, AuthRecord
*add
)
2378 if (rr
->NextResponse
== mDNSNULL
&& *nrpp
!= &rr
->NextResponse
)
2381 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2382 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2383 // The referenced record will definitely be acceptable (by recursive application of this rule)
2384 if (add
&& add
->NR_AdditionalTo
) add
= add
->NR_AdditionalTo
;
2385 rr
->NR_AdditionalTo
= add
;
2386 *nrpp
= &rr
->NextResponse
;
2388 debugf("AddRecordToResponseList: %##s (%s) already in list", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2391 mDNSlocal
void AddAdditionalsToResponseList(mDNS
*const m
, AuthRecord
*ResponseRecords
, AuthRecord
***nrpp
, const mDNSInterfaceID InterfaceID
)
2393 AuthRecord
*rr
, *rr2
;
2394 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // For each record we plan to put
2396 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2397 // later in the "for" loop, and we will follow further "additional" links then.)
2398 if (rr
->Additional1
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional1
, InterfaceID
))
2399 AddRecordToResponseList(nrpp
, rr
->Additional1
, rr
);
2401 if (rr
->Additional2
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional2
, InterfaceID
))
2402 AddRecordToResponseList(nrpp
, rr
->Additional2
, rr
);
2404 // For SRV records, automatically add the Address record(s) for the target host
2405 if (rr
->resrec
.rrtype
== kDNSType_SRV
)
2407 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2408 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2409 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2410 rr
->resrec
.rdatahash
== rr2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2411 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, rr2
->resrec
.name
))
2412 AddRecordToResponseList(nrpp
, rr2
, rr
);
2414 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
)) // For A or AAAA, put counterpart as additional
2416 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2417 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2418 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2419 rr
->resrec
.namehash
== rr2
->resrec
.namehash
&& // ... and have the same name
2420 SameDomainName(rr
->resrec
.name
, rr2
->resrec
.name
))
2421 AddRecordToResponseList(nrpp
, rr2
, rr
);
2423 else if (rr
->resrec
.rrtype
== kDNSType_PTR
) // For service PTR, see if we want to add DeviceInfo record
2425 if (ResourceRecordIsValidInterfaceAnswer(&m
->DeviceInfo
, InterfaceID
) &&
2426 SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2427 AddRecordToResponseList(nrpp
, &m
->DeviceInfo
, rr
);
2432 mDNSlocal
void SendDelayedUnicastResponse(mDNS
*const m
, const mDNSAddr
*const dest
, const mDNSInterfaceID InterfaceID
)
2435 AuthRecord
*ResponseRecords
= mDNSNULL
;
2436 AuthRecord
**nrp
= &ResponseRecords
;
2438 // Make a list of all our records that need to be unicast to this destination
2439 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2441 // If we find we can no longer unicast this answer, clear ImmedUnicast
2442 if (rr
->ImmedAnswer
== mDNSInterfaceMark
||
2443 mDNSSameIPv4Address(rr
->v4Requester
, onesIPv4Addr
) ||
2444 mDNSSameIPv6Address(rr
->v6Requester
, onesIPv6Addr
) )
2445 rr
->ImmedUnicast
= mDNSfalse
;
2447 if (rr
->ImmedUnicast
&& rr
->ImmedAnswer
== InterfaceID
)
2448 if ((dest
->type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->v4Requester
, dest
->ip
.v4
)) ||
2449 (dest
->type
== mDNSAddrType_IPv6
&& mDNSSameIPv6Address(rr
->v6Requester
, dest
->ip
.v6
)))
2451 rr
->ImmedAnswer
= mDNSNULL
; // Clear the state fields
2452 rr
->ImmedUnicast
= mDNSfalse
;
2453 rr
->v4Requester
= zerov4Addr
;
2454 rr
->v6Requester
= zerov6Addr
;
2455 if (rr
->NextResponse
== mDNSNULL
&& nrp
!= &rr
->NextResponse
) // rr->NR_AnswerTo
2456 { rr
->NR_AnswerTo
= (mDNSu8
*)~0; *nrp
= rr
; nrp
= &rr
->NextResponse
; }
2460 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
2462 while (ResponseRecords
)
2464 mDNSu8
*responseptr
= m
->omsg
.data
;
2466 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2468 // Put answers in the packet
2469 while (ResponseRecords
&& ResponseRecords
->NR_AnswerTo
)
2471 rr
= ResponseRecords
;
2472 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2473 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2474 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2475 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2476 if (!newptr
&& m
->omsg
.h
.numAnswers
) break; // If packet full, send it now
2477 if (newptr
) responseptr
= newptr
;
2478 ResponseRecords
= rr
->NextResponse
;
2479 rr
->NextResponse
= mDNSNULL
;
2480 rr
->NR_AnswerTo
= mDNSNULL
;
2481 rr
->NR_AdditionalTo
= mDNSNULL
;
2482 rr
->RequireGoodbye
= mDNStrue
;
2485 // Add additionals, if there's space
2486 while (ResponseRecords
&& !ResponseRecords
->NR_AnswerTo
)
2488 rr
= ResponseRecords
;
2489 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2490 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2491 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2492 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2494 if (newptr
) responseptr
= newptr
;
2495 if (newptr
&& m
->omsg
.h
.numAnswers
) rr
->RequireGoodbye
= mDNStrue
;
2496 else if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) rr
->ImmedAnswer
= mDNSInterfaceMark
;
2497 ResponseRecords
= rr
->NextResponse
;
2498 rr
->NextResponse
= mDNSNULL
;
2499 rr
->NR_AnswerTo
= mDNSNULL
;
2500 rr
->NR_AdditionalTo
= mDNSNULL
;
2503 if (m
->omsg
.h
.numAnswers
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, mDNSInterface_Any
, mDNSNULL
, dest
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2507 mDNSexport
void CompleteDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2509 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2510 // it should go ahead and immediately dispose of this registration
2511 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
2512 rr
->RequireGoodbye
= mDNSfalse
;
2513 if (rr
->AnsweredLocalQ
) { AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNSfalse
); rr
->AnsweredLocalQ
= mDNSfalse
; }
2514 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
); // Don't touch rr after this
2517 // Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2518 // the record list and/or question list.
2519 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2520 mDNSlocal
void DiscardDeregistrations(mDNS
*const m
)
2522 if (m
->CurrentRecord
)
2523 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
2524 m
->CurrentRecord
= m
->ResourceRecords
;
2526 while (m
->CurrentRecord
)
2528 AuthRecord
*rr
= m
->CurrentRecord
;
2529 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2530 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2532 m
->CurrentRecord
= rr
->next
;
2536 mDNSlocal mStatus
GetLabelDecimalValue(const mDNSu8
*const src
, mDNSu8
*dst
)
2539 if (src
[0] < 1 || src
[0] > 3) return(mStatus_Invalid
);
2540 for (i
=1; i
<=src
[0]; i
++)
2542 if (src
[i
] < '0' || src
[i
] > '9') return(mStatus_Invalid
);
2543 val
= val
* 10 + src
[i
] - '0';
2545 if (val
> 255) return(mStatus_Invalid
);
2547 return(mStatus_NoError
);
2550 mDNSlocal mStatus
GetIPv4FromName(mDNSAddr
*const a
, const domainname
*const name
)
2552 int skip
= CountLabels(name
) - 6;
2553 if (skip
< 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2554 if (GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+3)->c
, &a
->ip
.v4
.b
[0]) ||
2555 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+2)->c
, &a
->ip
.v4
.b
[1]) ||
2556 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+1)->c
, &a
->ip
.v4
.b
[2]) ||
2557 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+0)->c
, &a
->ip
.v4
.b
[3])) return mStatus_Invalid
;
2558 a
->type
= mDNSAddrType_IPv4
;
2559 return(mStatus_NoError
);
2562 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
2563 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
2564 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2566 mDNSlocal mStatus
GetIPv6FromName(mDNSAddr
*const a
, const domainname
*const name
)
2569 const domainname
*n
;
2571 int skip
= CountLabels(name
) - 34;
2572 if (skip
< 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2574 n
= SkipLeadingLabels(name
, skip
);
2575 for (i
=0; i
<16; i
++)
2577 if (n
->c
[0] != 1) return mStatus_Invalid
;
2578 l
= HexVal(n
->c
[1]);
2579 n
= (const domainname
*)(n
->c
+ 2);
2581 if (n
->c
[0] != 1) return mStatus_Invalid
;
2582 h
= HexVal(n
->c
[1]);
2583 n
= (const domainname
*)(n
->c
+ 2);
2585 if (l
<0 || h
<0) return mStatus_Invalid
;
2586 a
->ip
.v6
.b
[15-i
] = (h
<< 4) | l
;
2589 a
->type
= mDNSAddrType_IPv6
;
2590 return(mStatus_NoError
);
2593 mDNSlocal mDNSs32
ReverseMapDomainType(const domainname
*const name
)
2595 int skip
= CountLabels(name
) - 2;
2598 const domainname
*suffix
= SkipLeadingLabels(name
, skip
);
2599 if (SameDomainName(suffix
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4
;
2600 if (SameDomainName(suffix
, (const domainname
*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6
;
2602 return(mDNSAddrType_None
);
2605 mDNSlocal
void SendARP(mDNS
*const m
, const mDNSu8 op
, const AuthRecord
*const rr
,
2606 const mDNSu8
*const spa
, const mDNSu8
*const tha
, const mDNSu8
*const tpa
, const mDNSu8
*const dst
)
2609 mDNSu8
*ptr
= m
->omsg
.data
;
2610 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2611 if (!intf
) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr
->resrec
.InterfaceID
, ARDisplayString(m
,rr
)); return; }
2613 // 0x00 Destination address
2614 for (i
=0; i
<6; i
++) *ptr
++ = dst
[i
];
2616 // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
2617 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
2619 // 0x0C ARP Ethertype (0x0806)
2620 *ptr
++ = 0x08; *ptr
++ = 0x06;
2623 *ptr
++ = 0x00; *ptr
++ = 0x01; // Hardware address space; Ethernet = 1
2624 *ptr
++ = 0x08; *ptr
++ = 0x00; // Protocol address space; IP = 0x0800
2625 *ptr
++ = 6; // Hardware address length
2626 *ptr
++ = 4; // Protocol address length
2627 *ptr
++ = 0x00; *ptr
++ = op
; // opcode; Request = 1, Response = 2
2629 // 0x16 Sender hardware address (our MAC address)
2630 for (i
=0; i
<6; i
++) *ptr
++ = intf
->MAC
.b
[i
];
2632 // 0x1C Sender protocol address
2633 for (i
=0; i
<4; i
++) *ptr
++ = spa
[i
];
2635 // 0x20 Target hardware address
2636 for (i
=0; i
<6; i
++) *ptr
++ = tha
[i
];
2638 // 0x26 Target protocol address
2639 for (i
=0; i
<4; i
++) *ptr
++ = tpa
[i
];
2641 // 0x2A Total ARP Packet length 42 bytes
2642 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, rr
->resrec
.InterfaceID
);
2645 mDNSlocal
void SetupOwnerOpt(const mDNS
*const m
, const NetworkInterfaceInfo
*const intf
, rdataOPT
*const owner
)
2647 owner
->u
.owner
.vers
= 0;
2648 owner
->u
.owner
.seq
= m
->SleepSeqNum
;
2649 owner
->u
.owner
.HMAC
= m
->PrimaryMAC
;
2650 owner
->u
.owner
.IMAC
= intf
->MAC
;
2651 owner
->u
.owner
.password
= zeroEthAddr
;
2653 // Don't try to compute the optlen until *after* we've set up the data fields
2654 owner
->opt
= kDNSOpt_Owner
;
2655 owner
->optlen
= DNSOpt_Owner_Space(owner
) - 4;
2658 mDNSlocal
void GrantUpdateCredit(AuthRecord
*rr
)
2660 if (++rr
->UpdateCredits
>= kMaxUpdateCredits
) rr
->NextUpdateCredit
= 0;
2661 else rr
->NextUpdateCredit
= NonZeroTime(rr
->NextUpdateCredit
+ kUpdateCreditRefreshInterval
);
2664 // Note about acceleration of announcements to facilitate automatic coalescing of
2665 // multiple independent threads of announcements into a single synchronized thread:
2666 // The announcements in the packet may be at different stages of maturity;
2667 // One-second interval, two-second interval, four-second interval, and so on.
2668 // After we've put in all the announcements that are due, we then consider
2669 // whether there are other nearly-due announcements that are worth accelerating.
2670 // To be eligible for acceleration, a record MUST NOT be older (further along
2671 // its timeline) than the most mature record we've already put in the packet.
2672 // In other words, younger records can have their timelines accelerated to catch up
2673 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
2674 // Older records cannot have their timelines accelerated; this would just widen
2675 // the gap between them and their younger bretheren and get them even more out of sync.
2677 // Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
2678 // the record list and/or question list.
2679 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2680 mDNSlocal
void SendResponses(mDNS
*const m
)
2683 AuthRecord
*rr
, *r2
;
2684 mDNSs32 maxExistingAnnounceInterval
= 0;
2685 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
2687 m
->NextScheduledResponse
= m
->timenow
+ 0x78000000;
2689 if (m
->SleepState
== SleepState_Transferring
) RetrySPSRegistrations(m
);
2691 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2692 if (rr
->ImmedUnicast
)
2694 mDNSAddr v4
= { mDNSAddrType_IPv4
, {{{0}}} };
2695 mDNSAddr v6
= { mDNSAddrType_IPv6
, {{{0}}} };
2696 v4
.ip
.v4
= rr
->v4Requester
;
2697 v6
.ip
.v6
= rr
->v6Requester
;
2698 if (!mDNSIPv4AddressIsZero(rr
->v4Requester
)) SendDelayedUnicastResponse(m
, &v4
, rr
->ImmedAnswer
);
2699 if (!mDNSIPv6AddressIsZero(rr
->v6Requester
)) SendDelayedUnicastResponse(m
, &v6
, rr
->ImmedAnswer
);
2700 if (rr
->ImmedUnicast
)
2702 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m
, rr
));
2703 rr
->ImmedUnicast
= mDNSfalse
;
2708 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
2711 // Run through our list of records, and decide which ones we're going to announce on all interfaces
2712 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2714 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
2715 if (TimeToAnnounceThisRecord(rr
, m
->timenow
) && ResourceRecordIsValidAnswer(rr
))
2717 if (rr
->AddressProxy
.type
)
2719 rr
->AnnounceCount
--;
2720 rr
->ThisAPInterval
*= 2;
2721 rr
->LastAPTime
= m
->timenow
;
2722 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2724 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
));
2725 SendARP(m
, 1, rr
, rr
->AddressProxy
.ip
.v4
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, onesEthAddr
.b
);
2727 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2729 //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
2730 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2735 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2736 if (maxExistingAnnounceInterval
< rr
->ThisAPInterval
)
2737 maxExistingAnnounceInterval
= rr
->ThisAPInterval
;
2738 if (rr
->UpdateBlocked
) rr
->UpdateBlocked
= 0;
2743 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
2744 // Eligible records that are more than half-way to their announcement time are accelerated
2745 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2746 if ((rr
->resrec
.InterfaceID
&& rr
->ImmedAnswer
) ||
2747 (rr
->ThisAPInterval
<= maxExistingAnnounceInterval
&&
2748 TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2) &&
2749 !rr
->AddressProxy
.type
&& // Don't include ARP Annoucements when considering which records to accelerate
2750 ResourceRecordIsValidAnswer(rr
)))
2751 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2753 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
2754 // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
2755 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
2756 // then all that means is that it won't get sent -- which would not be the end of the world.
2757 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2759 if (rr
->ImmedAnswer
&& rr
->resrec
.rrtype
== kDNSType_SRV
)
2760 for (r2
=m
->ResourceRecords
; r2
; r2
=r2
->next
) // Scan list of resource records
2761 if (RRTypeIsAddressType(r2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2762 ResourceRecordIsValidAnswer(r2
) && // ... which are valid for answer ...
2763 rr
->LastMCTime
- r2
->LastMCTime
>= 0 && // ... which we have not sent recently ...
2764 rr
->resrec
.rdatahash
== r2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2765 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, r2
->resrec
.name
) &&
2766 (rr
->ImmedAnswer
== mDNSInterfaceMark
|| rr
->ImmedAnswer
== r2
->resrec
.InterfaceID
))
2767 r2
->ImmedAdditional
= r2
->resrec
.InterfaceID
; // ... then mark this address record for sending too
2768 // We also make sure we send the DeviceInfo TXT record too, if necessary
2769 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
2770 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
2771 if (rr
->ImmedAnswer
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->resrec
.rrtype
== kDNSType_PTR
)
2772 if (ResourceRecordIsValidAnswer(&m
->DeviceInfo
) && SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2774 if (!m
->DeviceInfo
.ImmedAnswer
) m
->DeviceInfo
.ImmedAnswer
= rr
->ImmedAnswer
;
2775 else m
->DeviceInfo
.ImmedAnswer
= mDNSInterfaceMark
;
2779 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
2780 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
2781 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
2782 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
2783 // -- 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
2784 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
2785 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2786 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2788 if (rr
->ImmedAnswer
) // If we're sending this as answer, see that its whole RRSet is similarly marked
2790 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2791 if (ResourceRecordIsValidAnswer(r2
))
2792 if (r2
->ImmedAnswer
!= mDNSInterfaceMark
&&
2793 r2
->ImmedAnswer
!= rr
->ImmedAnswer
&& SameResourceRecordSignature(r2
, rr
))
2794 r2
->ImmedAnswer
= !r2
->ImmedAnswer
? rr
->ImmedAnswer
: mDNSInterfaceMark
;
2796 else if (rr
->ImmedAdditional
) // If we're sending this as additional, see that its whole RRSet is similarly marked
2798 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2799 if (ResourceRecordIsValidAnswer(r2
))
2800 if (r2
->ImmedAdditional
!= rr
->ImmedAdditional
&& SameResourceRecordSignature(r2
, rr
))
2801 r2
->ImmedAdditional
= rr
->ImmedAdditional
;
2805 // Now set SendRNow state appropriately
2806 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2808 if (rr
->ImmedAnswer
== mDNSInterfaceMark
) // Sending this record on all appropriate interfaces
2810 rr
->SendRNow
= !intf
? mDNSNULL
: (rr
->resrec
.InterfaceID
) ? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
2811 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional if sending as answer
2812 rr
->LastMCTime
= m
->timenow
;
2813 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2814 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
2815 if (TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2))
2817 rr
->AnnounceCount
--;
2818 rr
->ThisAPInterval
*= 2;
2819 rr
->LastAPTime
= m
->timenow
;
2820 debugf("Announcing %##s (%s) %d", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->AnnounceCount
);
2823 else if (rr
->ImmedAnswer
) // Else, just respond to a single query on single interface:
2825 rr
->SendRNow
= rr
->ImmedAnswer
; // Just respond on that interface
2826 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional too
2827 rr
->LastMCTime
= m
->timenow
;
2828 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2830 SetNextAnnounceProbeTime(m
, rr
);
2831 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2835 // *** 2. Loop through interface list, sending records as appropriate
2841 int numAnnounce
= 0;
2843 mDNSu8
*responseptr
= m
->omsg
.data
;
2845 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2847 // First Pass. Look for:
2848 // 1. Deregistering records that need to send their goodbye packet
2849 // 2. Updated records that need to retract their old data
2850 // 3. Answers and announcements we need to send
2851 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2853 if (rr
->SendRNow
== intf
->InterfaceID
)
2856 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2858 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2859 if (newptr
) { responseptr
= newptr
; numDereg
++; }
2861 else if (rr
->NewRData
&& !m
->SleepState
) // If we have new data for this record
2863 RData
*OldRData
= rr
->resrec
.rdata
;
2864 mDNSu16 oldrdlength
= rr
->resrec
.rdlength
;
2865 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2866 if (ResourceRecordIsValidAnswer(rr
) && rr
->RequireGoodbye
)
2868 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2869 if (newptr
) { responseptr
= newptr
; numDereg
++; rr
->RequireGoodbye
= mDNSfalse
; }
2871 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2872 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
2873 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2874 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2875 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2876 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2877 if (newptr
) { responseptr
= newptr
; rr
->RequireGoodbye
= mDNStrue
; }
2878 SetNewRData(&rr
->resrec
, OldRData
, oldrdlength
);
2882 mDNSu8 active
= (m
->SleepState
!= SleepState_Sleeping
|| intf
->SPSAddr
[0].type
|| intf
->SPSAddr
[1].type
|| intf
->SPSAddr
[2].type
);
2883 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2884 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2885 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, active
? rr
->resrec
.rroriginalttl
: 0);
2886 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2889 responseptr
= newptr
;
2890 rr
->RequireGoodbye
= active
;
2891 if (rr
->LastAPTime
== m
->timenow
) numAnnounce
++; else numAnswer
++;
2894 // The first time through (pktcount==0), if this record is verified unique
2895 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2896 if (!pktcount
&& active
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= (mDNSInterfaceID
)1;
2899 if (newptr
) // If succeeded in sending, advance to next interface
2901 // If sending on all interfaces, go to next interface; else we're finished now
2902 if (rr
->ImmedAnswer
== mDNSInterfaceMark
&& rr
->resrec
.InterfaceID
== mDNSInterface_Any
)
2903 rr
->SendRNow
= GetNextActiveInterfaceID(intf
);
2905 rr
->SendRNow
= mDNSNULL
;
2910 // Second Pass. Add additional records, if there's space.
2911 newptr
= responseptr
;
2912 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2913 if (rr
->ImmedAdditional
== intf
->InterfaceID
)
2914 if (ResourceRecordIsValidAnswer(rr
))
2916 // If we have at least one answer already in the packet, then plan to add additionals too
2917 mDNSBool SendAdditional
= (m
->omsg
.h
.numAnswers
> 0);
2919 // If we're not planning to send any additionals, but this record is a unique one, then
2920 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2921 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2922 if (!SendAdditional
&& (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
))
2924 const AuthRecord
*a
;
2925 for (a
= m
->ResourceRecords
; a
; a
=a
->next
)
2926 if (a
->LastMCTime
== m
->timenow
&&
2927 a
->LastMCInterface
== intf
->InterfaceID
&&
2928 SameResourceRecordSignature(a
, rr
)) { SendAdditional
= mDNStrue
; break; }
2930 if (!SendAdditional
) // If we don't want to send this after all,
2931 rr
->ImmedAdditional
= mDNSNULL
; // then cancel its ImmedAdditional field
2932 else if (newptr
) // Else, try to add it if we can
2934 // The first time through (pktcount==0), if this record is verified unique
2935 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2936 if (!pktcount
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= (mDNSInterfaceID
)1;
2938 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2939 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2940 newptr
= PutResourceRecord(&m
->omsg
, newptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2941 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2944 responseptr
= newptr
;
2945 rr
->ImmedAdditional
= mDNSNULL
;
2946 rr
->RequireGoodbye
= mDNStrue
;
2947 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2948 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2949 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2950 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2951 rr
->LastMCTime
= m
->timenow
;
2952 rr
->LastMCInterface
= intf
->InterfaceID
;
2957 // Third Pass. Add NSEC records, if there's space.
2958 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2959 if (rr
->SendNSECNow
== (mDNSInterfaceID
)1 || rr
->SendNSECNow
== intf
->InterfaceID
)
2962 mDNS_SetupResourceRecord(&nsec
, mDNSNULL
, mDNSInterface_Any
, kDNSType_NSEC
, rr
->resrec
.rroriginalttl
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
2963 nsec
.resrec
.rrclass
|= kDNSClass_UniqueRRSet
;
2964 AssignDomainName(&nsec
.namestorage
, rr
->resrec
.name
);
2965 mDNSPlatformMemZero(nsec
.rdatastorage
.u
.nsec
.bitmap
, sizeof(nsec
.rdatastorage
.u
.nsec
.bitmap
));
2966 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2967 if (ResourceRecordIsValidAnswer(r2
) && SameResourceRecordNameClassInterface(r2
, rr
))
2969 if (r2
->resrec
.rrtype
>= kDNSQType_ANY
) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m
, r2
)); break; }
2970 else nsec
.rdatastorage
.u
.nsec
.bitmap
[r2
->resrec
.rrtype
>> 3] |= 128 >> (r2
->resrec
.rrtype
& 7);
2972 newptr
= responseptr
;
2973 if (!r2
) // If we successfully built our NSEC record, add it to the packet now
2975 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &nsec
.resrec
);
2976 if (newptr
) responseptr
= newptr
;
2979 // If we successfully put the NSEC record, clear the SendNSECNow flag
2980 // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
2981 if (newptr
|| rr
->SendNSECNow
== (mDNSInterfaceID
)1)
2983 rr
->SendNSECNow
= mDNSNULL
;
2984 // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
2985 for (r2
= rr
->next
; r2
; r2
=r2
->next
)
2986 if (SameResourceRecordNameClassInterface(r2
, rr
))
2987 if (r2
->SendNSECNow
== (mDNSInterfaceID
)1 || r2
->SendNSECNow
== intf
->InterfaceID
)
2988 r2
->SendNSECNow
= mDNSNULL
;
2992 if (m
->omsg
.h
.numAnswers
> 0 || m
->omsg
.h
.numAdditionals
)
2994 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2995 numDereg
, numDereg
== 1 ? "" : "s",
2996 numAnnounce
, numAnnounce
== 1 ? "" : "s",
2997 numAnswer
, numAnswer
== 1 ? "" : "s",
2998 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s", intf
->InterfaceID
);
2999 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3000 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3001 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
3002 if (++pktcount
>= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount
); break; }
3003 // There might be more things to send on this interface, so go around one more time and try again.
3005 else // Nothing more to send on this interface; go to next
3007 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3008 #if MDNS_DEBUGMSGS && 0
3009 const char *const msg
= next
? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3010 debugf(msg
, intf
, next
);
3013 pktcount
= 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
3018 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3021 if (m
->CurrentRecord
)
3022 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3023 m
->CurrentRecord
= m
->ResourceRecords
;
3024 while (m
->CurrentRecord
)
3026 rr
= m
->CurrentRecord
;
3027 m
->CurrentRecord
= rr
->next
;
3031 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3032 LogMsg("SendResponses: No active interface to send: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
3033 rr
->SendRNow
= mDNSNULL
;
3036 if (rr
->ImmedAnswer
)
3038 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
3040 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
3041 CompleteDeregistration(m
, rr
); // Don't touch rr after this
3044 rr
->ImmedAnswer
= mDNSNULL
;
3045 rr
->ImmedUnicast
= mDNSfalse
;
3046 rr
->v4Requester
= zerov4Addr
;
3047 rr
->v6Requester
= zerov6Addr
;
3051 verbosedebugf("SendResponses: Next in %ld ticks", m
->NextScheduledResponse
- m
->timenow
);
3054 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3055 // so we want to be lazy about how frequently we do it.
3056 // 1. If a cache record is currently referenced by *no* active questions,
3057 // then we don't mind expiring it up to a minute late (who will know?)
3058 // 2. Else, if a cache record is due for some of its final expiration queries,
3059 // we'll allow them to be late by up to 2% of the TTL
3060 // 3. Else, if a cache record has completed all its final expiration queries without success,
3061 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3062 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3063 // so allow at most 1/10 second lateness
3064 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
3065 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
3066 #define CacheCheckGracePeriod(RR) ( \
3067 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
3068 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
3069 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
3070 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
3071 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
3073 // Note: MUST call SetNextCacheCheckTime any time we change:
3075 // rr->resrec.rroriginalttl
3076 // rr->UnansweredQueries
3077 // rr->CRActiveQuestion
3078 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3079 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3080 mDNSlocal
void SetNextCacheCheckTime(mDNS
*const m
, CacheRecord
*const rr
)
3082 rr
->NextRequiredQuery
= RRExpireTime(rr
);
3084 // If we have an active question, then see if we want to schedule a refresher query for this record.
3085 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3086 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3088 rr
->NextRequiredQuery
-= TicksTTL(rr
)/20 * (MaxUnansweredQueries
- rr
->UnansweredQueries
);
3089 rr
->NextRequiredQuery
+= mDNSRandom((mDNSu32
)TicksTTL(rr
)/50);
3090 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3091 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
),
3092 (rr
->NextRequiredQuery
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
));
3095 if (m
->NextCacheCheck
- (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
)) > 0)
3096 m
->NextCacheCheck
= (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
));
3098 if (rr
->DelayDelivery
)
3099 if (m
->NextCacheCheck
- rr
->DelayDelivery
> 0)
3100 m
->NextCacheCheck
= rr
->DelayDelivery
;
3103 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
3104 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
3105 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
3106 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3108 mDNSlocal mStatus
mDNS_Reconfirm_internal(mDNS
*const m
, CacheRecord
*const rr
, mDNSu32 interval
)
3110 if (interval
< kMinimumReconfirmTime
)
3111 interval
= kMinimumReconfirmTime
;
3112 if (interval
> 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
3113 interval
= 0x10000000;
3115 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3116 if (RRExpireTime(rr
) - m
->timenow
> (mDNSs32
)((interval
* 4) / 3))
3118 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3119 // For all the reconfirmations in a given batch, we want to use the same random value
3120 // so that the reconfirmation questions can be grouped into a single query packet
3121 if (!m
->RandomReconfirmDelay
) m
->RandomReconfirmDelay
= 1 + mDNSRandom(0x3FFFFFFF);
3122 interval
+= m
->RandomReconfirmDelay
% ((interval
/3) + 1);
3123 rr
->TimeRcvd
= m
->timenow
- (mDNSs32
)interval
* 3;
3124 rr
->resrec
.rroriginalttl
= (interval
* 4 + mDNSPlatformOneSecond
- 1) / mDNSPlatformOneSecond
;
3125 SetNextCacheCheckTime(m
, rr
);
3127 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
3128 RRExpireTime(rr
) - m
->timenow
, CRDisplayString(m
, rr
), rr
->CRActiveQuestion
);
3129 return(mStatus_NoError
);
3132 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
3134 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3135 // It also appends to the list of known answer records that need to be included,
3136 // and updates the forcast for the size of the known answer section.
3137 mDNSlocal mDNSBool
BuildQuestion(mDNS
*const m
, DNSMessage
*query
, mDNSu8
**queryptr
, DNSQuestion
*q
,
3138 CacheRecord
***kalistptrptr
, mDNSu32
*answerforecast
)
3140 mDNSBool ucast
= (q
->LargeAnswers
|| q
->RequestUnicast
) && m
->CanReceiveUnicastOn5353
;
3141 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3142 const mDNSu8
*const limit
= query
->data
+ NormalMaxDNSMessageData
;
3143 mDNSu8
*newptr
= putQuestion(query
, *queryptr
, limit
, &q
->qname
, q
->qtype
, (mDNSu16
)(q
->qclass
| ucbit
));
3146 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3149 else if (newptr
+ *answerforecast
>= limit
)
3151 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3152 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ *answerforecast
- query
->data
);
3153 query
->h
.numQuestions
--;
3158 mDNSu32 forecast
= *answerforecast
;
3159 const mDNSu32 slot
= HashSlot(&q
->qname
);
3160 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3162 CacheRecord
**ka
= *kalistptrptr
; // Make a working copy of the pointer we're going to update
3164 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3165 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3166 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not already in the known answer list
3167 rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3168 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3169 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
> // and its half-way-to-expiry time is at least 1 second away
3170 mDNSPlatformOneSecond
) // (also ensures we never include goodbye records with TTL=1)
3172 *ka
= rr
; // Link this record into our known answer chain
3173 ka
= &rr
->NextInKAList
;
3174 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3175 forecast
+= 12 + rr
->resrec
.rdestimate
;
3176 // If we're trying to put more than one question in this packet, and it doesn't fit
3177 // then undo that last question and try again next time
3178 if (query
->h
.numQuestions
> 1 && newptr
+ forecast
>= limit
)
3180 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3181 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ forecast
- query
->data
);
3182 query
->h
.numQuestions
--;
3183 ka
= *kalistptrptr
; // Go back to where we started and retract these answer records
3184 while (*ka
) { CacheRecord
*c
= *ka
; *ka
= mDNSNULL
; ka
= &c
->NextInKAList
; }
3185 return(mDNSfalse
); // Return false, so we'll try again in the next packet
3189 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3190 *queryptr
= newptr
; // Update the packet pointer
3191 *answerforecast
= forecast
; // Update the forecast
3192 *kalistptrptr
= ka
; // Update the known answer list pointer
3193 if (ucast
) q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3195 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // For every resource record in our cache,
3196 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3197 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not in the known answer list
3198 SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) // which answers our question
3200 rr
->UnansweredQueries
++; // indicate that we're expecting a response
3201 rr
->LastUnansweredTime
= m
->timenow
;
3202 SetNextCacheCheckTime(m
, rr
);
3209 // When we have a query looking for a specified name, but there appear to be no answers with
3210 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
3211 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
3212 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
3213 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
3214 // A typical reconfirmation scenario might go like this:
3215 // Depth 0: Name "myhost.local" has no address records
3216 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
3217 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
3218 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
3219 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
3220 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
3221 mDNSlocal
void ReconfirmAntecedents(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const int depth
)
3226 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth
, name
->c
);
3227 FORALL_CACHERECORDS(slot
, cg
, cr
)
3229 domainname
*crtarget
= GetRRDomainNameTarget(&cr
->resrec
);
3230 if (crtarget
&& cr
->resrec
.rdatahash
== namehash
&& SameDomainName(crtarget
, name
))
3232 LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth
, CRDisplayString(m
, cr
));
3233 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
3234 if (depth
< 5) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, depth
+1);
3239 // If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
3240 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
3241 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
3242 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
3243 mDNSlocal
const CacheRecord
*CacheHasAddressTypeForName(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
)
3245 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(name
), namehash
, name
);
3246 const CacheRecord
*cr
= cg
? cg
->members
: mDNSNULL
;
3247 while (cr
&& !RRTypeIsAddressType(cr
->resrec
.rrtype
)) cr
=cr
->next
;
3251 mDNSlocal
const CacheRecord
*FindSPSInCache1(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*const c0
, const CacheRecord
*const c1
)
3253 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(&q
->qname
), q
->qnamehash
, &q
->qname
);
3254 const CacheRecord
*cr
, *bestcr
= mDNSNULL
;
3255 mDNSu32 bestmetric
= 1000000;
3256 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
3257 if (cr
->resrec
.rrtype
== kDNSType_PTR
&& cr
->resrec
.rdlength
>= 6) // If record is PTR type, with long enough name,
3258 if (cr
!= c0
&& cr
!= c1
) // that's not one we've seen before,
3259 if (SameNameRecordAnswersQuestion(&cr
->resrec
, q
)) // and answers our browse query,
3260 if (!IdenticalSameNameRecord(&cr
->resrec
, &m
->SPSRecords
.RR_PTR
.resrec
)) // and is not our own advertised service...
3262 mDNSu32 metric
= SPSMetric(cr
->resrec
.rdata
->u
.name
.c
);
3263 if (bestmetric
> metric
) { bestmetric
= metric
; bestcr
= cr
; }
3268 // Finds the three best Sleep Proxies we currently have in our cache
3269 mDNSexport
void FindSPSInCache(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*sps
[3])
3271 sps
[0] = FindSPSInCache1(m
, q
, mDNSNULL
, mDNSNULL
);
3272 sps
[1] = !sps
[0] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], mDNSNULL
);
3273 sps
[2] = !sps
[1] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], sps
[1]);
3276 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3277 mDNSlocal
void ExpireDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
)
3280 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3283 mDNSlocal
void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
, mDNSInterfaceID InterfaceID
)
3286 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3289 mDNSlocal mDNSBool
SuppressOnThisInterface(const DupSuppressInfo ds
[DupSuppressInfoSize
], const NetworkInterfaceInfo
* const intf
)
3292 mDNSBool v4
= !intf
->IPv4Available
; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3293 mDNSBool v6
= !intf
->IPv6Available
; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3294 for (i
=0; i
<DupSuppressInfoSize
; i
++)
3295 if (ds
[i
].InterfaceID
== intf
->InterfaceID
)
3297 if (ds
[i
].Type
== mDNSAddrType_IPv4
) v4
= mDNStrue
;
3298 else if (ds
[i
].Type
== mDNSAddrType_IPv6
) v6
= mDNStrue
;
3299 if (v4
&& v6
) return(mDNStrue
);
3304 mDNSlocal
int RecordDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 Time
, mDNSInterfaceID InterfaceID
, mDNSs32 Type
)
3308 // See if we have this one in our list somewhere already
3309 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Type
== Type
) break;
3311 // If not, find a slot we can re-use
3312 if (i
>= DupSuppressInfoSize
)
3315 for (j
=1; j
<DupSuppressInfoSize
&& ds
[i
].InterfaceID
; j
++)
3316 if (!ds
[j
].InterfaceID
|| ds
[j
].Time
- ds
[i
].Time
< 0)
3320 // Record the info about this query we saw
3322 ds
[i
].InterfaceID
= InterfaceID
;
3328 mDNSlocal mDNSBool
AccelerateThisQuery(mDNS
*const m
, DNSQuestion
*q
)
3330 // If more than 90% of the way to the query time, we should unconditionally accelerate it
3331 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/10))
3334 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3335 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/2))
3337 // We forecast: qname (n) type (2) class (2)
3338 mDNSu32 forecast
= (mDNSu32
)DomainNameLength(&q
->qname
) + 4;
3339 const mDNSu32 slot
= HashSlot(&q
->qname
);
3340 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3341 const CacheRecord
*rr
;
3342 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3343 if (rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3344 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3345 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
>= 0 && // and it is less than half-way to expiry
3346 rr
->NextRequiredQuery
- (m
->timenow
+ q
->ThisQInterval
) > 0)// and we'll ask at least once again before NextRequiredQuery
3348 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3349 forecast
+= 12 + rr
->resrec
.rdestimate
;
3350 if (forecast
>= 512) return(mDNSfalse
); // If this would add 512 bytes or more to the packet, don't accelerate
3358 // How Standard Queries are generated:
3359 // 1. The Question Section contains the question
3360 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3362 // How Probe Queries are generated:
3363 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3364 // if some other host is already using *any* records with this name, we want to know about it.
3365 // 2. The Authority Section contains the proposed values we intend to use for one or more
3366 // of our records with that name (analogous to the Update section of DNS Update packets)
3367 // because if some other host is probing at the same time, we each want to know what the other is
3368 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3370 mDNSlocal
void SendQueries(mDNS
*const m
)
3378 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3379 mDNSs32 maxExistingQuestionInterval
= 0;
3380 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
3381 CacheRecord
*KnownAnswerList
= mDNSNULL
;
3383 // 1. If time for a query, work out what we need to do
3384 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
3388 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
3389 // to their NextRequiredQuery to be worth batching them together with this one
3390 FORALL_CACHERECORDS(slot
, cg
, rr
)
3391 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3392 if (m
->timenow
+ TicksTTL(rr
)/50 - rr
->NextRequiredQuery
>= 0)
3394 debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr
->UnansweredQueries
, CRDisplayString(m
, rr
));
3395 q
= rr
->CRActiveQuestion
;
3396 ExpireDupSuppressInfoOnInterface(q
->DupSuppress
, m
->timenow
- TicksTTL(rr
)/20, rr
->resrec
.InterfaceID
);
3397 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
3398 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
3399 if (q
->Target
.type
) q
->SendQNow
= mDNSInterfaceMark
; // If targeted query, mark it
3400 else if (!mDNSOpaque16IsZero(q
->TargetQID
)) { q
->LastQTime
= m
->timenow
- q
->ThisQInterval
; rr
->UnansweredQueries
++; }
3401 else if (q
->SendQNow
== mDNSNULL
) q
->SendQNow
= rr
->resrec
.InterfaceID
;
3402 else if (q
->SendQNow
!= rr
->resrec
.InterfaceID
) q
->SendQNow
= mDNSInterfaceMark
;
3405 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
3406 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
3408 // Scan our list of questions to see which:
3409 // *WideArea* queries need to be sent
3410 // *unicast* queries need to be sent
3411 // *multicast* queries we're definitely going to send
3412 if (m
->CurrentQuestion
)
3413 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3414 m
->CurrentQuestion
= m
->Questions
;
3415 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3417 q
= m
->CurrentQuestion
;
3418 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
)) uDNS_CheckCurrentQuestion(m
);
3419 else if (mDNSOpaque16IsZero(q
->TargetQID
) && q
->Target
.type
&& (q
->SendQNow
|| TimeToSendThisQuestion(q
, m
->timenow
)))
3421 mDNSu8
*qptr
= m
->omsg
.data
;
3422 const mDNSu8
*const limit
= m
->omsg
.data
+ sizeof(m
->omsg
.data
);
3424 // 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
3425 if (!q
->LocalSocket
) q
->LocalSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
3428 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, QueryFlags
);
3429 qptr
= putQuestion(&m
->omsg
, qptr
, limit
, &q
->qname
, q
->qtype
, q
->qclass
);
3430 mDNSSendDNSMessage(m
, &m
->omsg
, qptr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->Target
, q
->TargetPort
, mDNSNULL
, mDNSNULL
);
3431 q
->ThisQInterval
*= QuestionIntervalStep
;
3433 if (q
->ThisQInterval
> MaxQuestionInterval
)
3434 q
->ThisQInterval
= MaxQuestionInterval
;
3435 q
->LastQTime
= m
->timenow
;
3436 q
->LastQTxTime
= m
->timenow
;
3437 q
->RecentAnswerPkts
= 0;
3438 q
->SendQNow
= mDNSNULL
;
3439 q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3441 else if (mDNSOpaque16IsZero(q
->TargetQID
) && !q
->Target
.type
&& TimeToSendThisQuestion(q
, m
->timenow
))
3443 //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3444 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3445 if (maxExistingQuestionInterval
< q
->ThisQInterval
)
3446 maxExistingQuestionInterval
= q
->ThisQInterval
;
3448 // If m->CurrentQuestion wasn't modified out from under us, advance it now
3449 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
3450 // m->CurrentQuestion point to the right question
3451 if (q
== m
->CurrentQuestion
) m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
3453 m
->CurrentQuestion
= mDNSNULL
;
3455 // Scan our list of questions
3456 // (a) to see if there are any more that are worth accelerating, and
3457 // (b) to update the state variables for *all* the questions we're going to send
3458 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
3459 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
3460 // 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.
3461 m
->NextScheduledQuery
= m
->timenow
+ 0x78000000;
3462 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3464 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
||
3465 (!q
->Target
.type
&& ActiveQuestion(q
) && q
->ThisQInterval
<= maxExistingQuestionInterval
&& AccelerateThisQuery(m
,q
))))
3467 // If at least halfway to next query time, advance to next interval
3468 // If less than halfway to next query time, then
3469 // treat this as logically a repeat of the last transmission, without advancing the interval
3470 if (m
->timenow
- (q
->LastQTime
+ q
->ThisQInterval
/2) >= 0)
3472 //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3473 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3474 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
3475 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->ThisQInterval
/ InitialQuestionInterval
, q
->RequestUnicast
);
3476 q
->ThisQInterval
*= QuestionIntervalStep
;
3477 if (q
->ThisQInterval
> MaxQuestionInterval
)
3478 q
->ThisQInterval
= MaxQuestionInterval
;
3479 else if (q
->CurrentAnswers
== 0 && q
->ThisQInterval
== InitialQuestionInterval
* QuestionIntervalStep3
&& !q
->RequestUnicast
&&
3480 !(RRTypeIsAddressType(q
->qtype
) && CacheHasAddressTypeForName(m
, &q
->qname
, q
->qnamehash
)))
3482 // Generally don't need to log this.
3483 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
3484 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
3485 // and when there simply happen to be no instances of the service the client is looking
3486 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
3487 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3488 q
->qname
.c
, DNSTypeName(q
->qtype
));
3489 // Sending third query, and no answers yet; time to begin doubting the source
3490 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
3494 // Mark for sending. (If no active interfaces, then don't even try.)
3495 q
->SendOnAll
= (q
->SendQNow
== mDNSInterfaceMark
);
3498 q
->SendQNow
= !intf
? mDNSNULL
: (q
->InterfaceID
) ? q
->InterfaceID
: intf
->InterfaceID
;
3499 q
->LastQTime
= m
->timenow
;
3502 // If we recorded a duplicate suppression for this question less than half an interval ago,
3503 // then we consider it recent enough that we don't need to do an identical query ourselves.
3504 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
- q
->ThisQInterval
/2);
3506 q
->LastQTxTime
= m
->timenow
;
3507 q
->RecentAnswerPkts
= 0;
3508 if (q
->RequestUnicast
) q
->RequestUnicast
--;
3510 // For all questions (not just the ones we're sending) check what the next scheduled event will be
3511 SetNextQueryTime(m
,q
);
3515 // 2. Scan our authoritative RR list to see what probes we might need to send
3516 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
3518 m
->NextScheduledProbe
= m
->timenow
+ 0x78000000;
3520 if (m
->CurrentRecord
)
3521 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3522 m
->CurrentRecord
= m
->ResourceRecords
;
3523 while (m
->CurrentRecord
)
3525 AuthRecord
*rr
= m
->CurrentRecord
;
3526 m
->CurrentRecord
= rr
->next
;
3527 if (!AuthRecord_uDNS(rr
) && rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) // For all records that are still probing...
3529 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3530 if (m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) < 0)
3532 SetNextAnnounceProbeTime(m
, rr
);
3534 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3535 else if (rr
->ProbeCount
)
3537 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3539 LogSPS("SendQueries ARP Probe %d %s %s", rr
->ProbeCount
, InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), ARDisplayString(m
,rr
));
3540 SendARP(m
, 1, rr
, zerov4Addr
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, rr
->WakeUp
.IMAC
.b
);
3542 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3544 //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
3545 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
3547 // Mark for sending. (If no active interfaces, then don't even try.)
3548 rr
->SendRNow
= (!intf
|| rr
->WakeUp
.HMAC
.l
[0]) ? mDNSNULL
: rr
->resrec
.InterfaceID
? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
3549 rr
->LastAPTime
= m
->timenow
;
3550 // When we have a late conflict that resets a record to probing state we use a special marker value greater
3551 // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
3552 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
3553 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
3555 SetNextAnnounceProbeTime(m
, rr
);
3556 if (rr
->ProbeCount
== 0)
3558 // If this is the last probe for this record, then see if we have any matching records
3559 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
3561 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
)
3562 if (r2
->resrec
.RecordType
== kDNSRecordTypeUnique
&& RecordIsLocalDuplicate(r2
, rr
))
3564 // ... then acknowledge this record to the client.
3565 // We do this optimistically, just as we're about to send the third probe.
3566 // This helps clients that both advertise and browse, and want to filter themselves
3567 // from the browse results list, because it helps ensure that the registration
3568 // confirmation will be delivered 1/4 second *before* the browse "add" event.
3569 // A potential downside is that we could deliver a registration confirmation and then find out
3570 // moments later that there's a name conflict, but applications have to be prepared to handle
3571 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
3572 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
);
3575 // else, if it has now finished probing, move it to state Verified,
3576 // and update m->NextScheduledResponse so it will be announced
3579 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
); // Defensive, just in case it got missed somehow
3580 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
3581 rr
->ThisAPInterval
= DefaultAnnounceIntervalForTypeUnique
;
3582 rr
->LastAPTime
= m
->timenow
- DefaultAnnounceIntervalForTypeUnique
;
3583 SetNextAnnounceProbeTime(m
, rr
);
3587 m
->CurrentRecord
= m
->DuplicateRecords
;
3588 while (m
->CurrentRecord
)
3590 AuthRecord
*rr
= m
->CurrentRecord
;
3591 m
->CurrentRecord
= rr
->next
;
3592 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& rr
->ProbeCount
== 0 && !rr
->Acknowledged
)
3593 AcknowledgeRecord(m
, rr
);
3597 // 3. Now we know which queries and probes we're sending,
3598 // go through our interface list sending the appropriate queries on each interface
3601 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
;
3602 int OwnerRecordSpace
= 0;
3604 mDNSu8
*queryptr
= m
->omsg
.data
;
3605 mDNSu8
*limit
= m
->omsg
.data
+ AbsoluteMaxDNSMessageData
;
3606 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, QueryFlags
);
3607 if (KnownAnswerList
) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
3608 if (!KnownAnswerList
)
3610 // Start a new known-answer list
3611 CacheRecord
**kalistptr
= &KnownAnswerList
;
3612 mDNSu32 answerforecast
= 0;
3614 // Put query questions in this packet
3615 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3617 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
== intf
->InterfaceID
))
3619 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3620 SuppressOnThisInterface(q
->DupSuppress
, intf
) ? "Suppressing" : "Putting ",
3621 q
->qname
.c
, DNSTypeName(q
->qtype
), queryptr
- m
->omsg
.data
, queryptr
+ answerforecast
- m
->omsg
.data
);
3623 // If we're suppressing this question, or we successfully put it, update its SendQNow state
3624 if (SuppressOnThisInterface(q
->DupSuppress
, intf
) ||
3625 BuildQuestion(m
, &m
->omsg
, &queryptr
, q
, &kalistptr
, &answerforecast
))
3626 q
->SendQNow
= (q
->InterfaceID
|| !q
->SendOnAll
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3628 // Once we've put at least one question, cut back our limit to the normal single-packet size
3629 if (m
->omsg
.h
.numQuestions
) limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
;
3633 // Put probe questions in this packet
3634 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3635 if (rr
->SendRNow
== intf
->InterfaceID
)
3637 mDNSBool ucast
= (rr
->ProbeCount
>= DefaultProbeCountForTypeUnique
-1) && m
->CanReceiveUnicastOn5353
;
3638 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3639 mDNSu8
*newptr
= putQuestion(&m
->omsg
, queryptr
, limit
, rr
->resrec
.name
, kDNSQType_ANY
, (mDNSu16
)(rr
->resrec
.rrclass
| ucbit
));
3640 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3641 mDNSu32 forecast
= answerforecast
+ 12 + rr
->resrec
.rdestimate
;
3642 if (newptr
&& newptr
+ forecast
+ os
< limit
)
3645 limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
;
3646 answerforecast
= forecast
;
3647 OwnerRecordSpace
= os
;
3648 rr
->SendRNow
= (rr
->resrec
.InterfaceID
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3649 rr
->IncludeInProbe
= mDNStrue
;
3650 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
3651 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->ProbeCount
);
3655 verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
3656 m
->omsg
.h
.numQuestions
--;
3661 if (m
->omsg
.h
.numQuestions
) limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
- OwnerRecordSpace
;
3663 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3664 while (KnownAnswerList
)
3666 CacheRecord
*ka
= KnownAnswerList
;
3667 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- ka
->TimeRcvd
)) / mDNSPlatformOneSecond
;
3668 mDNSu8
*newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAnswers
, &ka
->resrec
, ka
->resrec
.rroriginalttl
- SecsSinceRcvd
, limit
);
3671 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
3672 ka
->resrec
.name
->c
, DNSTypeName(ka
->resrec
.rrtype
), queryptr
- m
->omsg
.data
, newptr
- m
->omsg
.data
);
3674 limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
- OwnerRecordSpace
;
3675 KnownAnswerList
= ka
->NextInKAList
;
3676 ka
->NextInKAList
= mDNSNULL
;
3680 // If we ran out of space and we have more than one question in the packet, that's an error --
3681 // we shouldn't have put more than one question if there was a risk of us running out of space.
3682 if (m
->omsg
.h
.numQuestions
> 1)
3683 LogMsg("SendQueries: Put %d answers; No more space for known answers", m
->omsg
.h
.numAnswers
);
3684 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_TC
;
3689 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3690 if (rr
->IncludeInProbe
)
3692 mDNSu8
*newptr
= PutResourceRecord(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAuthorities
, &rr
->resrec
);
3693 rr
->IncludeInProbe
= mDNSfalse
;
3694 if (newptr
) queryptr
= newptr
;
3695 else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m
,rr
));
3698 if (OwnerRecordSpace
)
3701 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
3702 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
3703 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
3704 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
3705 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[0]);
3706 LogSPS("SendQueries putting %s", ARDisplayString(m
, &opt
));
3707 queryptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAdditionals
,
3708 &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
3710 LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3711 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAdditionals
, ARDisplayString(m
, &opt
));
3714 if (queryptr
> m
->omsg
.data
)
3716 if ((m
->omsg
.h
.flags
.b
[0] & kDNSFlag0_TC
) && m
->omsg
.h
.numQuestions
> 1)
3717 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m
->omsg
.h
.numQuestions
);
3718 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
3719 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
3720 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
3721 m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAuthorities
== 1 ? "" : "s", intf
->InterfaceID
);
3722 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3723 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3724 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
3725 if (++pktcount
>= 1000)
3726 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount
); break; }
3727 // There might be more records left in the known answer list, or more questions to send
3728 // on this interface, so go around one more time and try again.
3730 else // Nothing more to send on this interface; go to next
3732 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3733 #if MDNS_DEBUGMSGS && 0
3734 const char *const msg
= next
? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
3735 debugf(msg
, intf
, next
);
3741 // 4. Final housekeeping
3743 // 4a. Debugging check: Make sure we announced all our records
3744 for (ar
= m
->ResourceRecords
; ar
; ar
=ar
->next
)
3747 if (ar
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3748 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m
, ar
));
3749 ar
->SendRNow
= mDNSNULL
;
3752 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3753 // that their interface which went away might come back again, the logic will want to send queries
3754 // for those records, but we can't because their interface isn't here any more, so to keep the
3755 // state machine ticking over we just pretend we did so.
3756 // If the interface does not come back in time, the cache record will expire naturally
3757 FORALL_CACHERECORDS(slot
, cg
, cr
)
3758 if (cr
->CRActiveQuestion
&& cr
->UnansweredQueries
< MaxUnansweredQueries
&& m
->timenow
- cr
->NextRequiredQuery
>= 0)
3760 cr
->UnansweredQueries
++;
3761 cr
->CRActiveQuestion
->SendQNow
= mDNSNULL
;
3762 SetNextCacheCheckTime(m
, cr
);
3765 // 4c. Debugging check: Make sure we sent all our planned questions
3766 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3767 // we legitimately couldn't send because the interface is no longer available
3768 for (q
= m
->Questions
; q
; q
=q
->next
)
3771 LogMsg("SendQueries: No active interface to send: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3772 q
->SendQNow
= mDNSNULL
;
3776 mDNSlocal
void SendWakeup(mDNS
*const m
, mDNSInterfaceID InterfaceID
, mDNSEthAddr
*EthAddr
, mDNSOpaque48
*password
)
3779 mDNSu8
*ptr
= m
->omsg
.data
;
3781 if (!InterfaceID
) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
3783 // 0x00 Destination address
3784 for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3786 // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
3787 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
3789 // 0x0C Ethertype (0x0842)
3793 // 0x0E Wakeup sync sequence
3794 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
3797 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3800 for (i
=0; i
<6; i
++) *ptr
++ = password
->b
[i
];
3802 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3804 // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
3805 // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
3806 // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
3807 // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
3808 // So, we send one of each, unicast first, then broadcast second.
3809 for (i
=0; i
<6; i
++) m
->omsg
.data
[i
] = 0xFF;
3810 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3813 // ***************************************************************************
3814 #if COMPILER_LIKES_PRAGMA_MARK
3816 #pragma mark - RR List Management & Task Management
3819 // Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3820 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
3821 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
3822 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
3823 mDNSexport
void AnswerCurrentQuestionWithResourceRecord(mDNS
*const m
, CacheRecord
*const rr
, const QC_result AddRecord
)
3825 DNSQuestion
*const q
= m
->CurrentQuestion
;
3826 mDNSBool followcname
= rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& AddRecord
&&
3827 rr
->resrec
.rrtype
== kDNSType_CNAME
&& q
->qtype
!= kDNSType_CNAME
;
3828 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q
->CurrentAnswers
, AddRecord
? "Add" : "Rmv", rr
->resrec
.rroriginalttl
, CRDisplayString(m
, rr
));
3830 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
3831 // may be called twice, once when the record is received, and again when it's time to notify local clients.
3832 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3834 rr
->LastUsed
= m
->timenow
;
3835 if (AddRecord
== QC_add
&& !q
->DuplicateOf
&& rr
->CRActiveQuestion
!= q
)
3837 if (!rr
->CRActiveQuestion
) m
->rrcache_active
++; // If not previously active, increment rrcache_active count
3838 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
3839 rr
->CRActiveQuestion
= q
; // We know q is non-null
3840 SetNextCacheCheckTime(m
, rr
);
3844 // (a) a no-cache add, where we've already done at least one 'QM' query, or
3845 // (b) a normal add, where we have at least one unique-type answer,
3846 // then there's no need to keep polling the network.
3847 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3848 // We do this for mDNS questions and uDNS one-shot questions, but not for
3849 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
3850 if ((AddRecord
== QC_addnocache
&& !q
->RequestUnicast
) ||
3851 (AddRecord
== QC_add
&& (q
->ExpectUnique
|| (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))))
3852 if (ActiveQuestion(q
) && (mDNSOpaque16IsZero(q
->TargetQID
) || !q
->LongLived
))
3854 q
->LastQTime
= m
->timenow
;
3855 q
->LastQTxTime
= m
->timenow
;
3856 q
->RecentAnswerPkts
= 0;
3857 q
->ThisQInterval
= MaxQuestionInterval
;
3858 q
->RequestUnicast
= mDNSfalse
;
3859 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3862 if (rr
->DelayDelivery
) return; // We'll come back later when CacheRecordDeferredAdd() calls us
3864 // Only deliver negative answers if client has explicitly requested them
3865 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
|| (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
)))
3866 if (!AddRecord
|| !q
->ReturnIntermed
) return;
3868 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
3869 if (q
->QuestionCallback
&& !q
->NoAnswer
&& (!followcname
|| q
->ReturnIntermed
))
3871 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
3872 if (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
))
3875 MakeNegativeCacheRecord(m
, &neg
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 1, rr
->resrec
.InterfaceID
);
3876 q
->QuestionCallback(m
, q
, &neg
.resrec
, AddRecord
);
3879 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
3880 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3882 // Note: Proceed with caution here because client callback function is allowed to do anything,
3883 // including starting/stopping queries, registering/deregistering records, etc.
3885 if (followcname
&& m
->CurrentQuestion
== q
&& q
->CNAMEReferrals
< 10)
3887 const mDNSu32 c
= q
->CNAMEReferrals
+ 1;
3888 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
3889 // and track CNAMEs coming and going, we should really create a subordinate query here,
3890 // which we would subsequently cancel and retract if the CNAME referral record were removed.
3891 // In reality this is such a corner case we'll ignore it until someone actually needs it.
3892 LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m
, rr
));
3894 // If this query is a duplicate of another query, UpdateQuestionDuplicates called from
3895 // mDNS_StopQuery_internal copies the value of CNAMEReferrals from this query to the other
3896 // query on the Questions list. By setting the new value before calling mDNS_StopQuery_internal,
3897 // we ensure that the duplicate question gets a hgigher value and eventually the check for 10 above
3898 // would be true. Otherwise, the two queries would end up as active questions
3899 // sending mDNSResponder in an infinite loop e.g., Two queries starting off unique but receives
3900 // a CNAME response that refers to itself (test IN CNAME test) which makes it a duplicate of
3901 // one another. This fix now will make sure that stop at the 10th iteration.
3903 // Though CNAME records that refer to itself are not added anymore in mDNSCoreReceiveResponse, this fix is
3904 // still needed to catch the cases where the CNAME referral spans across multiple records with a potential
3905 // cycle in it which in turn can make multiple queries duplicate of each other
3907 q
->CNAMEReferrals
= c
;
3908 mDNS_StopQuery_internal(m
, q
); // Stop old query
3909 AssignDomainName(&q
->qname
, &rr
->resrec
.rdata
->u
.name
); // Update qname
3910 q
->qnamehash
= DomainNameHashValue(&q
->qname
); // and namehash
3911 mDNS_StartQuery_internal(m
, q
); // start new query
3912 q
->CNAMEReferrals
= c
; // and keep count of how many times we've done this
3916 mDNSlocal
void CacheRecordDeferredAdd(mDNS
*const m
, CacheRecord
*rr
)
3918 rr
->DelayDelivery
= 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3919 if (m
->CurrentQuestion
)
3920 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3921 m
->CurrentQuestion
= m
->Questions
;
3922 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3924 DNSQuestion
*q
= m
->CurrentQuestion
;
3925 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3926 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3927 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3928 m
->CurrentQuestion
= q
->next
;
3930 m
->CurrentQuestion
= mDNSNULL
;
3933 mDNSlocal mDNSs32
CheckForSoonToExpireRecords(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const mDNSu32 slot
)
3935 const mDNSs32 threshhold
= m
->timenow
+ mDNSPlatformOneSecond
; // See if there are any records expiring within one second
3936 const mDNSs32 start
= m
->timenow
- 0x10000000;
3937 mDNSs32 delay
= start
;
3938 CacheGroup
*cg
= CacheGroupForName(m
, slot
, namehash
, name
);
3939 const CacheRecord
*rr
;
3940 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
3941 if (threshhold
- RRExpireTime(rr
) >= 0) // If we have records about to expire within a second
3942 if (delay
- RRExpireTime(rr
) < 0) // then delay until after they've been deleted
3943 delay
= RRExpireTime(rr
);
3944 if (delay
- start
> 0) return(NonZeroTime(delay
));
3948 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3949 // If new questions are created as a result of invoking client callbacks, they will be added to
3950 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3951 // rr is a new CacheRecord just received into our cache
3952 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3953 // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3954 // which may change the record list and/or question list.
3955 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3956 mDNSlocal
void CacheRecordAdd(mDNS
*const m
, CacheRecord
*rr
)
3960 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3961 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3962 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3964 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3966 // If this question is one that's actively sending queries, and it's received ten answers within one
3967 // second of sending the last query packet, then that indicates some radical network topology change,
3968 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
3969 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
3970 // because we will anyway send another query within a few seconds. The first reset query is sent out
3971 // randomized over the next four seconds to reduce possible synchronization between machines.
3972 if (q
->LastAnswerPktNum
!= m
->PktNum
)
3974 q
->LastAnswerPktNum
= m
->PktNum
;
3975 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
) && ++q
->RecentAnswerPkts
>= 10 &&
3976 q
->ThisQInterval
> InitialQuestionInterval
* QuestionIntervalStep3
&& m
->timenow
- q
->LastQTxTime
< mDNSPlatformOneSecond
)
3978 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
3979 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->RecentAnswerPkts
, q
->ThisQInterval
);
3980 q
->LastQTime
= m
->timenow
- InitialQuestionInterval
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*4);
3981 q
->ThisQInterval
= InitialQuestionInterval
;
3982 SetNextQueryTime(m
,q
);
3985 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
3986 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->resrec
.rroriginalttl
);
3987 q
->CurrentAnswers
++;
3988 q
->unansweredQueries
= 0;
3989 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
3990 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
3991 if (q
->CurrentAnswers
> 4000)
3993 static int msgcount
= 0;
3994 if (msgcount
++ < 10)
3995 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
3996 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->CurrentAnswers
);
3997 rr
->resrec
.rroriginalttl
= 0;
3998 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4003 if (!rr
->DelayDelivery
)
4005 if (m
->CurrentQuestion
)
4006 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4007 m
->CurrentQuestion
= m
->Questions
;
4008 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
4010 q
= m
->CurrentQuestion
;
4011 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4012 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
4013 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4014 m
->CurrentQuestion
= q
->next
;
4016 m
->CurrentQuestion
= mDNSNULL
;
4019 SetNextCacheCheckTime(m
, rr
);
4022 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4023 // If new questions are created as a result of invoking client callbacks, they will be added to
4024 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4025 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4026 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4027 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4028 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4029 // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4030 // which may change the record list and/or question list.
4031 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4032 mDNSlocal
void NoCacheAnswer(mDNS
*const m
, CacheRecord
*rr
)
4034 LogMsg("No cache space: Delivering non-cached result for %##s", m
->rec
.r
.resrec
.name
->c
);
4035 if (m
->CurrentQuestion
)
4036 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4037 m
->CurrentQuestion
= m
->Questions
;
4038 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
4039 // since we're not caching the record and we'll get no opportunity to do this later
4040 while (m
->CurrentQuestion
)
4042 DNSQuestion
*q
= m
->CurrentQuestion
;
4043 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4044 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_addnocache
); // QC_addnocache means "don't expect remove events for this"
4045 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4046 m
->CurrentQuestion
= q
->next
;
4048 m
->CurrentQuestion
= mDNSNULL
;
4051 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
4052 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
4053 // If new questions are created as a result of invoking client callbacks, they will be added to
4054 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4055 // rr is an existing cache CacheRecord that just expired and is being deleted
4056 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4057 // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4058 // which may change the record list and/or question list.
4059 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4060 mDNSlocal
void CacheRecordRmv(mDNS
*const m
, CacheRecord
*rr
)
4062 if (m
->CurrentQuestion
)
4063 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4064 m
->CurrentQuestion
= m
->Questions
;
4066 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
4067 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
4068 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
4070 DNSQuestion
*q
= m
->CurrentQuestion
;
4071 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4073 verbosedebugf("CacheRecordRmv %p %s", rr
, CRDisplayString(m
, rr
));
4074 q
->FlappingInterface1
= mDNSNULL
;
4075 q
->FlappingInterface2
= mDNSNULL
;
4076 if (q
->CurrentAnswers
== 0)
4077 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4078 q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4081 q
->CurrentAnswers
--;
4082 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
--;
4083 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
--;
4085 if (rr
->resrec
.rdata
->MaxRDLength
) // Never generate "remove" events for negative results
4087 if (q
->CurrentAnswers
== 0)
4089 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
4090 q
->qname
.c
, DNSTypeName(q
->qtype
));
4091 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
4093 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_rmv
);
4096 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4097 m
->CurrentQuestion
= q
->next
;
4099 m
->CurrentQuestion
= mDNSNULL
;
4102 mDNSlocal
void ReleaseCacheEntity(mDNS
*const m
, CacheEntity
*e
)
4104 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4106 for (i
=0; i
<sizeof(*e
); i
++) ((char*)e
)[i
] = 0xFF;
4108 e
->next
= m
->rrcache_free
;
4109 m
->rrcache_free
= e
;
4110 m
->rrcache_totalused
--;
4113 mDNSlocal
void ReleaseCacheGroup(mDNS
*const m
, CacheGroup
**cp
)
4115 CacheEntity
*e
= (CacheEntity
*)(*cp
);
4116 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4117 if ((*cp
)->rrcache_tail
!= &(*cp
)->members
)
4118 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4119 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
4120 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4121 if ((*cp
)->name
!= (domainname
*)((*cp
)->namestorage
)) mDNSPlatformMemFree((*cp
)->name
);
4122 (*cp
)->name
= mDNSNULL
;
4123 *cp
= (*cp
)->next
; // Cut record from list
4124 ReleaseCacheEntity(m
, e
);
4127 mDNSlocal
void ReleaseCacheRecord(mDNS
*const m
, CacheRecord
*r
)
4129 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
4130 if (r
->resrec
.rdata
&& r
->resrec
.rdata
!= (RData
*)&r
->smallrdatastorage
) mDNSPlatformMemFree(r
->resrec
.rdata
);
4131 r
->resrec
.rdata
= mDNSNULL
;
4132 ReleaseCacheEntity(m
, (CacheEntity
*)r
);
4135 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4136 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4137 // callbacks for old records are delivered before callbacks for newer records.
4138 mDNSlocal
void CheckCacheExpiration(mDNS
*const m
, CacheGroup
*const cg
)
4140 CacheRecord
**rp
= &cg
->members
;
4142 if (m
->lock_rrcache
) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4143 m
->lock_rrcache
= 1;
4147 CacheRecord
*const rr
= *rp
;
4148 mDNSs32 event
= RRExpireTime(rr
);
4149 if (m
->timenow
- event
>= 0) // If expired, delete it
4151 *rp
= rr
->next
; // Cut it from the list
4152 verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
4153 m
->timenow
- rr
->TimeRcvd
, rr
->resrec
.rroriginalttl
, rr
->CRActiveQuestion
, CRDisplayString(m
, rr
));
4154 if (rr
->CRActiveQuestion
) // If this record has one or more active questions, tell them it's going away
4156 CacheRecordRmv(m
, rr
);
4157 m
->rrcache_active
--;
4159 ReleaseCacheRecord(m
, rr
);
4161 else // else, not expired; see if we need to query
4163 if (rr
->DelayDelivery
&& rr
->DelayDelivery
- m
->timenow
> 0)
4164 event
= rr
->DelayDelivery
;
4167 if (rr
->DelayDelivery
) CacheRecordDeferredAdd(m
, rr
);
4168 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
4170 if (m
->timenow
- rr
->NextRequiredQuery
< 0) // If not yet time for next query
4171 event
= rr
->NextRequiredQuery
; // then just record when we want the next query
4172 else // else trigger our question to go out now
4174 // Set NextScheduledQuery to timenow so that SendQueries() will run.
4175 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
4176 m
->NextScheduledQuery
= m
->timenow
;
4177 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4178 // which will correctly update m->NextCacheCheck for us.
4179 event
= m
->timenow
+ 0x3FFFFFFF;
4183 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4184 (event
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
), CRDisplayString(m
, rr
));
4185 if (m
->NextCacheCheck
- (event
+ CacheCheckGracePeriod(rr
)) > 0)
4186 m
->NextCacheCheck
= (event
+ CacheCheckGracePeriod(rr
));
4190 if (cg
->rrcache_tail
!= rp
) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg
->rrcache_tail
, rp
);
4191 cg
->rrcache_tail
= rp
;
4192 m
->lock_rrcache
= 0;
4195 mDNSlocal
void AnswerNewQuestion(mDNS
*const m
)
4197 mDNSBool ShouldQueryImmediately
= mDNStrue
;
4198 DNSQuestion
*q
= m
->NewQuestions
; // Grab the question we're going to answer
4199 const mDNSu32 slot
= HashSlot(&q
->qname
);
4200 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4202 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4204 if (cg
) CheckCacheExpiration(m
, cg
);
4205 m
->NewQuestions
= q
->next
; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4207 if (m
->lock_rrcache
) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4208 // This should be safe, because calling the client's question callback may cause the
4209 // question list to be modified, but should not ever cause the rrcache list to be modified.
4210 // If the client's question callback deletes the question, then m->CurrentQuestion will
4211 // be advanced, and we'll exit out of the loop
4212 m
->lock_rrcache
= 1;
4213 if (m
->CurrentQuestion
)
4214 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4215 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4217 if (q
->NoAnswer
== NoAnswer_Fail
)
4219 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4220 MakeNegativeCacheRecord(m
, &m
->rec
.r
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60, mDNSInterface_Any
);
4221 q
->NoAnswer
= NoAnswer_Normal
; // Temporarily turn off answer suppression
4222 AnswerCurrentQuestionWithResourceRecord(m
, &m
->rec
.r
, QC_addnocache
);
4223 q
->NoAnswer
= NoAnswer_Fail
; // Restore NoAnswer state
4224 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4227 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4228 if (m
->CurrentQuestion
== q
&& q
->InterfaceID
== mDNSInterface_Any
)
4230 if (m
->CurrentRecord
)
4231 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4232 m
->CurrentRecord
= m
->ResourceRecords
;
4233 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4235 AuthRecord
*rr
= m
->CurrentRecord
;
4236 m
->CurrentRecord
= rr
->next
;
4237 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
4238 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4240 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4241 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4244 m
->CurrentRecord
= mDNSNULL
;
4247 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
4249 if (m
->CurrentQuestion
== q
)
4252 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4253 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
))
4255 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
4256 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- rr
->TimeRcvd
)) / mDNSPlatformOneSecond
;
4257 if (rr
->resrec
.rroriginalttl
<= SecsSinceRcvd
)
4259 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
4260 rr
->resrec
.rroriginalttl
, SecsSinceRcvd
, CRDisplayString(m
, rr
), m
->timenow
, rr
->TimeRcvd
);
4261 continue; // Go to next one in loop
4264 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
4265 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4266 if ((rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) || (q
->ExpectUnique
))
4267 ShouldQueryImmediately
= mDNSfalse
;
4268 q
->CurrentAnswers
++;
4269 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
4270 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
4271 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
4272 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4274 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
) && RRTypeIsAddressType(q
->qtype
))
4275 ShouldQueryImmediately
= mDNSfalse
;
4278 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving cache answers");
4280 if (m
->CurrentQuestion
== q
&& ShouldQueryImmediately
&& ActiveQuestion(q
))
4282 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4283 q
->ThisQInterval
= InitialQuestionInterval
;
4284 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4285 if (mDNSOpaque16IsZero(q
->TargetQID
)) // For mDNS, spread packets to avoid a burst of simultaneous queries
4287 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
4288 if (!m
->RandomQueryDelay
)
4289 m
->RandomQueryDelay
= (mDNSPlatformOneSecond
+ mDNSRandom(mDNSPlatformOneSecond
*5) - 1) / 50 + 1;
4290 q
->LastQTime
+= m
->RandomQueryDelay
;
4293 if (m
->NextScheduledQuery
- (q
->LastQTime
+ q
->ThisQInterval
) > 0)
4294 m
->NextScheduledQuery
= (q
->LastQTime
+ q
->ThisQInterval
);
4297 m
->CurrentQuestion
= mDNSNULL
;
4298 m
->lock_rrcache
= 0;
4301 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4302 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
4303 mDNSlocal
void AnswerNewLocalOnlyQuestion(mDNS
*const m
)
4305 DNSQuestion
*q
= m
->NewLocalOnlyQuestions
; // Grab the question we're going to answer
4306 m
->NewLocalOnlyQuestions
= q
->next
; // Advance NewLocalOnlyQuestions to the next (if any)
4308 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4310 if (m
->CurrentQuestion
)
4311 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4312 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4314 if (m
->CurrentRecord
)
4315 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4316 m
->CurrentRecord
= m
->ResourceRecords
;
4318 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4320 AuthRecord
*rr
= m
->CurrentRecord
;
4321 m
->CurrentRecord
= rr
->next
;
4322 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4324 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4325 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4329 m
->CurrentQuestion
= mDNSNULL
;
4330 m
->CurrentRecord
= mDNSNULL
;
4333 mDNSlocal CacheEntity
*GetCacheEntity(mDNS
*const m
, const CacheGroup
*const PreserveCG
)
4335 CacheEntity
*e
= mDNSNULL
;
4337 if (m
->lock_rrcache
) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL
); }
4338 m
->lock_rrcache
= 1;
4340 // If we have no free records, ask the client layer to give us some more memory
4341 if (!m
->rrcache_free
&& m
->MainCallback
)
4343 if (m
->rrcache_totalused
!= m
->rrcache_size
)
4344 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4345 m
->rrcache_totalused
, m
->rrcache_size
);
4347 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4348 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4349 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4350 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
4351 // and recycle them, instead of allocating more memory.
4352 if (m
->rrcache_size
> 5000 && m
->rrcache_size
/ 32 > m
->rrcache_active
)
4353 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4354 m
->rrcache_size
, m
->rrcache_active
);
4357 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4358 m
->MainCallback(m
, mStatus_GrowCache
);
4359 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4363 // If we still have no free records, recycle all the records we can.
4364 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4365 if (!m
->rrcache_free
)
4367 mDNSu32 oldtotalused
= m
->rrcache_totalused
;
4369 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4371 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4374 CacheRecord
**rp
= &(*cp
)->members
;
4377 // Records that answer still-active questions are not candidates for recycling
4378 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4379 if ((*rp
)->CRActiveQuestion
|| (*rp
)->NextInCFList
)
4383 CacheRecord
*rr
= *rp
;
4384 *rp
= (*rp
)->next
; // Cut record from list
4385 ReleaseCacheRecord(m
, rr
);
4388 if ((*cp
)->rrcache_tail
!= rp
)
4389 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot
, (*cp
)->rrcache_tail
, rp
);
4390 (*cp
)->rrcache_tail
= rp
;
4391 if ((*cp
)->members
|| (*cp
)==PreserveCG
) cp
=&(*cp
)->next
;
4392 else ReleaseCacheGroup(m
, cp
);
4395 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4396 oldtotalused
- m
->rrcache_totalused
, oldtotalused
, m
->rrcache_totalused
);
4399 if (m
->rrcache_free
) // If there are records in the free list, take one
4401 e
= m
->rrcache_free
;
4402 m
->rrcache_free
= e
->next
;
4403 if (++m
->rrcache_totalused
>= m
->rrcache_report
)
4405 LogInfo("RR Cache now using %ld objects", m
->rrcache_totalused
);
4406 if (m
->rrcache_report
< 100) m
->rrcache_report
+= 10;
4407 else if (m
->rrcache_report
< 1000) m
->rrcache_report
+= 100;
4408 else m
->rrcache_report
+= 1000;
4410 mDNSPlatformMemZero(e
, sizeof(*e
));
4413 m
->lock_rrcache
= 0;
4418 mDNSlocal CacheRecord
*GetCacheRecord(mDNS
*const m
, CacheGroup
*cg
, mDNSu16 RDLength
)
4420 CacheRecord
*r
= (CacheRecord
*)GetCacheEntity(m
, cg
);
4423 r
->resrec
.rdata
= (RData
*)&r
->smallrdatastorage
; // By default, assume we're usually going to be using local storage
4424 if (RDLength
> InlineCacheRDSize
) // If RDLength is too big, allocate extra storage
4426 r
->resrec
.rdata
= (RData
*)mDNSPlatformMemAllocate(sizeofRDataHeader
+ RDLength
);
4427 if (r
->resrec
.rdata
) r
->resrec
.rdata
->MaxRDLength
= r
->resrec
.rdlength
= RDLength
;
4428 else { ReleaseCacheEntity(m
, (CacheEntity
*)r
); r
= mDNSNULL
; }
4434 mDNSlocal CacheGroup
*GetCacheGroup(mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
4436 mDNSu16 namelen
= DomainNameLength(rr
->name
);
4437 CacheGroup
*cg
= (CacheGroup
*)GetCacheEntity(m
, mDNSNULL
);
4438 if (!cg
) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr
->name
->c
); return(mDNSNULL
); }
4439 cg
->next
= m
->rrcache_hash
[slot
];
4440 cg
->namehash
= rr
->namehash
;
4441 cg
->members
= mDNSNULL
;
4442 cg
->rrcache_tail
= &cg
->members
;
4443 cg
->name
= (domainname
*)cg
->namestorage
;
4444 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4445 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4446 if (namelen
> InlineCacheGroupNameSize
) cg
->name
= mDNSPlatformMemAllocate(namelen
);
4449 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr
->name
->c
);
4450 ReleaseCacheEntity(m
, (CacheEntity
*)cg
);
4453 AssignDomainName(cg
->name
, rr
->name
);
4455 if (CacheGroupForRecord(m
, slot
, rr
)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr
->name
->c
);
4456 m
->rrcache_hash
[slot
] = cg
;
4457 if (CacheGroupForRecord(m
, slot
, rr
) != cg
) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr
->name
->c
);
4462 mDNSexport
void mDNS_PurgeCacheResourceRecord(mDNS
*const m
, CacheRecord
*rr
)
4464 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4465 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4466 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4467 // a positive answer using an expired record (e.g. from an interface that has gone away).
4468 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4469 // summary deletion without giving the proper callback to any questions that are monitoring it.
4470 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4471 rr
->TimeRcvd
= m
->timenow
- mDNSPlatformOneSecond
* 60;
4472 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4473 rr
->resrec
.rroriginalttl
= 0;
4474 SetNextCacheCheckTime(m
, rr
);
4477 mDNSexport mDNSs32
mDNS_TimeNow(const mDNS
*const m
)
4480 mDNSPlatformLock(m
);
4483 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4484 if (!m
->timenow
) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
4487 if (m
->timenow
) time
= m
->timenow
;
4488 else time
= mDNS_TimeNow_NoLock(m
);
4489 mDNSPlatformUnlock(m
);
4493 // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4494 // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4495 // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4496 #define SetSPSProxyListChanged(X) do { \
4497 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4498 m->SPSProxyListChanged = (X); } while(0)
4500 // Called from mDNS_Execute() to expire stale proxy records
4501 mDNSlocal
void CheckProxyRecords(mDNS
*const m
, AuthRecord
*list
)
4503 m
->CurrentRecord
= list
;
4504 while (m
->CurrentRecord
)
4506 AuthRecord
*rr
= m
->CurrentRecord
;
4507 if (rr
->WakeUp
.HMAC
.l
[0])
4509 if (m
->timenow
- rr
->TimeExpire
< 0) // If proxy record not expired yet, update m->NextScheduledSPS
4511 if (m
->NextScheduledSPS
- rr
->TimeExpire
> 0)
4512 m
->NextScheduledSPS
= rr
->TimeExpire
;
4514 else // else proxy record expired, so remove it
4516 LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4517 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, ARDisplayString(m
, rr
));
4518 SetSPSProxyListChanged(rr
->resrec
.InterfaceID
);
4519 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
4520 // Don't touch rr after this -- memory may have been free'd
4523 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
4524 // because the list may have been changed in that call.
4525 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
4526 m
->CurrentRecord
= rr
->next
;
4530 mDNSexport mDNSs32
mDNS_Execute(mDNS
*const m
)
4532 mDNS_Lock(m
); // Must grab lock before trying to read m->timenow
4534 if (m
->timenow
- m
->NextScheduledEvent
>= 0)
4538 verbosedebugf("mDNS_Execute");
4539 if (m
->CurrentQuestion
)
4540 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4542 // 1. If we're past the probe suppression time, we can clear it
4543 if (m
->SuppressProbes
&& m
->timenow
- m
->SuppressProbes
>= 0) m
->SuppressProbes
= 0;
4545 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4546 if (m
->NumFailedProbes
&& m
->timenow
- m
->ProbeFailTime
>= mDNSPlatformOneSecond
* 10) m
->NumFailedProbes
= 0;
4548 // 3. Purge our cache of stale old records
4549 if (m
->rrcache_size
&& m
->timenow
- m
->NextCacheCheck
>= 0)
4552 m
->NextCacheCheck
= m
->timenow
+ 0x3FFFFFFF;
4553 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4555 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4558 CheckCacheExpiration(m
, *cp
);
4559 if ((*cp
)->members
) cp
=&(*cp
)->next
;
4560 else ReleaseCacheGroup(m
, cp
);
4565 if (m
->timenow
- m
->NextScheduledSPS
>= 0)
4567 m
->NextScheduledSPS
= m
->timenow
+ 0x3FFFFFFF;
4568 CheckProxyRecords(m
, m
->DuplicateRecords
); // Clear m->DuplicateRecords first, then m->ResourceRecords
4569 CheckProxyRecords(m
, m
->ResourceRecords
);
4572 SetSPSProxyListChanged(mDNSNULL
); // Perform any deferred BPF reconfiguration now
4574 if (m
->DelaySleep
&& m
->timenow
- m
->DelaySleep
>= 0)
4577 if (m
->SleepState
== SleepState_Transferring
)
4579 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4580 BeginSleepProcessing(m
);
4584 // 4. See if we can answer any of our new local questions from the cache
4585 for (i
=0; m
->NewQuestions
&& i
<1000; i
++)
4587 if (m
->NewQuestions
->DelayAnswering
&& m
->timenow
- m
->NewQuestions
->DelayAnswering
< 0) break;
4588 AnswerNewQuestion(m
);
4590 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4592 for (i
=0; m
->NewLocalOnlyQuestions
&& i
<1000; i
++) AnswerNewLocalOnlyQuestion(m
);
4593 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4595 for (i
=0; i
<1000 && m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
); i
++)
4597 AuthRecord
*rr
= m
->NewLocalRecords
;
4598 m
->NewLocalRecords
= m
->NewLocalRecords
->next
;
4599 AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNStrue
);
4601 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4603 // 5. See what packets we need to send
4604 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| (m
->SleepState
== SleepState_Sleeping
))
4605 DiscardDeregistrations(m
);
4606 if (m
->mDNSPlatformStatus
== mStatus_NoError
&& (m
->SuppressSending
== 0 || m
->timenow
- m
->SuppressSending
>= 0))
4608 // If the platform code is ready, and we're not suppressing packet generation right now
4609 // then send our responses, probes, and questions.
4610 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4611 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4612 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4613 // Finally, we send responses, including the previously mentioned records that just completed probing.
4614 m
->SuppressSending
= 0;
4616 // 6. Send Query packets. This may cause some probing records to advance to announcing state
4617 if (m
->timenow
- m
->NextScheduledQuery
>= 0 || m
->timenow
- m
->NextScheduledProbe
>= 0) SendQueries(m
);
4618 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
4621 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4622 m
->timenow
, m
->NextScheduledQuery
, m
->timenow
- m
->NextScheduledQuery
);
4623 m
->NextScheduledQuery
= m
->timenow
+ mDNSPlatformOneSecond
;
4624 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
4625 if (ActiveQuestion(q
) && q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
<= 0)
4626 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4628 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
4630 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4631 m
->timenow
, m
->NextScheduledProbe
, m
->timenow
- m
->NextScheduledProbe
);
4632 m
->NextScheduledProbe
= m
->timenow
+ mDNSPlatformOneSecond
;
4635 // 7. Send Response packets, including probing records just advanced to announcing state
4636 if (m
->timenow
- m
->NextScheduledResponse
>= 0) SendResponses(m
);
4637 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
4639 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4640 m
->NextScheduledResponse
= m
->timenow
+ mDNSPlatformOneSecond
;
4644 // Clear RandomDelay values, ready to pick a new different value next time
4645 m
->RandomQueryDelay
= 0;
4646 m
->RandomReconfirmDelay
= 0;
4649 // Note about multi-threaded systems:
4650 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4651 // performing mDNS API operations that change our next scheduled event time.
4653 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4654 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4655 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4656 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4657 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4658 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4659 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4660 // without blocking. This avoids the race condition between the signal from the other thread arriving
4661 // just *before* or just *after* the main thread enters the blocking primitive.
4663 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4664 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4665 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4666 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4667 // by the time it gets to the timer callback function).
4669 #ifndef UNICAST_DISABLED
4672 mDNS_Unlock(m
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4673 return(m
->NextScheduledEvent
);
4676 mDNSlocal
void SuspendLLQs(mDNS
*m
)
4679 for (q
= m
->Questions
; q
; q
= q
->next
)
4680 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->state
== LLQ_Established
)
4681 { q
->ReqLease
= 0; sendLLQRefresh(m
, q
); }
4684 // ActivateUnicastQuery() is called from three places:
4685 // 1. When a new question is created
4686 // 2. On wake from sleep
4687 // 3. When the DNS configuration changes
4688 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4689 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4690 mDNSlocal
void ActivateUnicastQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool ScheduleImmediately
)
4692 // For now this AutoTunnel stuff is specific to Mac OS X.
4693 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4694 #if APPLE_OSX_mDNSResponder
4695 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4696 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4697 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4698 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4699 // returns results for both at the same time.
4700 if (RRTypeIsAddressType(question
->qtype
) && question
->AuthInfo
&& question
->AuthInfo
->AutoTunnel
&& question
->QuestionCallback
!= AutoTunnelCallback
)
4702 question
->NoAnswer
= NoAnswer_Suspended
;
4703 AddNewClientTunnel(m
, question
);
4706 #endif // APPLE_OSX_mDNSResponder
4708 if (!question
->DuplicateOf
)
4710 debugf("ActivateUnicastQuery: %##s %s%s%s",
4711 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->AuthInfo
? " (Private)" : "", ScheduleImmediately
? " ScheduleImmediately" : "");
4712 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
4713 if (question
->LongLived
)
4715 question
->state
= LLQ_InitialRequest
;
4716 question
->id
= zeroOpaque64
;
4717 question
->servPort
= zeroIPPort
;
4718 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
4720 if (ScheduleImmediately
)
4722 question
->ThisQInterval
= InitialQuestionInterval
;
4723 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
4724 SetNextQueryTime(m
, question
);
4729 mDNSexport
void mDNSCoreRestartQueries(mDNS
*const m
)
4733 #ifndef UNICAST_DISABLED
4734 // Retrigger all our uDNS questions
4735 if (m
->CurrentQuestion
)
4736 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4737 m
->CurrentQuestion
= m
->Questions
;
4738 while (m
->CurrentQuestion
)
4740 q
= m
->CurrentQuestion
;
4741 m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
4742 if (!mDNSOpaque16IsZero(q
->TargetQID
)) ActivateUnicastQuery(m
, q
, mDNStrue
);
4746 // Retrigger all our mDNS questions
4747 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
4748 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
))
4750 q
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
4751 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
4752 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4753 q
->RecentAnswerPkts
= 0;
4754 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
);
4755 m
->NextScheduledQuery
= m
->timenow
;
4759 // ***************************************************************************
4760 #if COMPILER_LIKES_PRAGMA_MARK
4762 #pragma mark - Power Management (Sleep/Wake)
4765 mDNSlocal
void SendSPSRegistration(mDNS
*const m
, NetworkInterfaceInfo
*intf
, const mDNSOpaque16 id
)
4767 const int ownerspace
= mDNSSameEthAddress(&m
->PrimaryMAC
, &intf
->MAC
) ? DNSOpt_OwnerData_ID_Space
: DNSOpt_OwnerData_ID_Wake_Space
;
4768 const int optspace
= DNSOpt_Header_Space
+ DNSOpt_LeaseData_Space
+ ownerspace
;
4769 const int sps
= intf
->NextSPSAttempt
/ 3;
4772 if (!intf
->SPSAddr
[sps
].type
)
4774 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
4775 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
4776 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
4777 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf
->ifname
, intf
->NextSPSAttempt
, sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4781 // Mark our mDNS records (not unicast records) for transfer to SPS
4782 if (mDNSOpaque16IsZero(id
))
4783 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4784 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4785 if (rr
->resrec
.InterfaceID
== intf
->InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
4786 rr
->SendRNow
= mDNSInterfaceMark
; // mark it now
4790 mDNSu8
*p
= m
->omsg
.data
;
4791 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4792 // For now we follow that same logic for SPS registrations too.
4793 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4794 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4795 InitializeDNSMessage(&m
->omsg
.h
, mDNSOpaque16IsZero(id
) ? mDNS_NewMessageID(m
) : id
, UpdateReqFlags
);
4797 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4798 if (rr
->SendRNow
|| (!mDNSOpaque16IsZero(id
) && !AuthRecord_uDNS(rr
) && mDNSSameOpaque16(rr
->updateid
, id
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0))
4801 const mDNSu8
*const limit
= m
->omsg
.data
+ (m
->omsg
.h
.mDNS_numUpdates
? NormalMaxDNSMessageData
: AbsoluteMaxDNSMessageData
) - optspace
;
4802 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
4803 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
4804 newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
4805 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
4807 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf
->ifname
, p
- m
->omsg
.data
, limit
- m
->omsg
.data
, ARDisplayString(m
, rr
));
4810 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, rr
));
4811 rr
->SendRNow
= mDNSNULL
;
4812 rr
->ThisAPInterval
= mDNSPlatformOneSecond
;
4813 rr
->LastAPTime
= m
->timenow
;
4814 rr
->updateid
= m
->omsg
.h
.id
;
4815 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4816 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4821 if (!m
->omsg
.h
.mDNS_numUpdates
) break;
4825 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
4826 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
4827 opt
.resrec
.rdlength
= sizeof(rdataOPT
) * 2; // Two options in this OPT record
4828 opt
.resrec
.rdestimate
= sizeof(rdataOPT
) * 2;
4829 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
4830 opt
.resrec
.rdata
->u
.opt
[0].optlen
= DNSOpt_LeaseData_Space
- 4;
4831 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= DEFAULT_UPDATE_LEASE
;
4832 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[1]);
4833 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, &opt
));
4834 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
4836 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m
->omsg
.h
.mDNS_numUpdates
, ARDisplayString(m
, &opt
));
4840 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf
->ifname
, intf
->NextSPSAttempt
, sps
,
4841 mDNSVal16(m
->omsg
.h
.id
), m
->omsg
.h
.mDNS_numUpdates
, p
- m
->omsg
.data
, &intf
->SPSAddr
[sps
], mDNSVal16(intf
->SPSPort
[sps
]));
4842 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
4843 err
= mDNSSendDNSMessage(m
, &m
->omsg
, p
, intf
->InterfaceID
, mDNSNULL
, &intf
->SPSAddr
[sps
], intf
->SPSPort
[sps
], mDNSNULL
, mDNSNULL
);
4844 if (err
) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err
);
4845 if (err
&& intf
->SPSAddr
[sps
].type
== mDNSAddrType_IPv6
&& intf
->NetWakeResolve
[sps
].ThisQInterval
== -1)
4847 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4848 intf
->NetWakeResolve
[sps
].qtype
= kDNSType_A
;
4849 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[sps
]);
4856 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
* 10; // If successful, update NextSPSAttemptTime
4859 if (mDNSOpaque16IsZero(id
) && intf
->NextSPSAttempt
< 8) intf
->NextSPSAttempt
++;
4862 // RetrySPSRegistrations is called from SendResponses, with the lock held
4863 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
)
4866 NetworkInterfaceInfo
*intf
;
4868 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4869 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4870 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10)
4871 intf
->NextSPSAttemptTime
++;
4873 // Retry any record registrations that are due
4874 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4875 if (!AuthRecord_uDNS(rr
) && !mDNSOpaque16IsZero(rr
->updateid
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4876 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4877 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== intf
->InterfaceID
)
4879 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m
, rr
));
4880 SendSPSRegistration(m
, intf
, rr
->updateid
);
4883 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4884 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4885 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10 && intf
->NextSPSAttempt
< 8)
4886 intf
->NextSPSAttempt
++;
4889 mDNSlocal
void NetWakeResolve(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4891 NetworkInterfaceInfo
*intf
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
4892 int sps
= question
- intf
->NetWakeResolve
;
4894 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps
, AddRecord
, RRDisplayString(m
, answer
));
4896 if (!AddRecord
) return; // Don't care about REMOVE events
4897 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
4899 // if (answer->rrtype == kDNSType_AAAA) return; // To test failing to resolve sleep proxy's address
4901 mDNS_StopQuery(m
, question
);
4902 question
->ThisQInterval
= -1;
4904 if (answer
->rrtype
== kDNSType_SRV
)
4906 intf
->SPSPort
[sps
] = answer
->rdata
->u
.srv
.port
;
4907 AssignDomainName(&question
->qname
, &answer
->rdata
->u
.srv
.target
);
4908 question
->qtype
= kDNSType_AAAA
;
4909 mDNS_StartQuery(m
, question
);
4911 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== sizeof(mDNSv6Addr
) && mDNSv6AddressIsLinkLocal(&answer
->rdata
->u
.ipv6
))
4913 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv6
;
4914 intf
->SPSAddr
[sps
].ip
.v6
= answer
->rdata
->u
.ipv6
;
4916 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4919 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== 0) // If negative answer for IPv6, look for IPv4 addresses instead
4921 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps
, question
->qname
.c
);
4922 question
->qtype
= kDNSType_A
;
4923 mDNS_StartQuery(m
, question
);
4925 else if (answer
->rrtype
== kDNSType_A
&& answer
->rdlength
== sizeof(mDNSv4Addr
))
4927 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv4
;
4928 intf
->SPSAddr
[sps
].ip
.v4
= answer
->rdata
->u
.ipv4
;
4930 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4935 mDNSexport mDNSBool
mDNSCoreHaveAdvertisedMulticastServices(mDNS
*const m
)
4938 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4939 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& !AuthRecord_uDNS(rr
) && !mDNSSameIPPort(rr
->resrec
.rdata
->u
.srv
.port
, DiscardPort
))
4944 mDNSlocal
void SendSleepGoodbyes(mDNS
*const m
)
4947 m
->SleepState
= SleepState_Sleeping
;
4949 #ifndef UNICAST_DISABLED
4950 SleepServiceRegistrations(m
);
4951 SleepRecordRegistrations(m
); // If we have no SPS, need to deregister our uDNS records
4954 // Mark all the records we need to deregister and send them
4955 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4956 if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->RequireGoodbye
)
4957 rr
->ImmedAnswer
= mDNSInterfaceMark
;
4961 // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
4962 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
)
4964 mDNSBool SendGoodbyes
= mDNStrue
;
4965 const CacheRecord
*sps
[3] = { mDNSNULL
};
4967 m
->NextScheduledSPRetry
= m
->timenow
;
4969 if (!m
->SystemWakeOnLANEnabled
) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
4970 else if (!mDNSCoreHaveAdvertisedMulticastServices(m
)) LogSPS("BeginSleepProcessing: No advertised services");
4971 else // If we have at least one advertised service
4973 NetworkInterfaceInfo
*intf
;
4974 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4976 if (!intf
->NetWake
) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf
->ifname
);
4977 #if APPLE_OSX_mDNSResponder
4978 else if (ActivateLocalProxy(m
, intf
->ifname
) == mStatus_NoError
)
4980 SendGoodbyes
= mDNSfalse
;
4981 LogSPS("BeginSleepProcessing: %-6s using local proxy", intf
->ifname
);
4982 // This will leave m->SleepState set to SleepState_Transferring,
4983 // which is okay because with no outstanding resolves, or updates in flight,
4984 // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
4986 #endif // APPLE_OSX_mDNSResponder
4989 FindSPSInCache(m
, &intf
->NetWakeBrowse
, sps
);
4990 if (!sps
[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf
->ifname
, &intf
->ip
, intf
->NetWakeBrowse
.ThisQInterval
);
4994 SendGoodbyes
= mDNSfalse
;
4995 intf
->NextSPSAttempt
= 0;
4996 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
4997 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
5001 if (intf
->SPSAddr
[i
].type
)
5002 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf
->ifname
, i
, intf
->SPSAddr
[i
].type
); *(long*)0 = 0; }
5003 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0)
5004 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf
->ifname
, i
, intf
->NetWakeResolve
[i
].ThisQInterval
); *(long*)0 = 0; }
5006 intf
->SPSAddr
[i
].type
= mDNSAddrType_None
;
5007 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery(m
, &intf
->NetWakeResolve
[i
]);
5008 intf
->NetWakeResolve
[i
].ThisQInterval
= -1;
5011 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf
->ifname
, i
, sps
[i
]->resrec
.rroriginalttl
, CRDisplayString(m
, sps
[i
]));
5012 mDNS_SetupQuestion(&intf
->NetWakeResolve
[i
], intf
->InterfaceID
, &sps
[i
]->resrec
.rdata
->u
.name
, kDNSType_SRV
, NetWakeResolve
, intf
);
5013 intf
->NetWakeResolve
[i
].ReturnIntermed
= mDNStrue
;
5014 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[i
]);
5022 if (SendGoodbyes
) // If we didn't find even one Sleep Proxy
5024 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
5025 SendSleepGoodbyes(m
);
5029 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
5030 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
5031 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
5032 mDNSexport
void mDNSCoreMachineSleep(mDNS
*const m
, mDNSBool sleep
)
5038 LogSPS("%s (old state %d) at %ld", sleep
? "Sleeping" : "Waking", m
->SleepState
, m
->timenow
);
5040 if (sleep
&& !m
->SleepState
) // Going to sleep
5042 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5045 mDNSu8 oldstate
= m
->SPSState
;
5046 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5048 if (oldstate
== 1) mDNS_DeregisterService(m
, &m
->SPSRecords
);
5049 mDNS_ReclaimLockAfterCallback();
5052 m
->SleepState
= SleepState_Transferring
;
5053 if (m
->SystemWakeOnLANEnabled
&& m
->DelaySleep
)
5055 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5056 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m
->DelaySleep
- m
->timenow
);
5057 m
->SleepLimit
= m
->DelaySleep
+ mDNSPlatformOneSecond
* 10;
5062 m
->SleepLimit
= m
->timenow
+ mDNSPlatformOneSecond
* 10;
5063 BeginSleepProcessing(m
);
5066 #ifndef UNICAST_DISABLED
5069 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m
->SleepState
,
5070 m
->SleepState
== SleepState_Transferring
? "Transferring" :
5071 m
->SleepState
== SleepState_Sleeping
? "Sleeping" : "?", m
->SleepSeqNum
);
5073 else if (!sleep
) // Waking up
5078 NetworkInterfaceInfo
*intf
;
5080 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5081 if (m
->SleepState
!= SleepState_Awake
)
5083 m
->SleepState
= SleepState_Awake
;
5085 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5086 // then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5087 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5088 // before we make our determination of whether there's a Sleep Proxy out there we should register with.
5089 m
->DelaySleep
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 16);
5092 if (m
->SPSState
== 3)
5094 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5096 mDNSCoreBeSleepProxyServer(m
, m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
);
5097 mDNS_ReclaimLockAfterCallback();
5100 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5101 // on wake we go through our record list and clear updateid back to zero
5102 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) rr
->updateid
= zeroID
;
5104 // ... and the same for NextSPSAttempt
5105 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
)) intf
->NextSPSAttempt
= -1;
5107 // Restart unicast and multicast queries
5108 mDNSCoreRestartQueries(m
);
5110 // and reactivtate service registrations
5111 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5112 LogInfo("WakeServiceRegistrations %d %d", m
->timenow
, m
->NextSRVUpdate
);
5114 // 2. Re-validate our cache records
5115 m
->NextCacheCheck
= m
->timenow
;
5116 FORALL_CACHERECORDS(slot
, cg
, cr
)
5117 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForWake
);
5119 // 3. Retrigger probing and announcing for all our authoritative records
5120 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5121 if (AuthRecord_uDNS(rr
))
5123 ActivateUnicastRegistration(m
, rr
);
5127 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
5128 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
5129 rr
->AnnounceCount
= InitialAnnounceCount
;
5130 InitializeLastAPTime(m
, rr
);
5133 // 4. Refresh NAT mappings
5134 // We don't want to have to assume that all hardware can necessarily keep accurate
5135 // track of passage of time while asleep, so on wake we refresh our NAT mappings
5136 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
5137 m
->retryGetAddr
= m
->timenow
;
5138 RecreateNATMappings(m
);
5144 mDNSexport mDNSBool
mDNSCoreReadyForSleep(mDNS
*m
, mDNSs32 now
)
5148 ServiceRecordSet
*srs
;
5149 NetworkInterfaceInfo
*intf
;
5153 if (m
->DelaySleep
) goto notready
;
5155 // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks
5156 if (m
->SleepLimit
- now
> 0 && m
->NextScheduledSPRetry
- now
> 0) goto notready
;
5158 m
->NextScheduledSPRetry
= now
+ 0x40000000UL
;
5160 // See if we might need to retransmit any lost Sleep Proxy Registrations
5161 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5162 if (intf
->NextSPSAttempt
>= 0)
5164 if (now
- intf
->NextSPSAttemptTime
>= 0)
5166 LogSPS("ReadyForSleep retrying SPS %s %d", intf
->ifname
, intf
->NextSPSAttempt
);
5167 SendSPSRegistration(m
, intf
, zeroID
);
5168 // Don't need to "goto notready" here, becase if we do still have record registrations
5169 // that have not been acknowledged yet, we'll catch that in the record list scan below.
5172 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
5173 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
5176 // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
5177 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5178 if (intf
->NetWakeResolve
[0].ThisQInterval
>= 0)
5180 LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf
->ifname
, intf
->NetWakeResolve
[0].qname
.c
, DNSTypeName(intf
->NetWakeResolve
[0].qtype
));
5184 // Scan list of registered records
5185 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5186 if (!AuthRecord_uDNS(rr
))
5187 if (!mDNSOpaque16IsZero(rr
->updateid
))
5188 { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto spsnotready
; }
5190 // Scan list of private LLQs, and make sure they've all completed their handshake with the server
5191 for (q
= m
->Questions
; q
; q
= q
->next
)
5192 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->ReqLease
== 0 && q
->tcp
)
5194 LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5198 // Scan list of registered records
5199 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5200 if (AuthRecord_uDNS(rr
))
5201 if (rr
->state
== regState_Refresh
&& rr
->tcp
)
5202 { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto notready
; }
5204 // Scan list of registered services
5205 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
5206 if (srs
->state
== regState_NoTarget
&& srs
->tcp
) goto notready
;
5213 // If we failed to complete sleep proxy registration within ten seconds, we give up on that
5214 // and allow up to ten seconds more to complete wide-area deregistration instead
5215 if (now
- m
->SleepLimit
>= 0)
5217 LogMsg("Failed to register with SPS, now sending goodbyes");
5219 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5220 if (intf
->NetWakeBrowse
.ThisQInterval
>= 0)
5222 LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", intf
->ifname
, intf
->NetWakeResolve
[0].qname
.c
, DNSTypeName(intf
->NetWakeResolve
[0].qtype
));
5223 mDNS_DeactivateNetWake_internal(m
, intf
);
5226 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5227 if (!AuthRecord_uDNS(rr
))
5228 if (!mDNSOpaque16IsZero(rr
->updateid
))
5230 LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m
, rr
));
5231 rr
->updateid
= zeroID
;
5234 // We'd really like to allow up to ten seconds more here,
5235 // but if we don't respond to the sleep notification within 30 seconds
5236 // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake.
5237 // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds
5238 // more for SPS resolves and record registrations to complete, which puts us at 26 seconds.
5239 // If we allow just one more second to send our goodbyes, that puts us at 27 seconds.
5240 m
->SleepLimit
= now
+ mDNSPlatformOneSecond
* 1;
5242 SendSleepGoodbyes(m
);
5250 mDNSexport mDNSs32
mDNSCoreIntervalToNextWake(mDNS
*const m
, mDNSs32 now
)
5254 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5255 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5256 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5257 // and if that happens we don't want to just give up and go back to sleep and never try again.
5258 mDNSs32 e
= now
+ (120 * 60 * mDNSPlatformOneSecond
); // Sleep for at most 120 minutes
5260 NATTraversalInfo
*nat
;
5261 for (nat
= m
->NATTraversals
; nat
; nat
=nat
->next
)
5262 if (nat
->Protocol
&& nat
->ExpiryTime
&& nat
->ExpiryTime
- now
> mDNSPlatformOneSecond
*4)
5264 mDNSs32 t
= nat
->ExpiryTime
- (nat
->ExpiryTime
- now
) / 10; // Wake up when 90% of the way to the expiry time
5265 if (e
- t
> 0) e
= t
;
5266 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5267 nat
, nat
->Protocol
== NATOp_MapTCP
? "TCP" : "UDP",
5268 mDNSVal16(nat
->IntPort
), mDNSVal16(nat
->ExternalPort
), nat
->Result
,
5269 nat
->retryPortMap
? (nat
->retryPortMap
- now
) / mDNSPlatformOneSecond
: 0,
5270 nat
->retryInterval
/ mDNSPlatformOneSecond
,
5271 nat
->ExpiryTime
? (nat
->ExpiryTime
- now
) / mDNSPlatformOneSecond
: 0,
5272 (t
- now
) / mDNSPlatformOneSecond
);
5275 // This loop checks both the time we need to renew wide-area registrations,
5276 // and the time we need to renew Sleep Proxy registrations
5277 for (ar
= m
->ResourceRecords
; ar
; ar
= ar
->next
)
5278 if (ar
->expire
&& ar
->expire
- now
> mDNSPlatformOneSecond
*4)
5280 mDNSs32 t
= ar
->expire
- (ar
->expire
- now
) / 10; // Wake up when 90% of the way to the expiry time
5281 if (e
- t
> 0) e
= t
;
5282 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5283 ar
, ar
->ThisAPInterval
/ mDNSPlatformOneSecond
,
5284 (ar
->LastAPTime
+ ar
->ThisAPInterval
- now
) / mDNSPlatformOneSecond
,
5285 ar
->expire
? (ar
->expire
- now
) / mDNSPlatformOneSecond
: 0,
5286 (t
- now
) / mDNSPlatformOneSecond
, ARDisplayString(m
, ar
));
5292 // ***************************************************************************
5293 #if COMPILER_LIKES_PRAGMA_MARK
5295 #pragma mark - Packet Reception Functions
5298 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5300 mDNSlocal mDNSu8
*GenerateUnicastResponse(const DNSMessage
*const query
, const mDNSu8
*const end
,
5301 const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, DNSMessage
*const response
, AuthRecord
*ResponseRecords
)
5303 mDNSu8
*responseptr
= response
->data
;
5304 const mDNSu8
*const limit
= response
->data
+ sizeof(response
->data
);
5305 const mDNSu8
*ptr
= query
->data
;
5307 mDNSu32 maxttl
= 0x70000000;
5310 // Initialize the response fields so we can answer the questions
5311 InitializeDNSMessage(&response
->h
, query
->h
.id
, ResponseFlags
);
5314 // *** 1. Write out the list of questions we are actually going to answer with this packet
5319 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5322 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &q
); // get the question...
5323 if (!ptr
) return(mDNSNULL
);
5325 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // and search our list of proposed answers
5327 if (rr
->NR_AnswerTo
== ptr
) // If we're going to generate a record answering this question
5328 { // then put the question in the question section
5329 responseptr
= putQuestion(response
, responseptr
, limit
, &q
.qname
, q
.qtype
, q
.qclass
);
5330 if (!responseptr
) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL
); }
5331 break; // break out of the ResponseRecords loop, and go on to the next question
5336 if (response
->h
.numQuestions
== 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL
); }
5340 // *** 2. Write Answers
5342 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5343 if (rr
->NR_AnswerTo
)
5345 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAnswers
, &rr
->resrec
,
5346 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5347 if (p
) responseptr
= p
;
5348 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response
->h
.flags
.b
[0] |= kDNSFlag0_TC
; }
5352 // *** 3. Write Additionals
5354 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5355 if (rr
->NR_AdditionalTo
&& !rr
->NR_AnswerTo
)
5357 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAdditionals
, &rr
->resrec
,
5358 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5359 if (p
) responseptr
= p
;
5360 else debugf("GenerateUnicastResponse: No more space for additionals");
5363 return(responseptr
);
5366 // AuthRecord *our is our Resource Record
5367 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5368 // Returns 0 if there is no conflict
5369 // Returns +1 if there was a conflict and we won
5370 // Returns -1 if there was a conflict and we lost and have to rename
5371 mDNSlocal
int CompareRData(const AuthRecord
*const our
, const CacheRecord
*const pkt
)
5373 mDNSu8 ourdata
[256], *ourptr
= ourdata
, *ourend
;
5374 mDNSu8 pktdata
[256], *pktptr
= pktdata
, *pktend
;
5375 if (!our
) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5376 if (!pkt
) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5378 ourend
= putRData(mDNSNULL
, ourdata
, ourdata
+ sizeof(ourdata
), &our
->resrec
);
5379 pktend
= putRData(mDNSNULL
, pktdata
, pktdata
+ sizeof(pktdata
), &pkt
->resrec
);
5380 while (ourptr
< ourend
&& pktptr
< pktend
&& *ourptr
== *pktptr
) { ourptr
++; pktptr
++; }
5381 if (ourptr
>= ourend
&& pktptr
>= pktend
) return(0); // If data identical, not a conflict
5383 if (ourptr
>= ourend
) return(-1); // Our data ran out first; We lost
5384 if (pktptr
>= pktend
) return(+1); // Packet data ran out first; We won
5385 if (*pktptr
> *ourptr
) return(-1); // Our data is numerically lower; We lost
5386 if (*pktptr
< *ourptr
) return(+1); // Packet data is numerically lower; We won
5388 LogMsg("CompareRData ERROR: Invalid state");
5392 // See if we have an authoritative record that's identical to this packet record,
5393 // whose canonical DependentOn record is the specified master record.
5394 // The DependentOn pointer is typically used for the TXT record of service registrations
5395 // It indicates that there is no inherent conflict detection for the TXT record
5396 // -- it depends on the SRV record to resolve name conflicts
5397 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
5398 // pointer chain (if any) to make sure we reach the canonical DependentOn record
5399 // If the record has no DependentOn, then just return that record's pointer
5400 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5401 mDNSlocal mDNSBool
MatchDependentOn(const mDNS
*const m
, const CacheRecord
*const pktrr
, const AuthRecord
*const master
)
5403 const AuthRecord
*r1
;
5404 for (r1
= m
->ResourceRecords
; r1
; r1
=r1
->next
)
5406 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5408 const AuthRecord
*r2
= r1
;
5409 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5410 if (r2
== master
) return(mDNStrue
);
5413 for (r1
= m
->DuplicateRecords
; r1
; r1
=r1
->next
)
5415 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5417 const AuthRecord
*r2
= r1
;
5418 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5419 if (r2
== master
) return(mDNStrue
);
5425 // Find the canonical RRSet pointer for this RR received in a packet.
5426 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
5427 // pointers (if any) to make sure we return the canonical member of this name/type/class
5428 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5429 mDNSlocal
const AuthRecord
*FindRRSet(const mDNS
*const m
, const CacheRecord
*const pktrr
)
5431 const AuthRecord
*rr
;
5432 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5434 if (IdenticalResourceRecord(&rr
->resrec
, &pktrr
->resrec
))
5436 while (rr
->RRSet
&& rr
!= rr
->RRSet
) rr
= rr
->RRSet
;
5443 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
5444 // as one of our records (our) but different rdata.
5445 // 1. If our record is not a type that's supposed to be unique, we don't care.
5446 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
5447 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
5448 // points to our record, ignore this conflict (e.g. the packet record matches one of our
5449 // TXT records, and that record is marked as dependent on 'our', its SRV record).
5450 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
5451 // are members of the same RRSet, then this is not a conflict.
5452 mDNSlocal mDNSBool
PacketRRConflict(const mDNS
*const m
, const AuthRecord
*const our
, const CacheRecord
*const pktrr
)
5454 // If not supposed to be unique, not a conflict
5455 if (!(our
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)) return(mDNSfalse
);
5457 // If a dependent record, not a conflict
5458 if (our
->DependentOn
|| MatchDependentOn(m
, pktrr
, our
)) return(mDNSfalse
);
5461 // If the pktrr matches a member of ourset, not a conflict
5462 const AuthRecord
*ourset
= our
->RRSet
? our
->RRSet
: our
;
5463 const AuthRecord
*pktset
= FindRRSet(m
, pktrr
);
5464 if (pktset
== ourset
) return(mDNSfalse
);
5466 // For records we're proxying, where we don't know the full
5467 // relationship between the records, having any matching record
5468 // in our AuthRecords list is sufficient evidence of non-conflict
5469 if (our
->WakeUp
.HMAC
.l
[0] && pktset
) return(mDNSfalse
);
5472 // Okay, this is a conflict
5476 // Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
5477 // the record list and/or question list.
5478 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5479 mDNSlocal
void ResolveSimultaneousProbe(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5480 DNSQuestion
*q
, AuthRecord
*our
)
5483 const mDNSu8
*ptr
= LocateAuthorities(query
, end
);
5484 mDNSBool FoundUpdate
= mDNSfalse
;
5486 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
5488 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
5490 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5492 FoundUpdate
= mDNStrue
;
5493 if (PacketRRConflict(m
, our
, &m
->rec
.r
))
5495 int result
= (int)our
->resrec
.rrclass
- (int)m
->rec
.r
.resrec
.rrclass
;
5496 if (!result
) result
= (int)our
->resrec
.rrtype
- (int)m
->rec
.r
.resrec
.rrtype
;
5497 if (!result
) result
= CompareRData(our
, &m
->rec
.r
);
5500 const char *const msg
= (result
< 0) ? "lost:" : (result
> 0) ? "won: " : "tie: ";
5501 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5502 LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our
->ProbeCount
, msg
, our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5504 // 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.
5505 // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
5506 // If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
5509 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5510 our
->ProbeCount
= DefaultProbeCountForTypeUnique
;
5511 our
->AnnounceCount
= InitialAnnounceCount
;
5512 InitializeLastAPTime(m
, our
);
5519 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5520 LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5524 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5527 LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
5529 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5532 mDNSlocal CacheRecord
*FindIdenticalRecordInCache(const mDNS
*const m
, const ResourceRecord
*const pktrr
)
5534 mDNSu32 slot
= HashSlot(pktrr
->name
);
5535 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, pktrr
);
5537 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5538 if (pktrr
->InterfaceID
== rr
->resrec
.InterfaceID
&& IdenticalSameNameRecord(pktrr
, &rr
->resrec
)) break;
5542 // Called from ProcessQuery when we get an mDNS packet with an owner record in it
5543 mDNSlocal
void ClearProxyRecords(mDNS
*const m
, const OwnerOptData
*const owner
, AuthRecord
*const thelist
)
5545 m
->CurrentRecord
= thelist
;
5546 while (m
->CurrentRecord
)
5548 AuthRecord
*const rr
= m
->CurrentRecord
;
5549 if (m
->rec
.r
.resrec
.InterfaceID
== rr
->resrec
.InterfaceID
&& mDNSSameEthAddress(&owner
->HMAC
, &rr
->WakeUp
.HMAC
))
5550 if (owner
->seq
!= rr
->WakeUp
.seq
|| m
->timenow
- rr
->TimeRcvd
> mDNSPlatformOneSecond
* 60)
5552 LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
5553 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, owner
->seq
, ARDisplayString(m
, rr
));
5554 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
5555 SetSPSProxyListChanged(m
->rec
.r
.resrec
.InterfaceID
);
5557 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
5558 // because the list may have been changed in that call.
5559 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
5560 m
->CurrentRecord
= rr
->next
;
5564 // ProcessQuery examines a received query to see if we have any answers to give
5565 mDNSlocal mDNSu8
*ProcessQuery(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5566 const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, mDNSBool QueryWasMulticast
,
5567 mDNSBool QueryWasLocalUnicast
, DNSMessage
*const response
)
5569 mDNSBool FromLocalSubnet
= srcaddr
&& AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
5570 AuthRecord
*ResponseRecords
= mDNSNULL
;
5571 AuthRecord
**nrp
= &ResponseRecords
;
5572 CacheRecord
*ExpectedAnswers
= mDNSNULL
; // Records in our cache we expect to see updated
5573 CacheRecord
**eap
= &ExpectedAnswers
;
5574 DNSQuestion
*DupQuestions
= mDNSNULL
; // Our questions that are identical to questions in this packet
5575 DNSQuestion
**dqp
= &DupQuestions
;
5576 mDNSs32 delayresponse
= 0;
5577 mDNSBool SendLegacyResponse
= mDNSfalse
;
5579 mDNSu8
*responseptr
= mDNSNULL
;
5584 // *** 1. Look in Additional Section for an OPT record
5586 ptr
= LocateOptRR(query
, end
, DNSOpt_OwnerData_ID_Space
);
5589 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &m
->rec
);
5590 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
5592 const rdataOPT
*opt
;
5593 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
5594 // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
5595 // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
5596 for (opt
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; opt
< e
; opt
++)
5597 if (opt
->opt
== kDNSOpt_Owner
&& opt
->u
.owner
.vers
== 0 && opt
->u
.owner
.HMAC
.l
[0])
5599 ClearProxyRecords(m
, &opt
->u
.owner
, m
->DuplicateRecords
);
5600 ClearProxyRecords(m
, &opt
->u
.owner
, m
->ResourceRecords
);
5603 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5607 // *** 2. Parse Question Section and mark potential answers
5610 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5612 mDNSBool QuestionNeedsMulticastResponse
;
5613 int NumAnswersForThisQuestion
= 0;
5614 AuthRecord
*NSECAnswer
= mDNSNULL
;
5615 DNSQuestion pktq
, *q
;
5616 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &pktq
); // get the question...
5617 if (!ptr
) goto exit
;
5619 // The only queries that *need* a multicast response are:
5620 // * Queries sent via multicast
5622 // * that don't have the kDNSQClass_UnicastResponse bit set
5623 // These queries need multicast responses because other clients will:
5624 // * suppress their own identical questions when they see these questions, and
5625 // * expire their cache records if they don't see the expected responses
5626 // For other queries, we may still choose to send the occasional multicast response anyway,
5627 // to keep our neighbours caches warm, and for ongoing conflict detection.
5628 QuestionNeedsMulticastResponse
= QueryWasMulticast
&& !LegacyQuery
&& !(pktq
.qclass
& kDNSQClass_UnicastResponse
);
5629 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
5630 pktq
.qclass
&= ~kDNSQClass_UnicastResponse
;
5632 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
5633 // can result in user callbacks which may change the record list and/or question list.
5634 // Also note: we just mark potential answer records here, without trying to build the
5635 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
5636 // from that list while we're in the middle of trying to build it.
5637 if (m
->CurrentRecord
)
5638 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
5639 m
->CurrentRecord
= m
->ResourceRecords
;
5640 while (m
->CurrentRecord
)
5642 rr
= m
->CurrentRecord
;
5643 m
->CurrentRecord
= rr
->next
;
5644 if (AnyTypeRecordAnswersQuestion(&rr
->resrec
, &pktq
) && (QueryWasMulticast
|| QueryWasLocalUnicast
|| rr
->AllowRemoteQuery
))
5646 if (RRTypeAnswersQuestionType(&rr
->resrec
, pktq
.qtype
))
5648 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
5649 ResolveSimultaneousProbe(m
, query
, end
, &pktq
, rr
);
5650 else if (ResourceRecordIsValidAnswer(rr
))
5652 NumAnswersForThisQuestion
++;
5653 // Note: We should check here if this is a probe-type query, and if so, generate an immediate
5654 // unicast answer back to the source, because timeliness in answering probes is important.
5657 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
5658 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
5659 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
5660 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
5661 // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
5662 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
5663 if (QuestionNeedsMulticastResponse
|| (!FromLocalSubnet
&& QueryWasMulticast
&& !LegacyQuery
))
5665 // We only mark this question for sending if it is at least one second since the last time we multicast it
5666 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
5667 // This is to guard against the case where someone blasts us with queries as fast as they can.
5668 if (m
->timenow
- (rr
->LastMCTime
+ mDNSPlatformOneSecond
) >= 0 ||
5669 (rr
->LastMCInterface
!= mDNSInterfaceMark
&& rr
->LastMCInterface
!= InterfaceID
))
5670 rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5672 else if (!rr
->NR_AnswerTo
) rr
->NR_AnswerTo
= LegacyQuery
? ptr
: (mDNSu8
*)~1;
5675 else if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
5677 // If we don't have any answers for this question, but we do own another record with the same name,
5678 // then mark it to generate an NSEC record on this interface
5679 if (!NSECAnswer
) NSECAnswer
= rr
;
5684 if (NumAnswersForThisQuestion
== 0 && NSECAnswer
)
5686 NumAnswersForThisQuestion
++;
5687 NSECAnswer
->SendNSECNow
= InterfaceID
;
5688 m
->NextScheduledResponse
= m
->timenow
;
5691 // If we couldn't answer this question, someone else might be able to,
5692 // so use random delay on response to reduce collisions
5693 if (NumAnswersForThisQuestion
== 0) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5695 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5696 if (QuestionNeedsMulticastResponse
)
5698 // We only do the following accelerated cache expiration and duplicate question suppression processing
5699 // for non-truncated multicast queries with multicast responses.
5700 // For any query generating a unicast response we don't do this because we can't assume we will see the response.
5701 // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
5702 // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
5703 if (QuestionNeedsMulticastResponse
&& !(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5706 const mDNSu32 slot
= HashSlot(&pktq
.qname
);
5707 CacheGroup
*cg
= CacheGroupForName(m
, slot
, pktq
.qnamehash
, &pktq
.qname
);
5710 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
5711 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5712 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5713 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5715 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
5716 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &pktq
) && cr
->resrec
.rdlength
<= SmallRecordLimit
)
5717 if (!cr
->NextInKAList
&& eap
!= &cr
->NextInKAList
)
5720 eap
= &cr
->NextInKAList
;
5721 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5722 if (cr
->MPUnansweredQ
== 0 || m
->timenow
- cr
->MPLastUnansweredQT
>= mDNSPlatformOneSecond
)
5724 // Although MPUnansweredQ is only really used for multi-packet query processing,
5725 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
5726 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
5727 cr
->MPUnansweredQ
++;
5728 cr
->MPLastUnansweredQT
= m
->timenow
;
5729 cr
->MPExpectingKA
= mDNStrue
;
5734 // Check if this question is the same as any of mine.
5735 // We only do this for non-truncated queries. Right now it would be too complicated to try
5736 // to keep track of duplicate suppression state between multiple packets, especially when we
5737 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
5738 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5739 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5741 for (q
= m
->Questions
; q
; q
=q
->next
)
5742 if (!q
->Target
.type
&& ActiveQuestion(q
) && m
->timenow
- q
->LastQTxTime
> mDNSPlatformOneSecond
/ 4)
5743 if (!q
->InterfaceID
|| q
->InterfaceID
== InterfaceID
)
5744 if (q
->NextInDQList
== mDNSNULL
&& dqp
!= &q
->NextInDQList
)
5745 if (q
->qtype
== pktq
.qtype
&&
5746 q
->qclass
== pktq
.qclass
&&
5747 q
->qnamehash
== pktq
.qnamehash
&& SameDomainName(&q
->qname
, &pktq
.qname
))
5748 { *dqp
= q
; dqp
= &q
->NextInDQList
; }
5753 // *** 3. Now we can safely build the list of marked answers
5755 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) // Now build our list of potential answers
5756 if (rr
->NR_AnswerTo
) // If we marked the record...
5757 AddRecordToResponseList(&nrp
, rr
, mDNSNULL
); // ... add it to the list
5760 // *** 4. Add additional records
5762 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
5765 // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
5767 for (i
=0; i
<query
->h
.numAnswers
; i
++) // For each record in the query's answer section...
5769 // Get the record...
5770 CacheRecord
*ourcacherr
;
5771 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &m
->rec
);
5772 if (!ptr
) goto exit
;
5774 // See if this Known-Answer suppresses any of our currently planned answers
5775 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5776 if (MustSendRecord(rr
) && ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5777 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5779 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5780 for (rr
=m
->ResourceRecords
; rr
; rr
=rr
->next
)
5782 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5783 if (rr
->ImmedAnswer
== InterfaceID
&& ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5785 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5787 if (mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= zerov4Addr
;
5789 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5791 if (mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= zerov6Addr
;
5793 if (mDNSIPv4AddressIsZero(rr
->v4Requester
) && mDNSIPv6AddressIsZero(rr
->v6Requester
))
5795 rr
->ImmedAnswer
= mDNSNULL
;
5796 rr
->ImmedUnicast
= mDNSfalse
;
5797 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5798 LogMsg("Suppressed after%4d: %s", m
->timenow
- rr
->ImmedAnswerMarkTime
, ARDisplayString(m
, rr
));
5804 ourcacherr
= FindIdenticalRecordInCache(m
, &m
->rec
.r
.resrec
);
5806 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5807 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5808 // 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).
5809 if (ourcacherr
&& ourcacherr
->MPExpectingKA
&& m
->timenow
- ourcacherr
->MPLastUnansweredQT
< mDNSPlatformOneSecond
)
5811 ourcacherr
->MPUnansweredKA
++;
5812 ourcacherr
->MPExpectingKA
= mDNSfalse
;
5816 // Having built our ExpectedAnswers list from the questions in this packet, we then remove
5817 // any records that are suppressed by the Known Answer list in this packet.
5818 eap
= &ExpectedAnswers
;
5821 CacheRecord
*cr
= *eap
;
5822 if (cr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalResourceRecord(&m
->rec
.r
.resrec
, &cr
->resrec
))
5823 { *eap
= cr
->NextInKAList
; cr
->NextInKAList
= mDNSNULL
; }
5824 else eap
= &cr
->NextInKAList
;
5827 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5830 dqp
= &DupQuestions
;
5833 DNSQuestion
*q
= *dqp
;
5834 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5835 { *dqp
= q
->NextInDQList
; q
->NextInDQList
= mDNSNULL
; }
5836 else dqp
= &q
->NextInDQList
;
5839 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5843 // *** 6. Cancel any additionals that were added because of now-deleted records
5845 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5846 if (rr
->NR_AdditionalTo
&& !MustSendRecord(rr
->NR_AdditionalTo
))
5847 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5850 // *** 7. Mark the send flags on the records we plan to send
5852 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5854 if (rr
->NR_AnswerTo
)
5856 mDNSBool SendMulticastResponse
= mDNSfalse
; // Send modern multicast response
5857 mDNSBool SendUnicastResponse
= mDNSfalse
; // Send modern unicast response (not legacy unicast response)
5859 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5860 if (m
->timenow
- (rr
->LastMCTime
+ TicksTTL(rr
)/4) >= 0)
5862 SendMulticastResponse
= mDNStrue
;
5863 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5864 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5865 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5866 if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5869 // If the client insists on a multicast response, then we'd better send one
5870 if (rr
->NR_AnswerTo
== (mDNSu8
*)~0) SendMulticastResponse
= mDNStrue
;
5871 else if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) SendUnicastResponse
= mDNStrue
;
5872 else if (rr
->NR_AnswerTo
) SendLegacyResponse
= mDNStrue
;
5874 if (SendMulticastResponse
|| SendUnicastResponse
)
5876 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5877 rr
->ImmedAnswerMarkTime
= m
->timenow
;
5879 m
->NextScheduledResponse
= m
->timenow
;
5880 // If we're already planning to send this on another interface, just send it on all interfaces
5881 if (rr
->ImmedAnswer
&& rr
->ImmedAnswer
!= InterfaceID
)
5882 rr
->ImmedAnswer
= mDNSInterfaceMark
;
5885 rr
->ImmedAnswer
= InterfaceID
; // Record interface to send it on
5886 if (SendUnicastResponse
) rr
->ImmedUnicast
= mDNStrue
;
5887 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5889 if (mDNSIPv4AddressIsZero(rr
->v4Requester
)) rr
->v4Requester
= srcaddr
->ip
.v4
;
5890 else if (!mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= onesIPv4Addr
;
5892 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5894 if (mDNSIPv6AddressIsZero(rr
->v6Requester
)) rr
->v6Requester
= srcaddr
->ip
.v6
;
5895 else if (!mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= onesIPv6Addr
;
5899 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5900 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5901 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5902 // else, for a simple unique record reply, we can reply immediately; no need for delay
5903 if (query
->h
.flags
.b
[0] & kDNSFlag0_TC
) delayresponse
= mDNSPlatformOneSecond
* 20; // Divided by 50 = 400ms
5904 else if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5906 else if (rr
->NR_AdditionalTo
&& rr
->NR_AdditionalTo
->NR_AnswerTo
== (mDNSu8
*)~0)
5908 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
5909 // If two clients on different interfaces do queries that invoke the same optional additional answer,
5910 // then the earlier client is out of luck
5911 rr
->ImmedAdditional
= InterfaceID
;
5912 // No need to set m->NextScheduledResponse here
5913 // We'll send these additional records when we send them, or not, as the case may be
5918 // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
5920 if (delayresponse
&& (!m
->SuppressSending
|| (m
->SuppressSending
- m
->timenow
) < (delayresponse
+ 49) / 50))
5922 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5923 mDNSs32 oldss
= m
->SuppressSending
;
5924 if (oldss
&& delayresponse
)
5925 LogMsg("Current SuppressSending delay%5ld; require%5ld", m
->SuppressSending
- m
->timenow
, (delayresponse
+ 49) / 50);
5927 // Pick a random delay:
5928 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
5929 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5930 // This is an integer value, with resolution determined by the platform clock rate.
5931 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
5932 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5933 // The +49 before dividing is to ensure we round up, not down, to ensure that even
5934 // on platforms where the native clock rate is less than fifty ticks per second,
5935 // we still guarantee that the final calculated delay is at least one platform tick.
5936 // We want to make sure we don't ever allow the delay to be zero ticks,
5937 // because if that happens we'll fail the Bonjour Conformance Test.
5938 // Our final computed delay is 20-120ms for normal delayed replies,
5939 // or 400-500ms in the case of multi-packet known-answer lists.
5940 m
->SuppressSending
= m
->timenow
+ (delayresponse
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*5) + 49) / 50;
5941 if (m
->SuppressSending
== 0) m
->SuppressSending
= 1;
5942 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5943 if (oldss
&& delayresponse
)
5944 LogMsg("Set SuppressSending to %5ld", m
->SuppressSending
- m
->timenow
);
5949 // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5951 if (SendLegacyResponse
)
5952 responseptr
= GenerateUnicastResponse(query
, end
, InterfaceID
, LegacyQuery
, response
, ResponseRecords
);
5955 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5958 // *** 10. Finally, clear our link chains ready for use next time
5960 while (ResponseRecords
)
5962 rr
= ResponseRecords
;
5963 ResponseRecords
= rr
->NextResponse
;
5964 rr
->NextResponse
= mDNSNULL
;
5965 rr
->NR_AnswerTo
= mDNSNULL
;
5966 rr
->NR_AdditionalTo
= mDNSNULL
;
5969 while (ExpectedAnswers
)
5971 CacheRecord
*cr
= ExpectedAnswers
;
5972 ExpectedAnswers
= cr
->NextInKAList
;
5973 cr
->NextInKAList
= mDNSNULL
;
5975 // For non-truncated queries, we can definitively say that we should expect
5976 // to be seeing a response for any records still left in the ExpectedAnswers list
5977 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5978 if (cr
->UnansweredQueries
== 0 || m
->timenow
- cr
->LastUnansweredTime
>= mDNSPlatformOneSecond
)
5980 cr
->UnansweredQueries
++;
5981 cr
->LastUnansweredTime
= m
->timenow
;
5982 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5983 if (cr
->UnansweredQueries
> 1)
5984 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5985 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
5987 SetNextCacheCheckTime(m
, cr
);
5990 // If we've seen multiple unanswered queries for this record,
5991 // then mark it to expire in five seconds if we don't get a response by then.
5992 if (cr
->UnansweredQueries
>= MaxUnansweredQueries
)
5994 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5995 // Only show debugging message if this record was not about to expire anyway
5996 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
5997 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5998 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
6000 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
6002 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6003 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
6004 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
6005 // possible packet loss of up to 20% of the additional KA packets.)
6006 else if (cr
->MPUnansweredQ
* 4 > cr
->MPUnansweredKA
* 5 + 8)
6008 // We want to do this conservatively.
6009 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
6010 // then we don't want them to all hit the network simultaneously with their final expiration queries.
6011 // By setting the record to expire in four minutes, we achieve two things:
6012 // (a) the 90-95% final expiration queries will be less bunched together
6013 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
6014 mDNSu32 remain
= (mDNSu32
)(RRExpireTime(cr
) - m
->timenow
) / 4;
6015 if (remain
> 240 * (mDNSu32
)mDNSPlatformOneSecond
)
6016 remain
= 240 * (mDNSu32
)mDNSPlatformOneSecond
;
6018 // Only show debugging message if this record was not about to expire anyway
6019 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
6020 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
6021 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
6023 if (remain
<= 60 * (mDNSu32
)mDNSPlatformOneSecond
)
6024 cr
->UnansweredQueries
++; // Treat this as equivalent to one definite unanswered query
6025 cr
->MPUnansweredQ
= 0; // Clear MPQ/MPKA statistics
6026 cr
->MPUnansweredKA
= 0;
6027 cr
->MPExpectingKA
= mDNSfalse
;
6029 if (remain
< kDefaultReconfirmTimeForNoAnswer
)
6030 remain
= kDefaultReconfirmTimeForNoAnswer
;
6031 mDNS_Reconfirm_internal(m
, cr
, remain
);
6036 while (DupQuestions
)
6038 DNSQuestion
*q
= DupQuestions
;
6039 DupQuestions
= q
->NextInDQList
;
6040 q
->NextInDQList
= mDNSNULL
;
6041 i
= RecordDupSuppressInfo(q
->DupSuppress
, m
->timenow
, InterfaceID
, srcaddr
->type
);
6042 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q
->qname
.c
, DNSTypeName(q
->qtype
), InterfaceID
,
6043 srcaddr
->type
== mDNSAddrType_IPv4
? "v4" : "v6", i
);
6046 return(responseptr
);
6049 mDNSlocal
void mDNSCoreReceiveQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
6050 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6051 const mDNSInterfaceID InterfaceID
)
6053 mDNSu8
*responseend
= mDNSNULL
;
6054 mDNSBool QueryWasLocalUnicast
= srcaddr
&& dstaddr
&&
6055 !mDNSAddrIsDNSMulticast(dstaddr
) && AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
6057 if (!InterfaceID
&& dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
))
6059 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6060 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
6061 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6062 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6063 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6064 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6065 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6069 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6070 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6071 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6072 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6073 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6074 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6075 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6077 responseend
= ProcessQuery(m
, msg
, end
, srcaddr
, InterfaceID
,
6078 !mDNSSameIPPort(srcport
, MulticastDNSPort
), mDNSAddrIsDNSMulticast(dstaddr
), QueryWasLocalUnicast
, &m
->omsg
);
6080 if (responseend
) // If responseend is non-null, that means we built a unicast response packet
6082 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
6083 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
6084 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
6085 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s",
6086 srcaddr
, mDNSVal16(srcport
), InterfaceID
, srcaddr
->type
);
6087 mDNSSendDNSMessage(m
, &m
->omsg
, responseend
, InterfaceID
, mDNSNULL
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
6092 mDNSlocal mDNSBool
TrustedSource(const mDNS
*const m
, const mDNSAddr
*const srcaddr
)
6096 (void)srcaddr
; // Unused
6097 for (s
= m
->DNSServers
; s
; s
= s
->next
)
6098 if (mDNSSameAddress(srcaddr
, &s
->addr
)) return(mDNStrue
);
6103 struct UDPSocket_struct
6105 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
6108 mDNSlocal DNSQuestion
*ExpectingUnicastResponseForQuestion(const mDNS
*const m
, const mDNSIPPort port
, const mDNSOpaque16 id
, const DNSQuestion
*const question
)
6111 for (q
= m
->Questions
; q
; q
=q
->next
)
6112 if (q
->LocalSocket
&&
6113 mDNSSameIPPort (q
->LocalSocket
->port
, port
) &&
6114 mDNSSameOpaque16(q
->TargetQID
, id
) &&
6115 q
->qtype
== question
->qtype
&&
6116 q
->qclass
== question
->qclass
&&
6117 q
->qnamehash
== question
->qnamehash
&&
6118 SameDomainName(&q
->qname
, &question
->qname
))
6123 mDNSlocal mDNSBool
ExpectingUnicastResponseForRecord(mDNS
*const m
, const mDNSAddr
*const srcaddr
, const mDNSBool SrcLocal
, const mDNSIPPort port
, const mDNSOpaque16 id
, const CacheRecord
*const rr
)
6128 for (q
= m
->Questions
; q
; q
=q
->next
)
6129 if (!q
->DuplicateOf
&& ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
6131 if (!mDNSOpaque16IsZero(q
->TargetQID
))
6133 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id
), mDNSVal16(q
->TargetQID
), CRDisplayString(m
, rr
));
6134 if (mDNSSameOpaque16(q
->TargetQID
, id
))
6136 if (q
->LocalSocket
&& mDNSSameIPPort(q
->LocalSocket
->port
, port
)) return(mDNStrue
);
6137 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
6138 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
6139 // if (TrustedSource(m, srcaddr)) return(mDNStrue);
6140 LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
6141 q
->qname
.c
, DNSTypeName(q
->qtype
), &q
->Target
, mDNSVal16(q
->LocalSocket
? q
->LocalSocket
->port
: zeroIPPort
), srcaddr
, mDNSVal16(port
), CRDisplayString(m
, rr
));
6147 if (SrcLocal
&& q
->ExpectUnicastResp
&& (mDNSu32
)(m
->timenow
- q
->ExpectUnicastResp
) < (mDNSu32
)(mDNSPlatformOneSecond
*2))
6154 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
6155 // Currently this applies only to rdata types containing more than one domainname,
6156 // or types where the domainname is not the last item in the structure.
6157 // In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
6158 mDNSlocal mDNSu16
GetRDLengthMem(const ResourceRecord
*const rr
)
6162 case kDNSType_SOA
: return sizeof(rdataSOA
);
6163 case kDNSType_RP
: return sizeof(rdataRP
);
6164 case kDNSType_PX
: return sizeof(rdataPX
);
6165 case kDNSType_NSEC
:return sizeof(rdataNSEC
);
6166 default: return rr
->rdlength
;
6170 mDNSexport CacheRecord
*CreateNewCacheEntry(mDNS
*const m
, const mDNSu32 slot
, CacheGroup
*cg
)
6172 CacheRecord
*rr
= mDNSNULL
;
6173 mDNSu16 RDLength
= GetRDLengthMem(&m
->rec
.r
.resrec
);
6175 if (!m
->rec
.r
.resrec
.InterfaceID
) debugf("CreateNewCacheEntry %s", CRDisplayString(m
, &m
->rec
.r
));
6177 //if (RDLength > InlineCacheRDSize)
6178 // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
6180 if (!cg
) cg
= GetCacheGroup(m
, slot
, &m
->rec
.r
.resrec
); // If we don't have a CacheGroup for this name, make one now
6181 if (cg
) rr
= GetCacheRecord(m
, cg
, RDLength
); // Make a cache record, being careful not to recycle cg
6182 if (!rr
) NoCacheAnswer(m
, &m
->rec
.r
);
6185 RData
*saveptr
= rr
->resrec
.rdata
; // Save the rr->resrec.rdata pointer
6186 *rr
= m
->rec
.r
; // Block copy the CacheRecord object
6187 rr
->resrec
.rdata
= saveptr
; // Restore rr->resrec.rdata after the structure assignment
6188 rr
->resrec
.name
= cg
->name
; // And set rr->resrec.name to point into our CacheGroup header
6190 // If this is an oversized record with external storage allocated, copy rdata to external storage
6191 if (rr
->resrec
.rdata
== (RData
*)&rr
->smallrdatastorage
&& RDLength
> InlineCacheRDSize
)
6192 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6193 else if (rr
->resrec
.rdata
!= (RData
*)&rr
->smallrdatastorage
&& RDLength
<= InlineCacheRDSize
)
6194 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6195 if (RDLength
> InlineCacheRDSize
)
6196 mDNSPlatformMemCopy(rr
->resrec
.rdata
, m
->rec
.r
.resrec
.rdata
, sizeofRDataHeader
+ RDLength
);
6198 rr
->next
= mDNSNULL
; // Clear 'next' pointer
6199 *(cg
->rrcache_tail
) = rr
; // Append this record to tail of cache slot list
6200 cg
->rrcache_tail
= &(rr
->next
); // Advance tail pointer
6201 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
6202 rr
->DelayDelivery
= NonZeroTime(m
->timenow
);
6203 else if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
&& // If marked unique,
6204 rr
->resrec
.rdata
->MaxRDLength
!= 0) // and non-negative, assume we may have
6205 rr
->DelayDelivery
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
); // to delay delivery of this 'add' event
6207 rr
->DelayDelivery
= CheckForSoonToExpireRecords(m
, rr
->resrec
.name
, rr
->resrec
.namehash
, slot
);
6209 CacheRecordAdd(m
, rr
); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
6214 mDNSlocal
void RefreshCacheRecord(mDNS
*const m
, CacheRecord
*rr
, mDNSu32 ttl
)
6216 rr
->TimeRcvd
= m
->timenow
;
6217 rr
->resrec
.rroriginalttl
= ttl
;
6218 rr
->UnansweredQueries
= 0;
6219 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6220 rr
->MPUnansweredQ
= 0;
6221 rr
->MPUnansweredKA
= 0;
6222 rr
->MPExpectingKA
= mDNSfalse
;
6224 SetNextCacheCheckTime(m
, rr
);
6227 mDNSexport
void GrantCacheExtensions(mDNS
*const m
, DNSQuestion
*q
, mDNSu32 lease
)
6230 const mDNSu32 slot
= HashSlot(&q
->qname
);
6231 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
6232 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6233 if (rr
->CRActiveQuestion
== q
)
6235 //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
6236 RefreshCacheRecord(m
, rr
, lease
);
6240 mDNSlocal mDNSu32
GetEffectiveTTL(const uDNS_LLQType LLQType
, mDNSu32 ttl
) // TTL in seconds
6242 if (LLQType
== uDNS_LLQ_Entire
) ttl
= kLLQ_DefLease
;
6243 else if (LLQType
== uDNS_LLQ_Events
)
6245 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
6246 if (ttl
== 0xFFFFFFFF) ttl
= 0;
6247 else ttl
= kLLQ_DefLease
;
6249 else // else not LLQ (standard uDNS response)
6251 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
6252 // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL
6253 if (ttl
> 0x60000000UL
/ mDNSPlatformOneSecond
) ttl
= 0x60000000UL
/ mDNSPlatformOneSecond
;
6255 // Adjustment factor to avoid race condition:
6256 // 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.
6257 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
6258 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
6259 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
6260 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
6261 // the cached copy at our local caching server will already have expired, so the server will be forced
6262 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
6265 // For mDNS, TTL zero means "delete this record"
6266 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
6267 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
6268 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
6269 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
6270 if (ttl
< 15) ttl
= 15;
6276 // Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
6277 // the record list and/or question list.
6278 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6279 // InterfaceID non-NULL tells us the interface this multicast response was received on
6280 // InterfaceID NULL tells us this was a unicast response
6281 // dstaddr NULL tells us we received this over an outgoing TCP connection we made
6282 mDNSlocal
void mDNSCoreReceiveResponse(mDNS
*const m
,
6283 const DNSMessage
*const response
, const mDNSu8
*end
,
6284 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6285 const mDNSInterfaceID InterfaceID
)
6288 mDNSBool ResponseMCast
= dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
);
6289 mDNSBool ResponseSrcLocal
= !srcaddr
|| AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
6290 uDNS_LLQType LLQType
= uDNS_recvLLQResponse(m
, response
, end
, srcaddr
, srcport
);
6292 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
6293 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
6294 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
6295 CacheRecord
*CacheFlushRecords
= (CacheRecord
*)1;
6296 CacheRecord
**cfp
= &CacheFlushRecords
;
6298 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
6299 // to guard against spoof responses, then the only credible protection against that is cryptographic
6300 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
6301 int firstauthority
= response
->h
.numAnswers
;
6302 int firstadditional
= firstauthority
+ response
->h
.numAuthorities
;
6303 int totalrecords
= firstadditional
+ response
->h
.numAdditionals
;
6304 const mDNSu8
*ptr
= response
->data
;
6306 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
6307 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
6308 srcaddr
, dstaddr
, InterfaceID
,
6309 response
->h
.numQuestions
, response
->h
.numQuestions
== 1 ? ", " : "s,",
6310 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6311 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6312 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s", LLQType
);
6314 // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
6315 // When a DNS client receives a reply with TC
6316 // set, it should ignore that response, and query again, using a
6317 // mechanism, such as a TCP connection, that will permit larger replies.
6318 // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
6319 // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
6320 // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
6321 // <rdar://problem/6690034> Can't bind to Active Directory
6322 // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
6323 // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
6324 // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
6325 // and not even do the TCP query.
6326 // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
6327 if (!InterfaceID
&& (response
->h
.flags
.b
[0] & kDNSFlag0_TC
)) return;
6329 if (LLQType
== uDNS_LLQ_Ignore
) return;
6331 // 1. We ignore questions (if any) in mDNS response packets
6332 // 2. If this is an LLQ response, we handle it much the same
6333 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
6334 // answer as being the authoritative complete RRSet, and respond by deleting all other
6335 // matching cache records that don't appear in this packet.
6336 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
6337 if (ResponseMCast
|| LLQType
== uDNS_LLQ_Events
|| (response
->h
.flags
.b
[0] & kDNSFlag0_TC
))
6338 ptr
= LocateAnswers(response
, end
);
6339 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
6340 // in this response packet are immediately deemed to be invalid.
6343 mDNSu8 rcode
= (mDNSu8
)(response
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
6344 mDNSBool failure
= !(rcode
== kDNSFlag1_RC_NoErr
|| rcode
== kDNSFlag1_RC_NXDomain
|| rcode
== kDNSFlag1_RC_NotAuth
);
6345 mDNSBool returnEarly
= mDNSfalse
;
6346 // We could possibly combine this with the similar loop at the end of this function --
6347 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
6348 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
6349 // which it was received (or refreshed), and then at the end if we find any cache records which
6350 // answer questions in this packet's question section, but which aren't tagged with this packet's
6351 // packet number, then we deduce they are old and delete them
6352 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6354 DNSQuestion q
, *qptr
= mDNSNULL
;
6355 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6356 if (ptr
&& (!dstaddr
|| (qptr
= ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
))))
6361 const mDNSu32 slot
= HashSlot(&q
.qname
);
6362 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6363 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6364 if (q
.InterfaceID
== rr
->resrec
.InterfaceID
&& SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6366 debugf("uDNS marking %p %##s (%s) %p %s", q
.InterfaceID
, q
.qname
.c
, DNSTypeName(q
.qtype
),
6367 rr
->resrec
.InterfaceID
, CRDisplayString(m
, rr
));
6368 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
6369 rr
->TimeRcvd
= m
->timenow
- TicksTTL(rr
) - 1;
6370 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6377 LogInfo("Server %p responded with code %d to query %##s (%s)", qptr
->qDNSServer
, rcode
, q
.qname
.c
, DNSTypeName(q
.qtype
));
6378 PushDNSServerToEnd(m
, qptr
);
6380 returnEarly
= mDNStrue
;
6386 LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
6387 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6388 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6389 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s");
6390 // not goto exit because we won't have any CacheFlushRecords and we do not want to
6391 // generate negative cache entries (we want to query the next server)
6396 for (i
= 0; i
< totalrecords
&& ptr
&& ptr
< end
; i
++)
6398 // All responses sent via LL multicast are acceptable for caching
6399 // All responses received over our outbound TCP connections are acceptable for caching
6400 mDNSBool AcceptableResponse
= ResponseMCast
|| !dstaddr
|| LLQType
;
6401 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
6402 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
6404 const mDNSu8 RecordType
=
6405 (i
< firstauthority
) ? (mDNSu8
)kDNSRecordTypePacketAns
:
6406 (i
< firstadditional
) ? (mDNSu8
)kDNSRecordTypePacketAuth
: (mDNSu8
)kDNSRecordTypePacketAdd
;
6407 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, RecordType
, &m
->rec
);
6408 if (!ptr
) goto exit
; // Break out of the loop and clean up our CacheFlushRecords list before exiting
6410 // Don't want to cache OPT or TSIG pseudo-RRs
6411 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
|| m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
6412 { m
->rec
.r
.resrec
.RecordType
= 0; continue; }
6414 // if a CNAME record points to itself, then don't add it to the cache
6415 if ((m
->rec
.r
.resrec
.rrtype
== kDNSType_CNAME
) && SameDomainName(m
->rec
.r
.resrec
.name
, &m
->rec
.r
.resrec
.rdata
->u
.name
))
6417 LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m
->rec
.r
.resrec
.name
->c
);
6418 m
->rec
.r
.resrec
.RecordType
= 0;
6422 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
6423 // In the case of active LLQs, we'll get remove events when the records actually do go away
6424 // In the case of polling LLQs, we assume the record remains valid until the next poll
6425 if (!mDNSOpaque16IsZero(response
->h
.id
))
6426 m
->rec
.r
.resrec
.rroriginalttl
= GetEffectiveTTL(LLQType
, m
->rec
.r
.resrec
.rroriginalttl
);
6428 // If response was not sent via LL multicast,
6429 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
6430 if (!AcceptableResponse
) AcceptableResponse
= ExpectingUnicastResponseForRecord(m
, srcaddr
, ResponseSrcLocal
, dstport
, response
->h
.id
, &m
->rec
.r
);
6432 // 1. Check that this packet resource record does not conflict with any of ours
6433 if (mDNSOpaque16IsZero(response
->h
.id
) && m
->rec
.r
.resrec
.rrtype
!= kDNSType_NSEC
)
6435 if (m
->CurrentRecord
)
6436 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
6437 m
->CurrentRecord
= m
->ResourceRecords
;
6438 while (m
->CurrentRecord
)
6440 AuthRecord
*rr
= m
->CurrentRecord
;
6441 m
->CurrentRecord
= rr
->next
;
6442 // We accept all multicast responses, and unicast responses resulting from queries we issued
6443 // For other unicast responses, this code accepts them only for responses with an
6444 // (apparently) local source address that pertain to a record of our own that's in probing state
6445 if (!AcceptableResponse
&& !(ResponseSrcLocal
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)) continue;
6447 if (PacketRRMatchesSignature(&m
->rec
.r
, rr
)) // If interface, name, type (if shared record) and class match...
6449 // ... check to see if type and rdata are identical
6450 if (IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6452 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
6453 if (m
->rec
.r
.resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/2 || m
->SleepState
)
6455 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
6456 if (rr
->ImmedAnswer
== InterfaceID
) { rr
->ImmedAnswer
= mDNSNULL
; rr
->ImmedUnicast
= mDNSfalse
; }
6460 if (rr
->ImmedAnswer
== mDNSNULL
) { rr
->ImmedAnswer
= InterfaceID
; m
->NextScheduledResponse
= m
->timenow
; }
6461 else if (rr
->ImmedAnswer
!= InterfaceID
) { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6464 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
6465 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0 && PacketRRConflict(m
, rr
, &m
->rec
.r
))
6467 LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
6468 LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6470 // If this record is marked DependentOn another record for conflict detection purposes,
6471 // then *that* record has to be bumped back to probing state to resolve the conflict
6472 if (rr
->DependentOn
)
6474 while (rr
->DependentOn
) rr
= rr
->DependentOn
;
6475 LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6478 // If we've just whacked this record's ProbeCount, don't need to do it again
6479 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
6480 LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m
, rr
));
6481 else if (rr
->ProbeCount
== DefaultProbeCountForTypeUnique
)
6482 LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m
, rr
));
6485 LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr
, mDNSVal16(srcport
), CRDisplayString(m
, &m
->rec
.r
));
6486 // If we'd previously verified this record, put it back to probing state and try again
6487 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
6489 LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m
, rr
));
6490 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
6491 // We set ProbeCount to one more than the usual value so we know we've already touched this record.
6492 // This is because our single probe for "example-name.local" could yield a response with (say) two A records and
6493 // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
6494 // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
6495 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
+ 1;
6496 rr
->AnnounceCount
= InitialAnnounceCount
;
6497 InitializeLastAPTime(m
, rr
);
6498 RecordProbeFailure(m
, rr
); // Repeated late conflicts also cause us to back off to the slower probing rate
6500 // If we're probing for this record, we just failed
6501 else if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
6503 LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr
->ProbeCount
, ARDisplayString(m
, rr
));
6504 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6506 // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
6507 // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
6508 else if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
6510 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m
, rr
));
6511 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6514 LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
6517 // Else, matching signature, different type or rdata, but not a considered a conflict.
6518 // If the packet record has the cache-flush bit set, then we check to see if we
6519 // have any record(s) of the same type that we should re-assert to rescue them
6520 // (see note about "multi-homing and bridged networks" at the end of this function).
6521 else if (m
->rec
.r
.resrec
.rrtype
== rr
->resrec
.rrtype
)
6522 if ((m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && m
->timenow
- rr
->LastMCTime
> mDNSPlatformOneSecond
/2)
6523 { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6528 if (!AcceptableResponse
)
6530 const CacheRecord
*cr
;
6531 for (cr
= CacheFlushRecords
; cr
!= (CacheRecord
*)1; cr
= cr
->NextInCFList
)
6533 domainname
*target
= GetRRDomainNameTarget(&cr
->resrec
);
6534 if (target
&& cr
->resrec
.rdatahash
== m
->rec
.r
.resrec
.namehash
&& SameDomainName(target
, m
->rec
.r
.resrec
.name
))
6535 { AcceptableResponse
= mDNStrue
; break; }
6539 // 2. See if we want to add this packet resource record to our cache
6540 // We only try to cache answers if we have a cache to put them in
6541 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
6542 if (!AcceptableResponse
) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m
, &m
->rec
.r
));
6543 if (m
->rrcache_size
&& AcceptableResponse
)
6545 const mDNSu32 slot
= HashSlot(m
->rec
.r
.resrec
.name
);
6546 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &m
->rec
.r
.resrec
);
6549 // 2a. Check if this packet resource record is already in our cache
6550 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6552 // If we found this exact resource record, refresh its TTL
6553 if (rr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6555 if (m
->rec
.r
.resrec
.rdlength
> InlineCacheRDSize
)
6556 verbosedebugf("Found record size %5d interface %p already in cache: %s",
6557 m
->rec
.r
.resrec
.rdlength
, InterfaceID
, CRDisplayString(m
, &m
->rec
.r
));
6558 rr
->TimeRcvd
= m
->timenow
;
6560 if (m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
)
6562 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
6563 if (rr
->NextInCFList
== mDNSNULL
&& cfp
!= &rr
->NextInCFList
&& LLQType
!= uDNS_LLQ_Events
)
6564 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6566 // If this packet record is marked unique, and our previous cached copy was not, then fix it
6567 if (!(rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))
6570 for (q
= m
->Questions
; q
; q
=q
->next
) if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
)) q
->UniqueAnswers
++;
6571 rr
->resrec
.RecordType
= m
->rec
.r
.resrec
.RecordType
;
6575 if (!mDNSPlatformMemSame(m
->rec
.r
.resrec
.rdata
->u
.data
, rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
))
6577 // If the rdata of the packet record differs in name capitalization from the record in our cache
6578 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
6579 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
6580 rr
->resrec
.rroriginalttl
= 0;
6581 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6582 SetNextCacheCheckTime(m
, rr
);
6583 // DO NOT break out here -- we want to continue as if we never found it
6585 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0)
6587 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
6588 RefreshCacheRecord(m
, rr
, m
->rec
.r
.resrec
.rroriginalttl
);
6593 // If the packet TTL is zero, that means we're deleting this record.
6594 // To give other hosts on the network a chance to protest, we push the deletion
6595 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
6596 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
6597 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
6598 debugf("DE for %s", CRDisplayString(m
, rr
));
6599 rr
->resrec
.rroriginalttl
= 1;
6600 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6601 SetNextCacheCheckTime(m
, rr
);
6607 // If packet resource record not in our cache, add it now
6608 // (unless it is just a deletion of a record we never had, in which case we don't care)
6609 if (!rr
&& m
->rec
.r
.resrec
.rroriginalttl
> 0)
6611 rr
= CreateNewCacheEntry(m
, slot
, cg
);
6612 if (rr
&& (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && LLQType
!= uDNS_LLQ_Events
)
6613 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6616 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6620 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6622 // If we've just received one or more records with their cache flush bits set,
6623 // then scan that cache slot to see if there are any old stale records we need to flush
6624 while (CacheFlushRecords
!= (CacheRecord
*)1)
6626 CacheRecord
*r1
= CacheFlushRecords
, *r2
;
6627 const mDNSu32 slot
= HashSlot(r1
->resrec
.name
);
6628 const CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &r1
->resrec
);
6629 CacheFlushRecords
= CacheFlushRecords
->NextInCFList
;
6630 r1
->NextInCFList
= mDNSNULL
;
6632 // Look for records in the cache with the same signature as this new one with the cache flush
6633 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
6634 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
6635 // We make these TTL adjustments *only* for records that still have *more* than one second
6636 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
6637 // (and now has half a second remaining) could inadvertently get its life extended, by either
6638 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
6639 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
6640 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
6641 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
6642 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
6643 // To avoid this, we need to ensure that the cache flushing operation will only act to
6644 // *decrease* a record's remaining lifetime, never *increase* it.
6645 for (r2
= cg
? cg
->members
: mDNSNULL
; r2
; r2
=r2
->next
)
6646 if (r1
->resrec
.InterfaceID
== r2
->resrec
.InterfaceID
&&
6647 r1
->resrec
.rrtype
== r2
->resrec
.rrtype
&&
6648 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
)
6650 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
6651 // else, if record is old, mark it to be flushed
6652 if (m
->timenow
- r2
->TimeRcvd
< mDNSPlatformOneSecond
&& RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6654 // If we find mismatched TTLs in an RRSet, correct them.
6655 // We only do this for records with a TTL of 2 or higher. It's possible to have a
6656 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
6657 // which we treat as a goodbye followed by an addition) and in that case it would be
6658 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
6659 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
6660 // because certain early Bonjour devices are known to have this specific mismatch, and
6661 // there's no point filling syslog with messages about something we already know about.
6662 // We also don't log this for uDNS responses, since a caching name server is obliged
6663 // to give us an aged TTL to correct for how long it has held the record,
6664 // so our received TTLs are expected to vary in that case
6665 if (r2
->resrec
.rroriginalttl
!= r1
->resrec
.rroriginalttl
&& r1
->resrec
.rroriginalttl
> 1)
6667 if (!(r2
->resrec
.rroriginalttl
== 240 && r1
->resrec
.rroriginalttl
== 60 && r2
->resrec
.rrtype
== kDNSType_TXT
) &&
6668 mDNSOpaque16IsZero(response
->h
.id
))
6669 LogInfo("Correcting TTL from %4d to %4d for %s",
6670 r2
->resrec
.rroriginalttl
, r1
->resrec
.rroriginalttl
, CRDisplayString(m
, r2
));
6671 r2
->resrec
.rroriginalttl
= r1
->resrec
.rroriginalttl
;
6673 r2
->TimeRcvd
= m
->timenow
;
6675 else // else, if record is old, mark it to be flushed
6677 verbosedebugf("Cache flush %p X %p %s", r1
, r2
, CRDisplayString(m
, r2
));
6678 // We set stale records to expire in one second.
6679 // This gives the owner a chance to rescue it if necessary.
6680 // This is important in the case of multi-homing and bridged networks:
6681 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
6682 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
6683 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
6684 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
6685 // By delaying the deletion by one second, we give X a change to notice that this bridging has
6686 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
6688 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
6689 // final expiration queries for this record.
6691 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
6692 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
6693 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
6694 if (r2
->TimeRcvd
== m
->timenow
&& r2
->resrec
.rroriginalttl
<= 1 && r2
->UnansweredQueries
== MaxUnansweredQueries
)
6696 debugf("Cache flush for DE record %s", CRDisplayString(m
, r2
));
6697 r2
->resrec
.rroriginalttl
= 0;
6698 m
->NextCacheCheck
= m
->timenow
;
6699 m
->NextScheduledEvent
= m
->timenow
;
6701 else if (RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6703 // We only set a record to expire in one second if it currently has *more* than a second to live
6704 // If it's already due to expire in a second or less, we just leave it alone
6705 r2
->resrec
.rroriginalttl
= 1;
6706 r2
->UnansweredQueries
= MaxUnansweredQueries
;
6707 r2
->TimeRcvd
= m
->timenow
- 1;
6708 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
6709 // that we marked for deletion via an explicit DE record
6712 SetNextCacheCheckTime(m
, r2
);
6714 if (r1
->DelayDelivery
) // If we were planning to delay delivery of this record, see if we still need to
6716 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
6717 r1
->DelayDelivery
= CheckForSoonToExpireRecords(m
, r1
->resrec
.name
, r1
->resrec
.namehash
, slot
);
6718 if (!r1
->DelayDelivery
) CacheRecordDeferredAdd(m
, r1
);
6722 // See if we need to generate negative cache entries for unanswered unicast questions
6723 ptr
= response
->data
;
6724 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6727 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6728 if (ptr
&& (!dstaddr
|| ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
)))
6730 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
6731 // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
6732 // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
6733 // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
6734 // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
6735 // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
6736 // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
6737 // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
6738 // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
6739 // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
6740 if (!InterfaceID
&& q
.qtype
!= kDNSType_SOA
&& IsLocalDomain(&q
.qname
))
6741 LogInfo("Not generating negative cache entry for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
6744 CacheRecord
*rr
, *neg
= mDNSNULL
;
6745 mDNSu32 slot
= HashSlot(&q
.qname
);
6746 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6747 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6748 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6750 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
6751 if (rr
->TimeRcvd
+ TicksTTL(rr
) - m
->timenow
> 0) break;
6752 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
6753 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
) neg
= rr
;
6758 // We start off assuming a negative caching TTL of 60 seconds
6759 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
6760 mDNSu32 negttl
= 60;
6762 const domainname
*name
= &q
.qname
;
6763 mDNSu32 hash
= q
.qnamehash
;
6765 // Special case for our special Microsoft Active Directory "local SOA" check.
6766 // Some cheap home gateways don't include an SOA record in the authority section when
6767 // they send negative responses, so we don't know how long to cache the negative result.
6768 // Because we don't want to keep hitting the root name servers with our query to find
6769 // if we're on a network using Microsoft Active Directory using "local" as a private
6770 // internal top-level domain, we make sure to cache the negative result for at least one day.
6771 if (q
.qtype
== kDNSType_SOA
&& SameDomainName(&q
.qname
, &localdomain
)) negttl
= 60 * 60 * 24;
6773 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
6774 if (response
->h
.numAuthorities
&& (ptr
= LocateAuthorities(response
, end
)) != mDNSNULL
)
6776 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
6777 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_SOA
)
6779 const rdataSOA
*const soa
= (const rdataSOA
*)m
->rec
.r
.resrec
.rdata
->u
.data
;
6780 mDNSu32 ttl_s
= soa
->min
;
6781 // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
6782 // for the SOA record for ".", where the record is reported as non-cacheable
6783 // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
6784 if (ttl_s
> m
->rec
.r
.resrec
.rroriginalttl
&& m
->rec
.r
.resrec
.name
->c
[0])
6785 ttl_s
= m
->rec
.r
.resrec
.rroriginalttl
;
6786 if (negttl
< ttl_s
) negttl
= ttl_s
;
6788 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
6789 // with an Authority Section SOA record for d.com, then this is a hint that the authority
6790 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
6791 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
6792 if (q
.qtype
== kDNSType_SOA
)
6794 int qcount
= CountLabels(&q
.qname
);
6795 int scount
= CountLabels(m
->rec
.r
.resrec
.name
);
6796 if (qcount
- 1 > scount
)
6797 if (SameDomainName(SkipLeadingLabels(&q
.qname
, qcount
- scount
), m
->rec
.r
.resrec
.name
))
6798 repeat
= qcount
- 1 - scount
;
6801 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6804 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
6805 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
6806 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
6807 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
6808 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
6809 // so that we back off our polling rate and don't keep hitting the server continually.
6812 if (negttl
< neg
->resrec
.rroriginalttl
* 2)
6813 negttl
= neg
->resrec
.rroriginalttl
* 2;
6818 negttl
= GetEffectiveTTL(LLQType
, negttl
); // Add 25% grace period if necessary
6820 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
6823 debugf("Renewing negative TTL from %d to %d %s", neg
->resrec
.rroriginalttl
, negttl
, CRDisplayString(m
, neg
));
6824 RefreshCacheRecord(m
, neg
, negttl
);
6828 debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl
, name
->c
, DNSTypeName(q
.qtype
));
6829 MakeNegativeCacheRecord(m
, &m
->rec
.r
, name
, hash
, q
.qtype
, q
.qclass
, negttl
, mDNSInterface_Any
);
6830 CreateNewCacheEntry(m
, slot
, cg
);
6831 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6834 name
= (const domainname
*)(name
->c
+ 1 + name
->c
[0]);
6835 hash
= DomainNameHashValue(name
);
6836 slot
= HashSlot(name
);
6837 cg
= CacheGroupForName(m
, slot
, hash
, name
);
6845 mDNSlocal
void SPSRecordCallback(mDNS
*const m
, AuthRecord
*const ar
, mStatus result
)
6847 if (result
&& result
!= mStatus_MemFree
)
6848 LogInfo("SPS Callback %d %s", result
, ARDisplayString(m
, ar
));
6850 if (result
== mStatus_NameConflict
)
6852 LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
6853 InterfaceNameForID(m
, ar
->resrec
.InterfaceID
), &ar
->WakeUp
.HMAC
, ARDisplayString(m
, ar
));
6854 SendWakeup(m
, ar
->resrec
.InterfaceID
, &ar
->WakeUp
.IMAC
, &ar
->WakeUp
.password
);
6856 else if (result
== mStatus_MemFree
)
6859 mDNSPlatformMemFree(ar
);
6863 mDNSlocal
void mDNSCoreReceiveUpdate(mDNS
*const m
,
6864 const DNSMessage
*const msg
, const mDNSu8
*end
,
6865 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6866 const mDNSInterfaceID InterfaceID
)
6870 mDNSu8
*p
= m
->omsg
.data
;
6872 mDNSu32 updatelease
= 0;
6875 LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6876 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6877 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6878 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6879 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6880 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6881 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6883 if (!InterfaceID
|| !m
->SPSSocket
|| !mDNSSameIPPort(dstport
, m
->SPSSocket
->port
)) return;
6885 if (mDNS_PacketLoggingEnabled
)
6886 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
6888 ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
+ DNSOpt_OwnerData_ID_Space
);
6891 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
6892 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
6895 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
6896 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
6898 if (o
->opt
== kDNSOpt_Lease
) updatelease
= o
->u
.updatelease
;
6899 else if (o
->opt
== kDNSOpt_Owner
&& o
->u
.owner
.vers
== 0) owner
= o
->u
.owner
;
6902 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6905 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, UpdateRespFlags
);
6907 if (!updatelease
|| !owner
.HMAC
.l
[0])
6909 static int msgs
= 0;
6913 LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr
, mDNSVal16(srcport
),
6914 !updatelease
? " No lease" : "", !owner
.HMAC
.l
[0] ? " No owner" : "");
6916 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_FormErr
;
6918 else if (m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
> MAX_PROXY_RECORDS
)
6920 static int msgs
= 0;
6924 LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr
, mDNSVal16(srcport
),
6925 m
->ProxyRecords
, msg
->h
.mDNS_numUpdates
, m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
, MAX_PROXY_RECORDS
);
6927 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
;
6931 LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner
.HMAC
, &owner
.IMAC
, &owner
.password
, owner
.seq
);
6933 if (updatelease
> 24 * 60 * 60)
6934 updatelease
= 24 * 60 * 60;
6936 if (updatelease
> 0x40000000UL
/ mDNSPlatformOneSecond
)
6937 updatelease
= 0x40000000UL
/ mDNSPlatformOneSecond
;
6939 ptr
= LocateAuthorities(msg
, end
);
6940 for (i
= 0; i
< msg
->h
.mDNS_numUpdates
&& ptr
&& ptr
< end
; i
++)
6942 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
6945 mDNSu16 RDLengthMem
= GetRDLengthMem(&m
->rec
.r
.resrec
);
6946 AuthRecord
*ar
= mDNSPlatformMemAllocate(sizeof(AuthRecord
) - sizeof(RDataBody
) + RDLengthMem
);
6947 if (!ar
) { m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
; break; }
6950 mDNSu8 RecordType
= m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
? kDNSRecordTypeUnique
: kDNSRecordTypeShared
;
6951 m
->rec
.r
.resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
;
6952 mDNS_SetupResourceRecord(ar
, mDNSNULL
, InterfaceID
, m
->rec
.r
.resrec
.rrtype
, m
->rec
.r
.resrec
.rroriginalttl
, RecordType
, SPSRecordCallback
, ar
);
6953 AssignDomainName(&ar
->namestorage
, m
->rec
.r
.resrec
.name
);
6954 ar
->resrec
.rdlength
= GetRDLength(&m
->rec
.r
.resrec
, mDNSfalse
);
6955 ar
->resrec
.rdata
->MaxRDLength
= RDLengthMem
;
6956 mDNSPlatformMemCopy(ar
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, RDLengthMem
);
6958 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_PTR
)
6960 mDNSs32 t
= ReverseMapDomainType(m
->rec
.r
.resrec
.name
);
6961 if (t
== mDNSAddrType_IPv4
) GetIPv4FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
6962 else if (t
== mDNSAddrType_IPv6
) GetIPv6FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
6963 debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t
, ar
->AddressProxy
.type
, &ar
->AddressProxy
, ARDisplayString(m
, ar
));
6964 if (ar
->AddressProxy
.type
) SetSPSProxyListChanged(InterfaceID
);
6966 ar
->TimeRcvd
= m
->timenow
;
6967 ar
->TimeExpire
= m
->timenow
+ updatelease
* mDNSPlatformOneSecond
;
6968 if (m
->NextScheduledSPS
- ar
->TimeExpire
> 0)
6969 m
->NextScheduledSPS
= ar
->TimeExpire
;
6970 mDNS_Register_internal(m
, ar
);
6971 // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
6972 if (ar
->resrec
.rrtype
== kDNSType_AAAA
) ar
->resrec
.rroriginalttl
= 0;
6974 LogSPS("SPS Registered %4d %X %s", m
->ProxyRecords
, RecordType
, ARDisplayString(m
,ar
));
6977 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6980 if (m
->omsg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)
6982 LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr
, mDNSVal16(srcport
));
6983 ClearProxyRecords(m
, &owner
, m
->DuplicateRecords
);
6984 ClearProxyRecords(m
, &owner
, m
->ResourceRecords
);
6988 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
6989 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
6990 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
6991 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
6992 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
6993 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= updatelease
;
6994 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
6998 if (p
) mDNSSendDNSMessage(m
, &m
->omsg
, p
, InterfaceID
, m
->SPSSocket
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
7001 mDNSlocal
void mDNSCoreReceiveUpdateR(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
)
7006 mDNSu32 updatelease
= 60 * 60; // If SPS fails to indicate lease time, assume one hour
7007 const mDNSu8
*ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
);
7010 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
7011 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
7014 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
7015 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
7016 if (o
->opt
== kDNSOpt_Lease
)
7018 updatelease
= o
->u
.updatelease
;
7019 LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease
);
7022 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
7025 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7026 if (rr
->resrec
.InterfaceID
== InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
7027 if (mDNSSameOpaque16(rr
->updateid
, msg
->h
.id
))
7029 rr
->updateid
= zeroID
;
7030 rr
->expire
= NonZeroTime(m
->timenow
+ updatelease
* mDNSPlatformOneSecond
);
7031 LogSPS("Sleep Proxy registered record %5d %s", updatelease
, ARDisplayString(m
,rr
));
7035 // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
7036 // may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
7037 if (m
->SleepLimit
) m
->NextScheduledSPRetry
= m
->timenow
;
7040 mDNSexport
void MakeNegativeCacheRecord(mDNS
*const m
, CacheRecord
*const cr
,
7041 const domainname
*const name
, const mDNSu32 namehash
, const mDNSu16 rrtype
, const mDNSu16 rrclass
, mDNSu32 ttl_seconds
, mDNSInterfaceID InterfaceID
)
7043 if (cr
== &m
->rec
.r
&& m
->rec
.r
.resrec
.RecordType
)
7045 LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m
, &m
->rec
.r
));
7051 // Create empty resource record
7052 cr
->resrec
.RecordType
= kDNSRecordTypePacketNegative
;
7053 cr
->resrec
.InterfaceID
= InterfaceID
;
7054 cr
->resrec
.name
= name
; // Will be updated to point to cg->name when we call CreateNewCacheEntry
7055 cr
->resrec
.rrtype
= rrtype
;
7056 cr
->resrec
.rrclass
= rrclass
;
7057 cr
->resrec
.rroriginalttl
= ttl_seconds
;
7058 cr
->resrec
.rdlength
= 0;
7059 cr
->resrec
.rdestimate
= 0;
7060 cr
->resrec
.namehash
= namehash
;
7061 cr
->resrec
.rdatahash
= 0;
7062 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
7063 cr
->resrec
.rdata
->MaxRDLength
= 0;
7065 cr
->NextInKAList
= mDNSNULL
;
7066 cr
->TimeRcvd
= m
->timenow
;
7067 cr
->DelayDelivery
= 0;
7068 cr
->NextRequiredQuery
= m
->timenow
;
7069 cr
->LastUsed
= m
->timenow
;
7070 cr
->CRActiveQuestion
= mDNSNULL
;
7071 cr
->UnansweredQueries
= 0;
7072 cr
->LastUnansweredTime
= 0;
7073 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
7074 cr
->MPUnansweredQ
= 0;
7075 cr
->MPLastUnansweredQT
= 0;
7076 cr
->MPUnansweredKA
= 0;
7077 cr
->MPExpectingKA
= mDNSfalse
;
7079 cr
->NextInCFList
= mDNSNULL
;
7082 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, void *const pkt
, const mDNSu8
*const end
,
7083 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
,
7084 const mDNSInterfaceID InterfaceID
)
7086 mDNSInterfaceID ifid
= InterfaceID
;
7087 DNSMessage
*msg
= (DNSMessage
*)pkt
;
7088 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
7089 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
7090 const mDNSu8 UpdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_Update
;
7091 const mDNSu8 UpdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
7093 mDNSu8
*ptr
= mDNSNULL
;
7094 mDNSBool TLS
= (dstaddr
== (mDNSAddr
*)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
7095 if (TLS
) dstaddr
= mDNSNULL
;
7097 #ifndef UNICAST_DISABLED
7098 if (mDNSSameAddress(srcaddr
, &m
->Router
))
7100 #ifdef _LEGACY_NAT_TRAVERSAL_
7101 if (mDNSSameIPPort(srcport
, SSDPPort
) || (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)))
7104 LNT_ConfigureRouterInfo(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7109 if (mDNSSameIPPort(srcport
, NATPMPPort
))
7112 uDNS_ReceiveNATPMPPacket(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7117 #ifdef _LEGACY_NAT_TRAVERSAL_
7118 else if (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr
, mDNSVal16(srcport
)); return; }
7122 if ((unsigned)(end
- (mDNSu8
*)pkt
) < sizeof(DNSMessageHeader
)) { LogMsg("DNS Message too short"); return; }
7123 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
7124 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
7125 ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
7126 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
7127 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
7128 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
7129 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
7131 if (!m
) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
7133 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
7134 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
7135 if (srcaddr
&& !mDNSAddressIsValid(srcaddr
)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr
); return; }
7139 #ifndef UNICAST_DISABLED
7140 if (!dstaddr
|| (!mDNSAddressIsAllDNSLinkGroup(dstaddr
) && (QR_OP
== StdR
|| QR_OP
== UpdR
)))
7141 if (!mDNSOpaque16IsZero(msg
->h
.id
)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
7143 ifid
= mDNSInterface_Any
;
7144 if (mDNS_PacketLoggingEnabled
)
7145 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, TLS
? "TLS" : !dstaddr
? "TCP" : "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
7146 uDNS_ReceiveMsg(m
, msg
, end
, srcaddr
, srcport
);
7147 // Note: mDNSCore also needs to get access to received unicast responses
7150 if (QR_OP
== StdQ
) mDNSCoreReceiveQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7151 else if (QR_OP
== StdR
) mDNSCoreReceiveResponse(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7152 else if (QR_OP
== UpdQ
) mDNSCoreReceiveUpdate (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
);
7153 else if (QR_OP
== UpdR
) mDNSCoreReceiveUpdateR (m
, msg
, end
, InterfaceID
);
7156 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
7157 msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1], srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
-(mDNSu8
*)pkt
, InterfaceID
);
7158 if (mDNS_LoggingEnabled
)
7161 while (i
<end
-(mDNSu8
*)pkt
)
7164 char *p
= buffer
+ mDNS_snprintf(buffer
, sizeof(buffer
), "%04X", i
);
7165 do if (i
<end
-(mDNSu8
*)pkt
) p
+= mDNS_snprintf(p
, sizeof(buffer
), " %02X", ((mDNSu8
*)pkt
)[i
]); while (++i
& 15);
7166 LogInfo("%s", buffer
);
7170 // Packet reception often causes a change to the task list:
7171 // 1. Inbound queries can cause us to need to send responses
7172 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
7173 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
7174 // 4. Response packets that answer questions may cause our client to issue new questions
7178 // ***************************************************************************
7179 #if COMPILER_LIKES_PRAGMA_MARK
7181 #pragma mark - Searcher Functions
7184 // Targets are considered the same if both queries are untargeted, or
7185 // if both are targeted to the same address+port
7186 // (If Target address is zero, TargetPort is undefined)
7187 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
7188 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
7190 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
7191 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
7192 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
7193 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
7194 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
7196 // If IsLLQ(Q) is true, it means the question is both:
7197 // (a) long-lived and
7198 // (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
7199 // for multicast questions, we don't want to treat LongLived as anything special
7200 #define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
7202 mDNSlocal DNSQuestion
*FindDuplicateQuestion(const mDNS
*const m
, const DNSQuestion
*const question
)
7205 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
7206 // This prevents circular references, where two questions are each marked as a duplicate of the other.
7207 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
7208 // further in the list.
7209 for (q
= m
->Questions
; q
&& q
!= question
; q
=q
->next
) // Scan our list for another question
7210 if (q
->InterfaceID
== question
->InterfaceID
&& // with the same InterfaceID,
7211 SameQTarget(q
, question
) && // and same unicast/multicast target settings
7212 q
->qtype
== question
->qtype
&& // type,
7213 q
->qclass
== question
->qclass
&& // class,
7214 IsLLQ(q
) == IsLLQ(question
) && // and long-lived status matches
7215 (!q
->AuthInfo
|| question
->AuthInfo
) && // to avoid deadlock, don't make public query dup of a private one
7216 q
->qnamehash
== question
->qnamehash
&&
7217 SameDomainName(&q
->qname
, &question
->qname
)) // and name
7222 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
7223 mDNSlocal
void UpdateQuestionDuplicates(mDNS
*const m
, DNSQuestion
*const question
)
7226 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7227 if (q
->DuplicateOf
== question
) // To see if any questions were referencing this as their duplicate
7228 if ((q
->DuplicateOf
= FindDuplicateQuestion(m
, q
)) == mDNSNULL
)
7230 // If q used to be a duplicate, but now is not,
7231 // then inherit the state from the question that's going away
7232 q
->LastQTime
= question
->LastQTime
;
7233 q
->ThisQInterval
= question
->ThisQInterval
;
7234 q
->ExpectUnicastResp
= question
->ExpectUnicastResp
;
7235 q
->LastAnswerPktNum
= question
->LastAnswerPktNum
;
7236 q
->RecentAnswerPkts
= question
->RecentAnswerPkts
;
7237 q
->RequestUnicast
= question
->RequestUnicast
;
7238 q
->LastQTxTime
= question
->LastQTxTime
;
7239 q
->CNAMEReferrals
= question
->CNAMEReferrals
;
7240 q
->nta
= question
->nta
;
7241 q
->servAddr
= question
->servAddr
;
7242 q
->servPort
= question
->servPort
;
7243 q
->qDNSServer
= question
->qDNSServer
;
7244 q
->unansweredQueries
= question
->unansweredQueries
;
7246 q
->TargetQID
= question
->TargetQID
;
7247 q
->LocalSocket
= question
->LocalSocket
;
7249 q
->state
= question
->state
;
7250 // q->tcp = question->tcp;
7251 q
->ReqLease
= question
->ReqLease
;
7252 q
->expire
= question
->expire
;
7253 q
->ntries
= question
->ntries
;
7254 q
->id
= question
->id
;
7256 question
->LocalSocket
= mDNSNULL
;
7257 question
->nta
= mDNSNULL
; // If we've got a GetZoneData in progress, transfer it to the newly active question
7258 // question->tcp = mDNSNULL;
7261 debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7265 LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7266 q
->nta
->ZoneDataContext
= q
;
7269 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
7270 if (question
->tcp
) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
7272 if (question
->state
== LLQ_Established
)
7274 LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7275 question
->state
= 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
7278 SetNextQueryTime(m
,q
);
7282 // Look up a DNS Server, matching by name in split-dns configurations.
7283 mDNSexport DNSServer
*GetServerForName(mDNS
*m
, const domainname
*name
)
7285 DNSServer
*curmatch
= mDNSNULL
, *p
;
7286 int curmatchlen
= -1, ncount
= name
? CountLabels(name
) : 0;
7288 for (p
= m
->DNSServers
; p
; p
= p
->next
)
7290 int scount
= CountLabels(&p
->domain
);
7291 if (!(p
->flags
& DNSServer_FlagDelete
) && ncount
>= scount
&& scount
> curmatchlen
)
7292 if (SameDomainName(SkipLeadingLabels(name
, ncount
- scount
), &p
->domain
))
7293 { curmatch
= p
; curmatchlen
= scount
; }
7298 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
7299 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
7301 // Called in normal client context (lock not held)
7302 mDNSlocal
void LLQNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
7307 LogInfo("LLQNATCallback external address:port %.4a:%u", &n
->ExternalAddress
, mDNSVal16(n
->ExternalPort
));
7308 for (q
= m
->Questions
; q
; q
=q
->next
)
7309 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
)
7310 startLLQHandshake(m
, q
); // If ExternalPort is zero, will do StartLLQPolling instead
7311 #if APPLE_OSX_mDNSResponder
7312 UpdateAutoTunnelDomainStatuses(m
);
7317 mDNSexport mStatus
mDNS_StartQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7319 if (question
->Target
.type
&& !ValidQuestionTarget(question
))
7321 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
7322 question
->Target
.type
, mDNSVal16(question
->TargetPort
));
7323 question
->Target
.type
= mDNSAddrType_None
;
7326 if (!question
->Target
.type
) question
->TargetPort
= zeroIPPort
; // If question->Target specified clear TargetPort
7328 question
->TargetQID
=
7329 #ifndef UNICAST_DISABLED
7330 (question
->Target
.type
|| (question
->InterfaceID
== mDNSInterface_Unicast
) ||
7331 (question
->InterfaceID
!= mDNSInterface_LocalOnly
&& !question
->ForceMCast
&& !IsLocalDomain(&question
->qname
)))
7332 ? mDNS_NewMessageID(m
) :
7333 #endif // UNICAST_DISABLED
7336 debugf("mDNS_StartQuery: %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7338 if (m
->rrcache_size
== 0) // Can't do queries if we have no cache space allocated
7339 return(mStatus_NoCache
);
7345 if (!ValidateDomainName(&question
->qname
))
7347 LogMsg("Attempt to start query with invalid qname %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7348 return(mStatus_Invalid
);
7351 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
7353 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) q
= &m
->LocalOnlyQuestions
;
7354 while (*q
&& *q
!= question
) q
=&(*q
)->next
;
7358 LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
7359 question
->qname
.c
, DNSTypeName(question
->qtype
), question
);
7360 return(mStatus_AlreadyRegistered
);
7365 // If this question is referencing a specific interface, verify it exists
7366 if (question
->InterfaceID
&& question
->InterfaceID
!= mDNSInterface_LocalOnly
&& question
->InterfaceID
!= mDNSInterface_Unicast
)
7368 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, question
->InterfaceID
);
7370 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
7371 question
->InterfaceID
, question
->qname
.c
, DNSTypeName(question
->qtype
));
7374 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
7375 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
7376 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
7377 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
7378 // that to go out immediately.
7379 question
->next
= mDNSNULL
;
7380 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // MUST do this before FindDuplicateQuestion()
7381 question
->DelayAnswering
= CheckForSoonToExpireRecords(m
, &question
->qname
, question
->qnamehash
, HashSlot(&question
->qname
));
7382 question
->LastQTime
= m
->timenow
;
7383 question
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
7384 question
->ExpectUnicastResp
= 0;
7385 question
->LastAnswerPktNum
= m
->PktNum
;
7386 question
->RecentAnswerPkts
= 0;
7387 question
->CurrentAnswers
= 0;
7388 question
->LargeAnswers
= 0;
7389 question
->UniqueAnswers
= 0;
7390 question
->FlappingInterface1
= mDNSNULL
;
7391 question
->FlappingInterface2
= mDNSNULL
;
7392 question
->AuthInfo
= GetAuthInfoForQuestion(m
, question
); // Must do this before calling FindDuplicateQuestion()
7393 question
->DuplicateOf
= FindDuplicateQuestion(m
, question
);
7394 question
->NextInDQList
= mDNSNULL
;
7395 question
->SendQNow
= mDNSNULL
;
7396 question
->SendOnAll
= mDNSfalse
;
7397 question
->RequestUnicast
= 0;
7398 question
->LastQTxTime
= m
->timenow
;
7399 question
->CNAMEReferrals
= 0;
7401 // We'll create our question->LocalSocket on demand, if needed.
7402 // We won't need one for duplicate questions, or from questions answered immediately out of the cache.
7403 // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
7404 // NAT mapping for receiving inbound add/remove events.
7405 question
->LocalSocket
= mDNSNULL
;
7406 question
->qDNSServer
= mDNSNULL
;
7407 question
->unansweredQueries
= 0;
7408 question
->nta
= mDNSNULL
;
7409 question
->servAddr
= zeroAddr
;
7410 question
->servPort
= zeroIPPort
;
7411 question
->tcp
= mDNSNULL
;
7412 question
->NoAnswer
= NoAnswer_Normal
;
7414 question
->state
= LLQ_InitialRequest
;
7415 question
->ReqLease
= 0;
7416 question
->expire
= 0;
7417 question
->ntries
= 0;
7418 question
->id
= zeroOpaque64
;
7420 if (question
->DuplicateOf
) question
->AuthInfo
= question
->DuplicateOf
->AuthInfo
;
7422 for (i
=0; i
<DupSuppressInfoSize
; i
++)
7423 question
->DupSuppress
[i
].InterfaceID
= mDNSNULL
;
7425 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
7426 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->InterfaceID
, m
->timenow
,
7427 question
->LastQTime
+ question
->ThisQInterval
- m
->timenow
,
7428 question
->DelayAnswering
? question
->DelayAnswering
- m
->timenow
: 0,
7429 question
, question
->DuplicateOf
? "duplicate of" : "not duplicate", question
->DuplicateOf
);
7431 if (question
->InterfaceID
== mDNSInterface_LocalOnly
)
7433 if (!m
->NewLocalOnlyQuestions
) m
->NewLocalOnlyQuestions
= question
;
7437 if (!m
->NewQuestions
) m
->NewQuestions
= question
;
7439 // If the question's id is non-zero, then it's Wide Area
7440 // MUST NOT do this Wide Area setup until near the end of
7441 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
7442 // NS, etc.) and if we haven't finished setting up our own question and setting
7443 // m->NewQuestions if necessary then we could end up recursively re-entering
7444 // this routine with the question list data structures in an inconsistent state.
7445 if (!mDNSOpaque16IsZero(question
->TargetQID
))
7447 question
->qDNSServer
= GetServerForName(m
, &question
->qname
);
7448 ActivateUnicastQuery(m
, question
, mDNSfalse
);
7450 // If long-lived query, and we don't have our NAT mapping active, start it now
7451 if (question
->LongLived
&& !m
->LLQNAT
.clientContext
)
7453 m
->LLQNAT
.Protocol
= NATOp_MapUDP
;
7454 m
->LLQNAT
.IntPort
= m
->UnicastPort4
;
7455 m
->LLQNAT
.RequestedPort
= m
->UnicastPort4
;
7456 m
->LLQNAT
.clientCallback
= LLQNATCallback
;
7457 m
->LLQNAT
.clientContext
= (void*)1; // Means LLQ NAT Traversal is active
7458 mDNS_StartNATOperation_internal(m
, &m
->LLQNAT
);
7461 #if APPLE_OSX_mDNSResponder
7462 if (question
->LongLived
)
7463 UpdateAutoTunnelDomainStatuses(m
);
7467 SetNextQueryTime(m
,question
);
7470 return(mStatus_NoError
);
7474 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
7475 mDNSexport
void CancelGetZoneData(mDNS
*const m
, ZoneData
*nta
)
7477 debugf("CancelGetZoneData %##s (%s)", nta
->question
.qname
.c
, DNSTypeName(nta
->question
.qtype
));
7478 mDNS_StopQuery_internal(m
, &nta
->question
);
7479 mDNSPlatformMemFree(nta
);
7482 mDNSexport mStatus
mDNS_StopQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7484 const mDNSu32 slot
= HashSlot(&question
->qname
);
7485 CacheGroup
*cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7487 DNSQuestion
**qp
= &m
->Questions
;
7489 //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7491 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) qp
= &m
->LocalOnlyQuestions
;
7492 while (*qp
&& *qp
!= question
) qp
=&(*qp
)->next
;
7493 if (*qp
) *qp
= (*qp
)->next
;
7497 if (question
->ThisQInterval
>= 0) // Only log error message if the query was supposed to be active
7499 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
7500 question
->qname
.c
, DNSTypeName(question
->qtype
));
7504 return(mStatus_BadReferenceErr
);
7507 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
7508 UpdateQuestionDuplicates(m
, question
);
7509 // But don't trash ThisQInterval until afterwards.
7510 question
->ThisQInterval
= -1;
7512 // If there are any cache records referencing this as their active question, then see if there is any
7513 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
7514 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7516 if (rr
->CRActiveQuestion
== question
)
7519 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7520 if (ActiveQuestion(q
) && ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
7522 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
7523 rr
->CRActiveQuestion
= q
; // Question used to be active; new value may or may not be null
7524 if (!q
) m
->rrcache_active
--; // If no longer active, decrement rrcache_active count
7528 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
7529 // bump its pointer forward one question.
7530 if (m
->CurrentQuestion
== question
)
7532 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
7533 question
->qname
.c
, DNSTypeName(question
->qtype
));
7534 m
->CurrentQuestion
= question
->next
;
7537 if (m
->NewQuestions
== question
)
7539 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
7540 question
->qname
.c
, DNSTypeName(question
->qtype
));
7541 m
->NewQuestions
= question
->next
;
7544 if (m
->NewLocalOnlyQuestions
== question
) m
->NewLocalOnlyQuestions
= question
->next
;
7546 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
7547 question
->next
= mDNSNULL
;
7549 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
7551 // And finally, cancel any associated GetZoneData operation that's still running.
7552 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
7553 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
7554 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
7555 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
7556 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
7557 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
7558 if (question
->LocalSocket
) { mDNSPlatformUDPClose(question
->LocalSocket
); question
->LocalSocket
= mDNSNULL
; }
7559 if (!mDNSOpaque16IsZero(question
->TargetQID
) && question
->LongLived
)
7561 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
7563 for (q
= m
->Questions
; q
; q
=q
->next
)
7564 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
) break;
7567 if (!m
->LLQNAT
.clientContext
) // Should never happen, but just in case...
7568 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
7571 LogInfo("Stopping LLQNAT");
7572 mDNS_StopNATOperation_internal(m
, &m
->LLQNAT
);
7573 m
->LLQNAT
.clientContext
= mDNSNULL
; // Means LLQ NAT Traversal not running
7577 // If necessary, tell server it can delete this LLQ state
7578 if (question
->state
== LLQ_Established
)
7580 question
->ReqLease
= 0;
7581 sendLLQRefresh(m
, question
);
7582 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
7583 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
7584 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
7585 // we let that run out its natural course and complete asynchronously.
7588 question
->tcp
->question
= mDNSNULL
;
7589 question
->tcp
= mDNSNULL
;
7592 #if APPLE_OSX_mDNSResponder
7593 UpdateAutoTunnelDomainStatuses(m
);
7597 return(mStatus_NoError
);
7600 mDNSexport mStatus
mDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
7604 status
= mDNS_StartQuery_internal(m
, question
);
7609 mDNSexport mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
7613 status
= mDNS_StopQuery_internal(m
, question
);
7618 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
7619 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
7620 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
7621 // specifically to catch and report if the client callback does try to make API calls
7622 mDNSexport mStatus
mDNS_StopQueryWithRemoves(mDNS
*const m
, DNSQuestion
*const question
)
7628 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
7629 for (qq
= m
->NewQuestions
; qq
; qq
=qq
->next
) if (qq
== question
) break;
7631 status
= mDNS_StopQuery_internal(m
, question
);
7632 if (status
== mStatus_NoError
&& !qq
)
7634 const CacheRecord
*rr
;
7635 const mDNSu32 slot
= HashSlot(&question
->qname
);
7636 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7637 LogInfo("Generating terminal removes for %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7638 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7639 if (rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& SameNameRecordAnswersQuestion(&rr
->resrec
, question
))
7641 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
7642 if (question
->QuestionCallback
)
7643 question
->QuestionCallback(m
, question
, &rr
->resrec
, mDNSfalse
);
7650 mDNSexport mStatus
mDNS_Reconfirm(mDNS
*const m
, CacheRecord
*const cr
)
7654 status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7655 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7660 mDNSexport mStatus
mDNS_ReconfirmByValue(mDNS
*const m
, ResourceRecord
*const rr
)
7662 mStatus status
= mStatus_BadReferenceErr
;
7665 cr
= FindIdenticalRecordInCache(m
, rr
);
7666 debugf("mDNS_ReconfirmByValue: %p %s", cr
, RRDisplayString(m
, rr
));
7667 if (cr
) status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7668 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7673 mDNSlocal mStatus
mDNS_StartBrowse_internal(mDNS
*const m
, DNSQuestion
*const question
,
7674 const domainname
*const srv
, const domainname
*const domain
,
7675 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7677 question
->InterfaceID
= InterfaceID
;
7678 question
->Target
= zeroAddr
;
7679 question
->qtype
= kDNSType_PTR
;
7680 question
->qclass
= kDNSClass_IN
;
7681 question
->LongLived
= mDNSfalse
;
7682 question
->ExpectUnique
= mDNSfalse
;
7683 question
->ForceMCast
= ForceMCast
;
7684 question
->ReturnIntermed
= mDNSfalse
;
7685 question
->QuestionCallback
= Callback
;
7686 question
->QuestionContext
= Context
;
7687 if (!ConstructServiceName(&question
->qname
, mDNSNULL
, srv
, domain
)) return(mStatus_BadParamErr
);
7689 #ifndef UNICAST_DISABLED
7690 if (Question_uDNS(question
))
7692 question
->LongLived
= mDNStrue
;
7693 question
->ThisQInterval
= InitialQuestionInterval
;
7694 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
7696 #endif // UNICAST_DISABLED
7697 return(mDNS_StartQuery_internal(m
, question
));
7700 mDNSexport mStatus
mDNS_StartBrowse(mDNS
*const m
, DNSQuestion
*const question
,
7701 const domainname
*const srv
, const domainname
*const domain
,
7702 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7706 status
= mDNS_StartBrowse_internal(m
, question
, srv
, domain
, InterfaceID
, ForceMCast
, Callback
, Context
);
7711 mDNSlocal mDNSBool
MachineHasActiveIPv6(mDNS
*const m
)
7713 NetworkInterfaceInfo
*intf
;
7714 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
7715 if (intf
->ip
.type
== mDNSAddrType_IPv6
) return(mDNStrue
);
7719 mDNSlocal
void FoundServiceInfoSRV(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7721 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7722 mDNSBool PortChanged
= !mDNSSameIPPort(query
->info
->port
, answer
->rdata
->u
.srv
.port
);
7723 if (!AddRecord
) return;
7724 if (answer
->rrtype
!= kDNSType_SRV
) return;
7726 query
->info
->port
= answer
->rdata
->u
.srv
.port
;
7728 // If this is our first answer, then set the GotSRV flag and start the address query
7731 query
->GotSRV
= mDNStrue
;
7732 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
7733 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
7734 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
7735 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
7736 mDNS_StartQuery(m
, &query
->qAv4
);
7737 // Only do the AAAA query if this machine actually has IPv6 active
7738 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
7740 // If this is not our first answer, only re-issue the address query if the target host name has changed
7741 else if ((query
->qAv4
.InterfaceID
!= query
->qSRV
.InterfaceID
&& query
->qAv4
.InterfaceID
!= answer
->InterfaceID
) ||
7742 !SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
))
7744 mDNS_StopQuery(m
, &query
->qAv4
);
7745 if (query
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &query
->qAv6
);
7746 if (SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
) && !PortChanged
)
7748 // If we get here, it means:
7749 // 1. This is not our first SRV answer
7750 // 2. The interface ID is different, but the target host and port are the same
7751 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
7752 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
7753 query
->qAv4
.InterfaceID
= query
->qSRV
.InterfaceID
; // Will be mDNSInterface_Any, or a specific interface
7754 query
->qAv6
.InterfaceID
= query
->qSRV
.InterfaceID
;
7758 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
7759 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
7760 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
7761 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
7763 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query
->qAv4
.qname
.c
, DNSTypeName(query
->qAv4
.qtype
));
7764 mDNS_StartQuery(m
, &query
->qAv4
);
7765 // Only do the AAAA query if this machine actually has IPv6 active
7766 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
7768 else if (query
->ServiceInfoQueryCallback
&& query
->GotADD
&& query
->GotTXT
&& PortChanged
)
7770 if (++query
->Answers
>= 100)
7771 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
7772 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.srv
.target
.c
,
7773 mDNSVal16(answer
->rdata
->u
.srv
.port
));
7774 query
->ServiceInfoQueryCallback(m
, query
);
7776 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7777 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7780 mDNSlocal
void FoundServiceInfoTXT(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7782 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7783 if (!AddRecord
) return;
7784 if (answer
->rrtype
!= kDNSType_TXT
) return;
7785 if (answer
->rdlength
> sizeof(query
->info
->TXTinfo
)) return;
7787 query
->GotTXT
= mDNStrue
;
7788 query
->info
->TXTlen
= answer
->rdlength
;
7789 query
->info
->TXTinfo
[0] = 0; // In case answer->rdlength is zero
7790 mDNSPlatformMemCopy(query
->info
->TXTinfo
, answer
->rdata
->u
.txt
.c
, answer
->rdlength
);
7792 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query
->info
->name
.c
, query
->GotADD
);
7794 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7795 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7796 if (query
->ServiceInfoQueryCallback
&& query
->GotADD
)
7798 if (++query
->Answers
>= 100)
7799 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
7800 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.txt
.c
);
7801 query
->ServiceInfoQueryCallback(m
, query
);
7805 mDNSlocal
void FoundServiceInfo(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7807 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7808 //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
7809 if (!AddRecord
) return;
7811 if (answer
->rrtype
== kDNSType_A
)
7813 query
->info
->ip
.type
= mDNSAddrType_IPv4
;
7814 query
->info
->ip
.ip
.v4
= answer
->rdata
->u
.ipv4
;
7816 else if (answer
->rrtype
== kDNSType_AAAA
)
7818 query
->info
->ip
.type
= mDNSAddrType_IPv6
;
7819 query
->info
->ip
.ip
.v6
= answer
->rdata
->u
.ipv6
;
7823 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer
->name
->c
, answer
->rrtype
, DNSTypeName(answer
->rrtype
));
7827 query
->GotADD
= mDNStrue
;
7828 query
->info
->InterfaceID
= answer
->InterfaceID
;
7830 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query
->info
->ip
.type
, query
->info
->name
.c
, query
->GotTXT
);
7832 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7833 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7834 if (query
->ServiceInfoQueryCallback
&& query
->GotTXT
)
7836 if (++query
->Answers
>= 100)
7837 debugf(answer
->rrtype
== kDNSType_A
?
7838 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
7839 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
7840 query
->Answers
, query
->qSRV
.qname
.c
, &answer
->rdata
->u
.data
);
7841 query
->ServiceInfoQueryCallback(m
, query
);
7845 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
7846 // If the query is not interface-specific, then InterfaceID may be zero
7847 // Each time the Callback is invoked, the remainder of the fields will have been filled in
7848 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
7849 mDNSexport mStatus
mDNS_StartResolveService(mDNS
*const m
,
7850 ServiceInfoQuery
*query
, ServiceInfo
*info
, mDNSServiceInfoQueryCallback
*Callback
, void *Context
)
7855 query
->qSRV
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7856 query
->qSRV
.InterfaceID
= info
->InterfaceID
;
7857 query
->qSRV
.Target
= zeroAddr
;
7858 AssignDomainName(&query
->qSRV
.qname
, &info
->name
);
7859 query
->qSRV
.qtype
= kDNSType_SRV
;
7860 query
->qSRV
.qclass
= kDNSClass_IN
;
7861 query
->qSRV
.LongLived
= mDNSfalse
;
7862 query
->qSRV
.ExpectUnique
= mDNStrue
;
7863 query
->qSRV
.ForceMCast
= mDNSfalse
;
7864 query
->qSRV
.ReturnIntermed
= mDNSfalse
;
7865 query
->qSRV
.QuestionCallback
= FoundServiceInfoSRV
;
7866 query
->qSRV
.QuestionContext
= query
;
7868 query
->qTXT
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7869 query
->qTXT
.InterfaceID
= info
->InterfaceID
;
7870 query
->qTXT
.Target
= zeroAddr
;
7871 AssignDomainName(&query
->qTXT
.qname
, &info
->name
);
7872 query
->qTXT
.qtype
= kDNSType_TXT
;
7873 query
->qTXT
.qclass
= kDNSClass_IN
;
7874 query
->qTXT
.LongLived
= mDNSfalse
;
7875 query
->qTXT
.ExpectUnique
= mDNStrue
;
7876 query
->qTXT
.ForceMCast
= mDNSfalse
;
7877 query
->qTXT
.ReturnIntermed
= mDNSfalse
;
7878 query
->qTXT
.QuestionCallback
= FoundServiceInfoTXT
;
7879 query
->qTXT
.QuestionContext
= query
;
7881 query
->qAv4
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7882 query
->qAv4
.InterfaceID
= info
->InterfaceID
;
7883 query
->qAv4
.Target
= zeroAddr
;
7884 query
->qAv4
.qname
.c
[0] = 0;
7885 query
->qAv4
.qtype
= kDNSType_A
;
7886 query
->qAv4
.qclass
= kDNSClass_IN
;
7887 query
->qAv4
.LongLived
= mDNSfalse
;
7888 query
->qAv4
.ExpectUnique
= mDNStrue
;
7889 query
->qAv4
.ForceMCast
= mDNSfalse
;
7890 query
->qAv4
.ReturnIntermed
= mDNSfalse
;
7891 query
->qAv4
.QuestionCallback
= FoundServiceInfo
;
7892 query
->qAv4
.QuestionContext
= query
;
7894 query
->qAv6
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7895 query
->qAv6
.InterfaceID
= info
->InterfaceID
;
7896 query
->qAv6
.Target
= zeroAddr
;
7897 query
->qAv6
.qname
.c
[0] = 0;
7898 query
->qAv6
.qtype
= kDNSType_AAAA
;
7899 query
->qAv6
.qclass
= kDNSClass_IN
;
7900 query
->qAv6
.LongLived
= mDNSfalse
;
7901 query
->qAv6
.ExpectUnique
= mDNStrue
;
7902 query
->qAv6
.ForceMCast
= mDNSfalse
;
7903 query
->qAv6
.ReturnIntermed
= mDNSfalse
;
7904 query
->qAv6
.QuestionCallback
= FoundServiceInfo
;
7905 query
->qAv6
.QuestionContext
= query
;
7907 query
->GotSRV
= mDNSfalse
;
7908 query
->GotTXT
= mDNSfalse
;
7909 query
->GotADD
= mDNSfalse
;
7913 query
->ServiceInfoQueryCallback
= Callback
;
7914 query
->ServiceInfoQueryContext
= Context
;
7916 // info->name = Must already be set up by client
7917 // info->interface = Must already be set up by client
7918 info
->ip
= zeroAddr
;
7919 info
->port
= zeroIPPort
;
7922 // We use mDNS_StartQuery_internal here because we're already holding the lock
7923 status
= mDNS_StartQuery_internal(m
, &query
->qSRV
);
7924 if (status
== mStatus_NoError
) status
= mDNS_StartQuery_internal(m
, &query
->qTXT
);
7925 if (status
!= mStatus_NoError
) mDNS_StopResolveService(m
, query
);
7931 mDNSexport
void mDNS_StopResolveService (mDNS
*const m
, ServiceInfoQuery
*q
)
7934 // We use mDNS_StopQuery_internal here because we're already holding the lock
7935 if (q
->qSRV
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qSRV
);
7936 if (q
->qTXT
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qTXT
);
7937 if (q
->qAv4
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv4
);
7938 if (q
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv6
);
7942 mDNSexport mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
7943 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
7945 question
->InterfaceID
= InterfaceID
;
7946 question
->Target
= zeroAddr
;
7947 question
->qtype
= kDNSType_PTR
;
7948 question
->qclass
= kDNSClass_IN
;
7949 question
->LongLived
= mDNSfalse
;
7950 question
->ExpectUnique
= mDNSfalse
;
7951 question
->ForceMCast
= mDNSfalse
;
7952 question
->ReturnIntermed
= mDNSfalse
;
7953 question
->QuestionCallback
= Callback
;
7954 question
->QuestionContext
= Context
;
7955 if (DomainType
> mDNS_DomainTypeMax
) return(mStatus_BadParamErr
);
7956 if (!MakeDomainNameFromDNSNameString(&question
->qname
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
7957 if (!dom
) dom
= &localdomain
;
7958 if (!AppendDomainName(&question
->qname
, dom
)) return(mStatus_BadParamErr
);
7959 return(mDNS_StartQuery(m
, question
));
7962 // ***************************************************************************
7963 #if COMPILER_LIKES_PRAGMA_MARK
7965 #pragma mark - Responder Functions
7968 mDNSexport mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
)
7972 status
= mDNS_Register_internal(m
, rr
);
7977 mDNSexport mStatus
mDNS_Update(mDNS
*const m
, AuthRecord
*const rr
, mDNSu32 newttl
,
7978 const mDNSu16 newrdlength
, RData
*const newrdata
, mDNSRecordUpdateCallback
*Callback
)
7980 #ifndef UNICAST_DISABLED
7981 mDNSBool unicast
= !(rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(rr
->resrec
.name
));
7983 mDNSBool unicast
= mDNSfalse
;
7986 if (!ValidateRData(rr
->resrec
.rrtype
, newrdlength
, newrdata
))
7988 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr
->resrec
, &newrdata
->u
, m
->MsgBuffer
));
7989 return(mStatus_Invalid
);
7994 // If TTL is unspecified, leave TTL unchanged
7995 if (newttl
== 0) newttl
= rr
->resrec
.rroriginalttl
;
7997 // If we already have an update queued up which has not gone through yet,
7998 // give the client a chance to free that memory
7999 if (!unicast
&& rr
->NewRData
)
8001 RData
*n
= rr
->NewRData
;
8002 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
8003 if (rr
->UpdateCallback
)
8004 rr
->UpdateCallback(m
, rr
, n
); // ...and let the client free this memory, if necessary
8007 rr
->NewRData
= newrdata
;
8008 rr
->newrdlength
= newrdlength
;
8009 rr
->UpdateCallback
= Callback
;
8011 if (unicast
) { mStatus status
= uDNS_UpdateRecord(m
, rr
); mDNS_Unlock(m
); return(status
); }
8013 if (rr
->resrec
.rroriginalttl
== newttl
&&
8014 rr
->resrec
.rdlength
== newrdlength
&& mDNSPlatformMemSame(rr
->resrec
.rdata
->u
.data
, newrdata
->u
.data
, newrdlength
))
8015 CompleteRDataUpdate(m
, rr
);
8019 domainname type
, domain
;
8020 DeconstructServiceName(rr
->resrec
.name
, &name
, &type
, &domain
);
8021 rr
->AnnounceCount
= InitialAnnounceCount
;
8022 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
8023 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
8024 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
8025 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
8026 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
8027 if (SameDomainLabel(type
.c
, (mDNSu8
*)"\x6_ichat")) rr
->AnnounceCount
= 1;
8028 InitializeLastAPTime(m
, rr
);
8029 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
8030 if (!rr
->UpdateBlocked
&& rr
->UpdateCredits
) rr
->UpdateCredits
--;
8031 if (!rr
->NextUpdateCredit
) rr
->NextUpdateCredit
= NonZeroTime(m
->timenow
+ kUpdateCreditRefreshInterval
);
8032 if (rr
->AnnounceCount
> rr
->UpdateCredits
+ 1) rr
->AnnounceCount
= (mDNSu8
)(rr
->UpdateCredits
+ 1);
8033 if (rr
->UpdateCredits
<= 5)
8035 mDNSu32 delay
= 6 - rr
->UpdateCredits
; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
8036 if (!rr
->UpdateBlocked
) rr
->UpdateBlocked
= NonZeroTime(m
->timenow
+ (mDNSs32
)delay
* mDNSPlatformOneSecond
);
8037 rr
->ThisAPInterval
*= 4;
8038 rr
->LastAPTime
= rr
->UpdateBlocked
- rr
->ThisAPInterval
;
8039 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
8040 rr
->resrec
.name
->c
, delay
, delay
> 1 ? "s" : "");
8042 rr
->resrec
.rroriginalttl
= newttl
;
8046 return(mStatus_NoError
);
8049 // Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
8050 // the record list and/or question list.
8051 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8052 mDNSexport mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
)
8056 status
= mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
8061 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
8062 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
8064 mDNSlocal NetworkInterfaceInfo
*FindFirstAdvertisedInterface(mDNS
*const m
)
8066 NetworkInterfaceInfo
*intf
;
8067 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8068 if (intf
->Advertise
) break;
8072 mDNSlocal
void AdvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8074 char buffer
[MAX_REVERSE_MAPPING_NAME
];
8075 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
8076 if (!primary
) primary
= set
; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
8078 // Send dynamic update for non-linklocal IPv4 Addresses
8079 mDNS_SetupResourceRecord(&set
->RR_A
, mDNSNULL
, set
->InterfaceID
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNS_HostNameCallback
, set
);
8080 mDNS_SetupResourceRecord(&set
->RR_PTR
, mDNSNULL
, set
->InterfaceID
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
8081 mDNS_SetupResourceRecord(&set
->RR_HINFO
, mDNSNULL
, set
->InterfaceID
, kDNSType_HINFO
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
8083 #if ANSWER_REMOTE_HOSTNAME_QUERIES
8084 set
->RR_A
.AllowRemoteQuery
= mDNStrue
;
8085 set
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
8086 set
->RR_HINFO
.AllowRemoteQuery
= mDNStrue
;
8088 // 1. Set up Address record to map from host name ("foo.local.") to IP address
8089 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
8090 AssignDomainName(&set
->RR_A
.namestorage
, &m
->MulticastHostname
);
8091 if (set
->ip
.type
== mDNSAddrType_IPv4
)
8093 set
->RR_A
.resrec
.rrtype
= kDNSType_A
;
8094 set
->RR_A
.resrec
.rdata
->u
.ipv4
= set
->ip
.ip
.v4
;
8095 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8096 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.",
8097 set
->ip
.ip
.v4
.b
[3], set
->ip
.ip
.v4
.b
[2], set
->ip
.ip
.v4
.b
[1], set
->ip
.ip
.v4
.b
[0]);
8099 else if (set
->ip
.type
== mDNSAddrType_IPv6
)
8102 set
->RR_A
.resrec
.rrtype
= kDNSType_AAAA
;
8103 set
->RR_A
.resrec
.rdata
->u
.ipv6
= set
->ip
.ip
.v6
;
8104 for (i
= 0; i
< 16; i
++)
8106 static const char hexValues
[] = "0123456789ABCDEF";
8107 buffer
[i
* 4 ] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] & 0x0F];
8108 buffer
[i
* 4 + 1] = '.';
8109 buffer
[i
* 4 + 2] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] >> 4];
8110 buffer
[i
* 4 + 3] = '.';
8112 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
8115 MakeDomainNameFromDNSNameString(&set
->RR_PTR
.namestorage
, buffer
);
8116 set
->RR_PTR
.AutoTarget
= Target_AutoHost
; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
8117 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
8119 set
->RR_A
.RRSet
= &primary
->RR_A
; // May refer to self
8121 mDNS_Register_internal(m
, &set
->RR_A
);
8122 mDNS_Register_internal(m
, &set
->RR_PTR
);
8124 if (!NO_HINFO
&& m
->HIHardware
.c
[0] > 0 && m
->HISoftware
.c
[0] > 0 && m
->HIHardware
.c
[0] + m
->HISoftware
.c
[0] <= 254)
8126 mDNSu8
*p
= set
->RR_HINFO
.resrec
.rdata
->u
.data
;
8127 AssignDomainName(&set
->RR_HINFO
.namestorage
, &m
->MulticastHostname
);
8128 set
->RR_HINFO
.DependentOn
= &set
->RR_A
;
8129 mDNSPlatformMemCopy(p
, &m
->HIHardware
, 1 + (mDNSu32
)m
->HIHardware
.c
[0]);
8131 mDNSPlatformMemCopy(p
, &m
->HISoftware
, 1 + (mDNSu32
)m
->HISoftware
.c
[0]);
8132 mDNS_Register_internal(m
, &set
->RR_HINFO
);
8136 debugf("Not creating HINFO record: platform support layer provided no information");
8137 set
->RR_HINFO
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
8141 mDNSlocal
void DeadvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8143 NetworkInterfaceInfo
*intf
;
8145 // If we still have address records referring to this one, update them
8146 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
8147 AuthRecord
*A
= primary
? &primary
->RR_A
: mDNSNULL
;
8148 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8149 if (intf
->RR_A
.RRSet
== &set
->RR_A
)
8150 intf
->RR_A
.RRSet
= A
;
8152 // Unregister these records.
8153 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
8154 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
8155 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
8156 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
8157 if (set
->RR_A
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_A
, mDNS_Dereg_normal
);
8158 if (set
->RR_PTR
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_PTR
, mDNS_Dereg_normal
);
8159 if (set
->RR_HINFO
.resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_HINFO
, mDNS_Dereg_normal
);
8162 mDNSexport
void mDNS_SetFQDN(mDNS
*const m
)
8164 domainname newmname
;
8165 NetworkInterfaceInfo
*intf
;
8169 if (!AppendDomainLabel(&newmname
, &m
->hostlabel
)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8170 if (!AppendLiteralLabelString(&newmname
, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8174 if (SameDomainNameCS(&m
->MulticastHostname
, &newmname
)) debugf("mDNS_SetFQDN - hostname unchanged");
8177 AssignDomainName(&m
->MulticastHostname
, &newmname
);
8179 // 1. Stop advertising our address records on all interfaces
8180 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8181 if (intf
->Advertise
) DeadvertiseInterface(m
, intf
);
8183 // 2. Start advertising our address records using the new name
8184 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8185 if (intf
->Advertise
) AdvertiseInterface(m
, intf
);
8188 // 3. Make sure that any AutoTarget SRV records (and the like) get updated
8189 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8190 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8195 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8197 (void)rr
; // Unused parameter
8201 char *msg
= "Unknown result";
8202 if (result
== mStatus_NoError
) msg
= "Name registered";
8203 else if (result
== mStatus_NameConflict
) msg
= "Name conflict";
8204 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8208 if (result
== mStatus_NoError
)
8210 // Notify the client that the host name is successfully registered
8211 if (m
->MainCallback
)
8212 m
->MainCallback(m
, mStatus_NoError
);
8214 else if (result
== mStatus_NameConflict
)
8216 domainlabel oldlabel
= m
->hostlabel
;
8218 // 1. First give the client callback a chance to pick a new name
8219 if (m
->MainCallback
)
8220 m
->MainCallback(m
, mStatus_NameConflict
);
8222 // 2. If the client callback didn't do it, add (or increment) an index ourselves
8223 // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
8224 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
8225 if (SameDomainLabel(m
->hostlabel
.c
, oldlabel
.c
))
8226 IncrementLabelSuffix(&m
->hostlabel
, mDNSfalse
);
8228 // 3. Generate the FQDNs from the hostlabel,
8229 // and make sure all SRV records, etc., are updated to reference our new hostname
8231 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel
.c
, m
->hostlabel
.c
);
8233 else if (result
== mStatus_MemFree
)
8235 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
8236 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
8237 debugf("mDNS_HostNameCallback: MemFree (ignored)");
8240 LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result
, rr
->resrec
.name
->c
);
8243 mDNSlocal
void UpdateInterfaceProtocols(mDNS
*const m
, NetworkInterfaceInfo
*active
)
8245 NetworkInterfaceInfo
*intf
;
8246 active
->IPv4Available
= mDNSfalse
;
8247 active
->IPv6Available
= mDNSfalse
;
8248 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8249 if (intf
->InterfaceID
== active
->InterfaceID
)
8251 if (intf
->ip
.type
== mDNSAddrType_IPv4
&& intf
->McastTxRx
) active
->IPv4Available
= mDNStrue
;
8252 if (intf
->ip
.type
== mDNSAddrType_IPv6
&& intf
->McastTxRx
) active
->IPv6Available
= mDNStrue
;
8256 mDNSlocal
void RestartRecordGetZoneData(mDNS
* const m
)
8259 ServiceRecordSet
*s
;
8261 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8262 if (AuthRecord_uDNS(rr
))
8264 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr
->resrec
.name
->c
);
8265 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
8266 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
8269 for (s
= m
->ServiceRegistrations
; s
; s
= s
->uDNS_next
)
8271 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s
->RR_SRV
.resrec
.name
->c
);
8272 if (s
->srs_nta
) CancelGetZoneData(m
, s
->srs_nta
);
8273 s
->srs_nta
= StartGetZoneData(m
, s
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, s
);
8277 mDNSlocal
void InitializeNetWakeState(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8280 set
->NetWakeBrowse
.ThisQInterval
= -1;
8283 set
->NetWakeResolve
[i
].ThisQInterval
= -1;
8284 set
->SPSAddr
[i
].type
= mDNSAddrType_None
;
8286 set
->NextSPSAttempt
= -1;
8287 set
->NextSPSAttemptTime
= m
->timenow
;
8290 mDNSexport
void mDNS_ActivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8292 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8293 while (p
&& p
!= set
) p
=p
->next
;
8294 if (!p
) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8296 if (set
->InterfaceActive
)
8298 LogSPS("ActivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8299 mDNS_StartBrowse_internal(m
, &set
->NetWakeBrowse
, &SleepProxyServiceType
, &localdomain
, set
->InterfaceID
, mDNSfalse
, m
->SPSBrowseCallback
, set
);
8303 mDNSexport
void mDNS_DeactivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8305 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8306 while (p
&& p
!= set
) p
=p
->next
;
8307 if (!p
) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8309 if (set
->NetWakeBrowse
.ThisQInterval
>= 0)
8312 LogSPS("DeactivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8314 // Stop our browse and resolve operations
8315 mDNS_StopQuery_internal(m
, &set
->NetWakeBrowse
);
8316 for (i
=0; i
<3; i
++) if (set
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &set
->NetWakeResolve
[i
]);
8318 // Make special call to the browse callback to let it know it can to remove all records for this interface
8319 if (m
->SPSBrowseCallback
) m
->SPSBrowseCallback(m
, &set
->NetWakeBrowse
, mDNSNULL
, mDNSfalse
);
8321 // Reset our variables back to initial state, so we're ready for when NetWake is turned back on
8322 // (includes resetting NetWakeBrowse.ThisQInterval back to -1)
8323 InitializeNetWakeState(m
, set
);
8327 mDNSexport mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8330 mDNSBool FirstOfType
= mDNStrue
;
8331 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8333 if (!set
->InterfaceID
)
8334 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set
->ip
); return(mStatus_Invalid
); }
8336 if (!mDNSAddressIsValidNonZero(&set
->mask
))
8337 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set
->ip
, &set
->mask
); return(mStatus_Invalid
); }
8341 // Assume this interface will be active now, unless we find a duplicate already in the list
8342 set
->InterfaceActive
= mDNStrue
;
8343 set
->IPv4Available
= (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
);
8344 set
->IPv6Available
= (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
);
8346 InitializeNetWakeState(m
, set
);
8348 // Scan list to see if this InterfaceID is already represented
8353 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
8355 return(mStatus_AlreadyRegistered
);
8358 if ((*p
)->InterfaceID
== set
->InterfaceID
)
8360 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
8361 set
->InterfaceActive
= mDNSfalse
;
8362 if (set
->ip
.type
== (*p
)->ip
.type
) FirstOfType
= mDNSfalse
;
8363 if (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
) (*p
)->IPv4Available
= mDNStrue
;
8364 if (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
) (*p
)->IPv6Available
= mDNStrue
;
8370 set
->next
= mDNSNULL
;
8374 AdvertiseInterface(m
, set
);
8376 LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set
->InterfaceID
, set
->ifname
, &set
->ip
,
8377 set
->InterfaceActive
?
8378 "not represented in list; marking active and retriggering queries" :
8379 "already represented in list; marking inactive for now");
8381 if (set
->NetWake
) mDNS_ActivateNetWake_internal(m
, set
);
8383 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8384 // giving the false impression that there's an active representative of this interface when there really isn't.
8385 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
8386 // even if we believe that we previously had an active representative of this interface.
8387 if (set
->McastTxRx
&& ((m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) || FirstOfType
|| set
->InterfaceActive
))
8390 // If flapping, delay between first and second queries is eight seconds instead of one
8391 mDNSs32 delay
= flapping
? mDNSPlatformOneSecond
* 5 : 0;
8392 mDNSu8 announce
= flapping
? (mDNSu8
)1 : InitialAnnounceCount
;
8395 // Use a small amount of randomness:
8396 // In the case of a network administrator turning on an Ethernet hub so that all the
8397 // connected machines establish link at exactly the same time, we don't want them all
8398 // to go and hit the network with identical queries at exactly the same moment.
8399 newSS
= m
->timenow
+ (mDNSs32
)mDNSRandom((mDNSu32
)InitialQuestionInterval
);
8400 #if APPLE_OSX_mDNSResponder
8401 // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
8402 // of network change notifications in a row, and we don't know when we're done getting notified.
8403 // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
8404 newSS
+= mDNSPlatformOneSecond
* 2;
8406 if (!m
->SuppressSending
|| newSS
- m
->SuppressSending
< 0) m
->SuppressSending
= newSS
;
8410 LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)",
8411 set
->ifname
, &set
->ip
);
8412 if (!m
->SuppressProbes
||
8413 m
->SuppressProbes
- (m
->timenow
+ delay
) < 0)
8414 m
->SuppressProbes
= (m
->timenow
+ delay
);
8417 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
8418 if (mDNSOpaque16IsZero(q
->TargetQID
))
8419 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
) // If non-specific Q, or Q on this specific interface,
8420 { // then reactivate this question
8421 mDNSBool dodelay
= flapping
&& (q
->FlappingInterface1
== set
->InterfaceID
|| q
->FlappingInterface2
== set
->InterfaceID
);
8422 mDNSs32 initial
= dodelay
? InitialQuestionInterval
* QuestionIntervalStep2
: InitialQuestionInterval
;
8423 mDNSs32 qdelay
= dodelay
? mDNSPlatformOneSecond
* 5 : 0;
8424 if (dodelay
) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q
->qname
.c
, DNSTypeName(q
->qtype
));
8426 if (!q
->ThisQInterval
|| q
->ThisQInterval
> initial
)
8428 q
->ThisQInterval
= initial
;
8429 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
8431 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ qdelay
;
8432 q
->RecentAnswerPkts
= 0;
8433 SetNextQueryTime(m
,q
);
8436 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
8437 // we now need them to re-probe if necessary, and then re-announce.
8438 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8439 if (!AuthRecord_uDNS(rr
))
8440 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8442 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
8443 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
8444 if (rr
->AnnounceCount
< announce
) rr
->AnnounceCount
= announce
;
8445 InitializeLastAPTime(m
, rr
);
8449 RestartRecordGetZoneData(m
);
8452 return(mStatus_NoError
);
8455 // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
8456 // the record list and/or question list.
8457 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8458 mDNSexport
void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8460 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8462 mDNSBool revalidate
= mDNSfalse
;
8463 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
8464 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
8465 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
8466 if (m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) revalidate
= mDNStrue
;
8470 // Find this record in our list
8471 while (*p
&& *p
!= set
) p
=&(*p
)->next
;
8472 if (!*p
) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m
); return; }
8474 mDNS_DeactivateNetWake_internal(m
, set
);
8476 // Unlink this record from our list
8478 set
->next
= mDNSNULL
;
8480 if (!set
->InterfaceActive
)
8482 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
8483 NetworkInterfaceInfo
*intf
;
8484 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8485 if (intf
->InterfaceActive
&& intf
->InterfaceID
== set
->InterfaceID
)
8486 UpdateInterfaceProtocols(m
, intf
);
8490 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, set
->InterfaceID
);
8493 LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
8494 " making it active", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8495 if (intf
->InterfaceActive
)
8496 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set
->ifname
, &set
->ip
);
8497 intf
->InterfaceActive
= mDNStrue
;
8498 UpdateInterfaceProtocols(m
, intf
);
8500 if (intf
->NetWake
) mDNS_ActivateNetWake_internal(m
, intf
);
8502 // See if another representative *of the same type* exists. If not, we mave have gone from
8503 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
8504 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8505 if (intf
->InterfaceID
== set
->InterfaceID
&& intf
->ip
.type
== set
->ip
.type
)
8507 if (!intf
) revalidate
= mDNStrue
;
8517 LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
8518 " marking questions etc. dormant", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8521 LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)",
8522 set
->ifname
, &set
->ip
);
8524 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
8525 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
8526 for (q
= m
->Questions
; q
; q
=q
->next
)
8528 if (q
->InterfaceID
== set
->InterfaceID
) q
->ThisQInterval
= 0;
8529 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
)
8531 q
->FlappingInterface2
= q
->FlappingInterface1
;
8532 q
->FlappingInterface1
= set
->InterfaceID
; // Keep history of the last two interfaces to go away
8536 // 2. Flush any cache records received on this interface
8537 revalidate
= mDNSfalse
; // Don't revalidate if we're flushing the records
8538 FORALL_CACHERECORDS(slot
, cg
, rr
)
8539 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8541 // If this interface is deemed flapping,
8542 // postpone deleting the cache records in case the interface comes back again
8543 if (!flapping
) mDNS_PurgeCacheResourceRecord(m
, rr
);
8546 // We want these record to go away in 30 seconds
8547 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
8548 // if the interface does come back, any relevant questions will be reactivated anyway
8549 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8550 rr
->UnansweredQueries
= MaxUnansweredQueries
;
8554 // 3. Any DNS servers specific to this interface are now unusable
8555 for (s
= m
->DNSServers
; s
; s
= s
->next
)
8556 if (s
->interface
== set
->InterfaceID
)
8558 s
->interface
= mDNSInterface_Any
;
8559 s
->teststate
= DNSServer_Disabled
;
8564 // If we were advertising on this interface, deregister those address and reverse-lookup records now
8565 if (set
->Advertise
) DeadvertiseInterface(m
, set
);
8567 // If we have any cache records received on this interface that went away, then re-verify them.
8568 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8569 // giving the false impression that there's an active representative of this interface when there really isn't.
8570 // Don't need to do this when shutting down, because *all* interfaces are about to go away
8571 if (revalidate
&& !m
->ShutdownTime
)
8576 m
->NextCacheCheck
= m
->timenow
;
8577 FORALL_CACHERECORDS(slot
, cg
, rr
)
8578 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8579 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8585 mDNSlocal
void ServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8587 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8588 (void)m
; // Unused parameter
8592 char *msg
= "Unknown result";
8593 if (result
== mStatus_NoError
) msg
= "Name Registered";
8594 else if (result
== mStatus_NameConflict
) msg
= "Name Conflict";
8595 else if (result
== mStatus_MemFree
) msg
= "Memory Free";
8596 debugf("ServiceCallback: %##s (%s) %s (%d)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8600 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
8601 if (result
== mStatus_NoError
&& rr
!= &sr
->RR_SRV
) return;
8603 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
8604 if (result
== mStatus_NameConflict
)
8606 sr
->Conflict
= mDNStrue
; // Record that this service set had a conflict
8607 mDNS_DeregisterService(m
, sr
); // Unlink the records from our list
8611 if (result
== mStatus_MemFree
)
8613 // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
8614 // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
8615 // every record is finished cleaning up.
8617 if (sr
->RR_SRV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8618 if (sr
->RR_TXT
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8619 if (sr
->RR_PTR
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8620 if (sr
->RR_ADV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8621 for (i
=0; i
<sr
->NumSubTypes
; i
++) if (sr
->SubTypes
[i
].resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8623 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
8624 // then we can now report the NameConflict to the client
8625 if (sr
->Conflict
) result
= mStatus_NameConflict
;
8629 LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m
, &sr
->RR_SRV
));
8630 CancelGetZoneData(m
, sr
->srs_nta
);
8631 sr
->srs_nta
= mDNSNULL
;
8635 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
8636 // function is allowed to do anything, including deregistering this service and freeing its memory.
8637 if (sr
->ServiceCallback
)
8638 sr
->ServiceCallback(m
, sr
, result
);
8641 mDNSlocal
void NSSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8643 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8644 if (sr
->ServiceCallback
)
8645 sr
->ServiceCallback(m
, sr
, result
);
8648 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8649 mDNSlocal mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
8652 ServiceRecordSet
**p
= &m
->ServiceRegistrations
;
8653 while (*p
&& *p
!= srs
) p
=&(*p
)->uDNS_next
;
8654 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
->c
); return(mStatus_AlreadyRegistered
); }
8656 srs
->uDNS_next
= mDNSNULL
;
8659 srs
->RR_SRV
.resrec
.rroriginalttl
= kHostNameTTL
;
8660 srs
->RR_TXT
.resrec
.rroriginalttl
= kStandardTTL
;
8661 srs
->RR_PTR
.resrec
.rroriginalttl
= kStandardTTL
;
8662 for (i
= 0; i
< srs
->NumSubTypes
;i
++) srs
->SubTypes
[i
].resrec
.rroriginalttl
= kStandardTTL
;
8664 srs
->srs_uselease
= mDNStrue
;
8666 if (srs
->RR_SRV
.AutoTarget
)
8668 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
8669 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
8670 // with the port number in our advertised SRV record automatically tracking the external mapped port.
8671 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
8672 if (!AuthInfo
|| !AuthInfo
->AutoTunnel
) srs
->RR_SRV
.AutoTarget
= Target_AutoHostAndNATMAP
;
8675 if (!GetServiceTarget(m
, &srs
->RR_SRV
))
8677 // defer registration until we've got a target
8678 LogInfo("uDNS_RegisterService - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
8679 srs
->state
= regState_NoTarget
;
8680 return mStatus_NoError
;
8683 ActivateUnicastRegistration(m
, &srs
->RR_SRV
);
8684 srs
->state
= regState_FetchingZoneData
;
8685 return mStatus_NoError
;
8690 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
8691 // Type is service type (e.g. "_ipp._tcp.")
8692 // Domain is fully qualified domain name (i.e. ending with a null label)
8693 // We always register a TXT, even if it is empty (so that clients are not
8694 // left waiting forever looking for a nonexistent record.)
8695 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
8696 // then the default host name (m->MulticastHostname) is automatically used
8697 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
8698 mDNSexport mStatus
mDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*sr
,
8699 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
8700 const domainname
*const host
, mDNSIPPort port
, const mDNSu8 txtinfo
[], mDNSu16 txtlen
,
8701 AuthRecord
*SubTypes
, mDNSu32 NumSubTypes
,
8702 const mDNSInterfaceID InterfaceID
, mDNSServiceCallback Callback
, void *Context
)
8707 sr
->state
= regState_Zero
;
8708 sr
->srs_uselease
= 0;
8709 sr
->TestForSelfConflict
= 0;
8713 sr
->SRSUpdateServer
= zeroAddr
;
8714 sr
->SRSUpdatePort
= zeroIPPort
;
8715 mDNSPlatformMemZero(&sr
->NATinfo
, sizeof(sr
->NATinfo
));
8716 sr
->NATinfo
.IntPort
= port
; // Record originally-requested port
8717 sr
->ClientCallbackDeferred
= 0;
8718 sr
->DeferredStatus
= 0;
8719 sr
->SRVUpdateDeferred
= 0;
8723 sr
->ServiceCallback
= Callback
;
8724 sr
->ServiceContext
= Context
;
8725 sr
->Conflict
= mDNSfalse
;
8727 sr
->Extras
= mDNSNULL
;
8728 sr
->NumSubTypes
= NumSubTypes
;
8729 sr
->SubTypes
= SubTypes
;
8731 // Initialize the AuthRecord objects to sane values
8732 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
8733 mDNS_SetupResourceRecord(&sr
->RR_ADV
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeAdvisory
, ServiceCallback
, sr
);
8734 mDNS_SetupResourceRecord(&sr
->RR_PTR
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
8735 mDNS_SetupResourceRecord(&sr
->RR_SRV
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8736 mDNS_SetupResourceRecord(&sr
->RR_TXT
, mDNSNULL
, InterfaceID
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8738 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
8739 if (mDNSIPPortIsZero(port
))
8740 return(mDNS_RegisterNoSuchService(m
, &sr
->RR_SRV
, name
, type
, domain
, mDNSNULL
, mDNSInterface_Any
, NSSCallback
, sr
));
8742 // If the client is registering an oversized TXT record,
8743 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
8744 if (sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
< txtlen
)
8745 sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
= txtlen
;
8747 // Set up the record names
8748 // For now we only create an advisory record for the main type, not for subtypes
8749 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
8750 if (ConstructServiceName(&sr
->RR_ADV
.namestorage
, (const domainlabel
*)"\x09_services", (const domainname
*)"\x07_dns-sd\x04_udp", domain
) == mDNSNULL
)
8751 return(mStatus_BadParamErr
);
8752 if (ConstructServiceName(&sr
->RR_PTR
.namestorage
, mDNSNULL
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8753 if (ConstructServiceName(&sr
->RR_SRV
.namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8754 AssignDomainName(&sr
->RR_TXT
.namestorage
, sr
->RR_SRV
.resrec
.name
);
8756 // 1. Set up the ADV record rdata to advertise our service type
8757 AssignDomainName(&sr
->RR_ADV
.resrec
.rdata
->u
.name
, sr
->RR_PTR
.resrec
.name
);
8759 // 2. Set up the PTR record rdata to point to our service name
8760 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
8761 AssignDomainName(&sr
->RR_PTR
.resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
8762 sr
->RR_PTR
.Additional1
= &sr
->RR_SRV
;
8763 sr
->RR_PTR
.Additional2
= &sr
->RR_TXT
;
8765 // 2a. Set up any subtype PTRs to point to our service name
8766 // If the client is using subtypes, it is the client's responsibility to have
8767 // already set the first label of the record name to the subtype being registered
8768 for (i
=0; i
<NumSubTypes
; i
++)
8771 AssignDomainName(&st
, sr
->SubTypes
[i
].resrec
.name
);
8772 st
.c
[1+st
.c
[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
8773 AppendDomainName(&st
, type
);
8774 mDNS_SetupResourceRecord(&sr
->SubTypes
[i
], mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
8775 if (ConstructServiceName(&sr
->SubTypes
[i
].namestorage
, mDNSNULL
, &st
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8776 AssignDomainName(&sr
->SubTypes
[i
].resrec
.rdata
->u
.name
, &sr
->RR_SRV
.namestorage
);
8777 sr
->SubTypes
[i
].Additional1
= &sr
->RR_SRV
;
8778 sr
->SubTypes
[i
].Additional2
= &sr
->RR_TXT
;
8781 // 3. Set up the SRV record rdata.
8782 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.priority
= 0;
8783 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.weight
= 0;
8784 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= port
;
8786 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
8787 if (host
&& host
->c
[0]) AssignDomainName(&sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, host
);
8788 else { sr
->RR_SRV
.AutoTarget
= Target_AutoHost
; sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0'; }
8790 // 4. Set up the TXT record rdata,
8791 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
8792 if (txtinfo
== mDNSNULL
) sr
->RR_TXT
.resrec
.rdlength
= 0;
8793 else if (txtinfo
!= sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
)
8795 sr
->RR_TXT
.resrec
.rdlength
= txtlen
;
8796 if (sr
->RR_TXT
.resrec
.rdlength
> sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
) return(mStatus_BadParamErr
);
8797 mDNSPlatformMemCopy(sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, txtinfo
, txtlen
);
8799 sr
->RR_TXT
.DependentOn
= &sr
->RR_SRV
;
8801 sr
->srs_nta
= mDNSNULL
;
8803 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8804 // If the client has specified an explicit InterfaceID,
8805 // then we do a multicast registration on that interface, even for unicast domains.
8806 if (!(InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&sr
->RR_SRV
.namestorage
)))
8810 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
8811 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
8812 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
8813 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
8814 if (!sr
->RR_TXT
.resrec
.rdlength
) { sr
->RR_TXT
.resrec
.rdlength
= 1; sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
[0] = 0; }
8816 status
= uDNS_RegisterService(m
, sr
);
8823 err
= mDNS_Register_internal(m
, &sr
->RR_SRV
);
8824 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_TXT
);
8825 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
8826 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
8827 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
8828 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
8829 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
8830 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_ADV
);
8831 for (i
=0; i
<NumSubTypes
; i
++) if (!err
) err
= mDNS_Register_internal(m
, &sr
->SubTypes
[i
]);
8832 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_PTR
);
8836 if (err
) mDNS_DeregisterService(m
, sr
);
8840 mDNSlocal
void DummyCallback(mDNS
*const m
, AuthRecord
*rr
, mStatus result
)
8844 (void)result
; // Unused
8845 LogInfo("DummyCallback %d %s", result
, ARDisplayString(m
, rr
));
8848 mDNSexport mStatus
mDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
,
8849 ExtraResourceRecord
*extra
, RData
*rdata
, mDNSu32 ttl
)
8851 ExtraResourceRecord
**e
;
8854 extra
->next
= mDNSNULL
;
8855 mDNS_SetupResourceRecord(&extra
->r
, rdata
, sr
->RR_PTR
.resrec
.InterfaceID
,
8856 extra
->r
.resrec
.rrtype
, ttl
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8857 AssignDomainName(&extra
->r
.namestorage
, sr
->RR_SRV
.resrec
.name
);
8861 while (*e
) e
= &(*e
)->next
;
8863 if (ttl
== 0) ttl
= kStandardTTL
;
8865 extra
->r
.DependentOn
= &sr
->RR_SRV
;
8867 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
8868 extra
->r
.resrec
.name
->c
, DNSTypeName(extra
->r
.resrec
.rrtype
), extra
->r
.resrec
.rdlength
);
8870 status
= mDNS_Register_internal(m
, &extra
->r
);
8871 if (status
== mStatus_NoError
)
8874 #ifndef UNICAST_DISABLED
8875 if (AuthRecord_uDNS(&sr
->RR_SRV
))
8877 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name (???)
8878 extra
->r
.RecordCallback
= DummyCallback
; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
8879 if (sr
->state
!= regState_Registered
&& sr
->state
!= regState_Refresh
) extra
->r
.state
= regState_ExtraQueued
;
8888 mDNSexport mStatus
mDNS_RemoveRecordFromService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
,
8889 mDNSRecordCallback MemFreeCallback
, void *Context
)
8891 ExtraResourceRecord
**e
;
8896 while (*e
&& *e
!= extra
) e
= &(*e
)->next
;
8899 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra
->r
.resrec
.name
->c
);
8900 status
= mStatus_BadReferenceErr
;
8904 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra
->r
.resrec
.name
->c
);
8905 extra
->r
.RecordCallback
= MemFreeCallback
;
8906 extra
->r
.RecordContext
= Context
;
8908 status
= mDNS_Deregister_internal(m
, &extra
->r
, mDNS_Dereg_normal
);
8914 mDNSexport mStatus
mDNS_RenameAndReregisterService(mDNS
*const m
, ServiceRecordSet
*const sr
, const domainlabel
*newname
)
8916 // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
8917 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
8918 domainlabel name1
, name2
;
8919 domainname type
, domain
;
8920 const domainname
*host
= sr
->RR_SRV
.AutoTarget
? mDNSNULL
: &sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
8921 ExtraResourceRecord
*extras
= sr
->Extras
;
8924 DeconstructServiceName(sr
->RR_SRV
.resrec
.name
, &name1
, &type
, &domain
);
8928 IncrementLabelSuffix(&name2
, mDNStrue
);
8932 if (SameDomainName(&domain
, &localdomain
))
8933 debugf("%##s service renamed from \"%#s\" to \"%#s\"", type
.c
, name1
.c
, newname
->c
);
8934 else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type
.c
, domain
.c
, name1
.c
, newname
->c
);
8936 err
= mDNS_RegisterService(m
, sr
, newname
, &type
, &domain
,
8937 host
, sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
, sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, sr
->RR_TXT
.resrec
.rdlength
,
8938 sr
->SubTypes
, sr
->NumSubTypes
,
8939 sr
->RR_PTR
.resrec
.InterfaceID
, sr
->ServiceCallback
, sr
->ServiceContext
);
8941 // mDNS_RegisterService() just reset sr->Extras to NULL.
8942 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
8943 // through the old list of extra records, and re-add them to our freshly created service registration
8944 while (!err
&& extras
)
8946 ExtraResourceRecord
*e
= extras
;
8947 extras
= extras
->next
;
8948 err
= mDNS_AddRecordToService(m
, sr
, e
, e
->r
.resrec
.rdata
, e
->r
.resrec
.rroriginalttl
);
8954 // Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
8955 // which may change the record list and/or question list.
8956 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8957 mDNSexport mStatus
mDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*sr
)
8959 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
8960 if (mDNSIPPortIsZero(sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
)) return(mDNS_DeregisterNoSuchService(m
, &sr
->RR_SRV
));
8962 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8963 if (!(sr
->RR_SRV
.resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(sr
->RR_SRV
.resrec
.name
)))
8967 status
= uDNS_DeregisterService(m
, sr
);
8972 if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
8974 debugf("Service set for %##s already deregistered", sr
->RR_SRV
.resrec
.name
->c
);
8975 return(mStatus_BadReferenceErr
);
8977 else if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeDeregistering
)
8979 debugf("Service set for %##s already in the process of deregistering", sr
->RR_SRV
.resrec
.name
->c
);
8980 // Avoid race condition:
8981 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
8982 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
8983 // If the client happens to deregister the service in the middle of that process, then
8984 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
8985 // instead of incorrectly promoting it to mStatus_NameConflict.
8986 // This race condition is exposed particularly when the conformance test generates
8987 // a whole batch of simultaneous conflicts across a range of services all advertised
8988 // using the same system default name, and if we don't take this precaution then
8989 // we end up incrementing m->nicelabel multiple times instead of just once.
8990 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
8991 sr
->Conflict
= mDNSfalse
;
8992 return(mStatus_NoError
);
8998 ExtraResourceRecord
*e
;
9002 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
9003 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
9004 mDNS_Deregister_internal(m
, &sr
->RR_SRV
, mDNS_Dereg_repeat
);
9005 mDNS_Deregister_internal(m
, &sr
->RR_TXT
, mDNS_Dereg_repeat
);
9007 mDNS_Deregister_internal(m
, &sr
->RR_ADV
, mDNS_Dereg_normal
);
9009 // We deregister all of the extra records, but we leave the sr->Extras list intact
9010 // in case the client wants to do a RenameAndReregister and reinstate the registration
9013 mDNS_Deregister_internal(m
, &e
->r
, mDNS_Dereg_repeat
);
9017 for (i
=0; i
<sr
->NumSubTypes
; i
++)
9018 mDNS_Deregister_internal(m
, &sr
->SubTypes
[i
], mDNS_Dereg_normal
);
9020 // Be sure to deregister the PTR last!
9021 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
9022 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
9023 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
9024 // we've deregistered all our records and done any other necessary cleanup before that happens.
9025 status
= mDNS_Deregister_internal(m
, &sr
->RR_PTR
, mDNS_Dereg_normal
);
9031 // Create a registration that asserts that no such service exists with this name.
9032 // This can be useful where there is a given function is available through several protocols.
9033 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
9034 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
9035 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
9036 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
9037 mDNSexport mStatus
mDNS_RegisterNoSuchService(mDNS
*const m
, AuthRecord
*const rr
,
9038 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
9039 const domainname
*const host
,
9040 const mDNSInterfaceID InterfaceID
, mDNSRecordCallback Callback
, void *Context
)
9042 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, Callback
, Context
);
9043 if (ConstructServiceName(&rr
->namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
9044 rr
->resrec
.rdata
->u
.srv
.priority
= 0;
9045 rr
->resrec
.rdata
->u
.srv
.weight
= 0;
9046 rr
->resrec
.rdata
->u
.srv
.port
= zeroIPPort
;
9047 if (host
&& host
->c
[0]) AssignDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, host
);
9048 else rr
->AutoTarget
= Target_AutoHost
;
9049 return(mDNS_Register(m
, rr
));
9052 mDNSexport mStatus
mDNS_AdvertiseDomains(mDNS
*const m
, AuthRecord
*rr
,
9053 mDNS_DomainType DomainType
, const mDNSInterfaceID InterfaceID
, char *domname
)
9055 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
9056 if (!MakeDomainNameFromDNSNameString(&rr
->namestorage
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
9057 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.rdata
->u
.name
, domname
)) return(mStatus_BadParamErr
);
9058 return(mDNS_Register(m
, rr
));
9061 mDNSexport mDNSOpaque16
mDNS_NewMessageID(mDNS
* const m
)
9065 for (i
=0; i
<10; i
++)
9069 id
= mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
9070 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (mDNSSameOpaque16(id
, r
->updateid
)) continue;
9071 for (q
= m
->Questions
; q
; q
=q
->next
) if (mDNSSameOpaque16(id
, q
->TargetQID
)) continue;
9074 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id
));
9078 // ***************************************************************************
9079 #if COMPILER_LIKES_PRAGMA_MARK
9081 #pragma mark - Sleep Proxy Server
9084 mDNSlocal
void RestartProbing(mDNS
*const m
, AuthRecord
*const rr
)
9086 // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
9087 // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
9088 // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
9089 // then we'll transition out of probing state and start answering ARPs again.
9090 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
9091 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
9092 rr
->AnnounceCount
= InitialAnnounceCount
;
9093 InitializeLastAPTime(m
, rr
);
9096 mDNSexport
void mDNSCoreReceiveRawPacket(mDNS
*const m
, const mDNSu8
*const p
, const mDNSu8
*const end
, const mDNSInterfaceID InterfaceID
)
9098 static const mDNSOpaque16 Ethertype_IP
= { { 0x08, 0x00 } };
9099 static const mDNSOpaque32 ARP_EthIP_h0
= { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
9100 static const mDNSOpaque32 ARP_EthIP_h1
= { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen
9101 static const mDNSOpaque16 ARP_op_request
= { { 0, 1 } };
9102 const EthernetHeader
*const eth
= (const EthernetHeader
*)p
;
9103 const ARP_EthIP
*const arp
= (const ARP_EthIP
*)(eth
+1);
9104 const IPv4Header
*const v4
= (const IPv4Header
*)(eth
+1);
9105 const IPv6Header
*const v6
= (const IPv6Header
*)(eth
+1);
9106 if (end
>= p
+42 && *(mDNSu32
*)(p
+12) == ARP_EthIP_h0
.NotAnInteger
&& *(mDNSu32
*)(p
+16) == ARP_EthIP_h1
.NotAnInteger
)
9109 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
9112 debugf("Got ARP from %.4a/%.6a for %.4a", &arp
->spa
, &arp
->sha
, &arp
->tpa
);
9117 // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
9118 // We also process and answer ARPs from our own kernel (no special treatment for localhost).
9119 // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
9120 // 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.
9121 if (mDNSSameOpaque16(arp
->op
, ARP_op_request
) && !mDNSSameIPv4Address(arp
->spa
, arp
->tpa
))
9122 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9123 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->tpa
))
9125 static const char msg1
[] = "ARP Req from owner -- re-probing";
9126 static const char msg2
[] = "Ignoring ARP Request from ";
9127 static const char msg3
[] = "Creating Local ARP Cache entry ";
9128 static const char msg4
[] = "Answering ARP Request from ";
9129 const char *const msg
= mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
) ? msg1
:
9130 (rr
->AnnounceCount
== InitialAnnounceCount
) ? msg2
:
9131 mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
) ? msg3
: msg4
;
9132 LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
9133 InterfaceNameForID(m
, InterfaceID
), msg
, &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9134 if (msg
== msg1
) RestartProbing(m
, rr
);
9135 else if (msg
== msg3
) mDNSPlatformSetLocalARP(&arp
->tpa
, &rr
->WakeUp
.IMAC
, InterfaceID
);
9136 else if (msg
== msg4
) SendARP(m
, 2, rr
, arp
->tpa
.b
, arp
->sha
.b
, arp
->spa
.b
, arp
->sha
.b
);
9140 // 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.
9141 // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
9142 // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
9143 // 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.
9144 // If we see an apparently conflicting ARP, we check the sender hardware address:
9145 // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
9146 // 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.
9147 if (mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
))
9148 debugf("ARP from self for %.4a", &arp
->tpa
);
9151 if (!mDNSSameIPv4Address(arp
->spa
, zerov4Addr
))
9152 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9153 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->spa
))
9155 RestartProbing(m
, rr
);
9156 if (mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
))
9157 LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
9158 InterfaceNameForID(m
, InterfaceID
),
9159 mDNSSameIPv4Address(arp
->spa
, arp
->tpa
) ? "Announcement" : mDNSSameOpaque16(arp
->op
, ARP_op_request
) ? "Request " : "Response ",
9160 &arp
->sha
, &arp
->spa
, &arp
->tpa
, ARDisplayString(m
, rr
));
9163 LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
9164 InterfaceNameForID(m
, InterfaceID
), &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9165 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9172 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9174 const mDNSu8
*const trans
= p
+ 14 + (v4
->vlen
& 0xF) * 4;
9175 const mDNSu8
*const required
= trans
+ (v4
->protocol
== 1 ? 4 : v4
->protocol
== 6 ? 20 : v4
->protocol
== 17 ? 8 : 0);
9176 debugf("Got IPv4 from %.4a to %.4a", &v4
->src
, &v4
->dst
);
9177 if (end
>= required
)
9179 #define SSH_AsNumber 22
9180 #define ARD_AsNumber 3283
9181 #define IPSEC_AsNumber 4500
9182 static const mDNSIPPort SSH
= { { SSH_AsNumber
>> 8, SSH_AsNumber
& 0xFF } };
9183 static const mDNSIPPort ARD
= { { ARD_AsNumber
>> 8, ARD_AsNumber
& 0xFF } };
9184 static const mDNSIPPort IPSEC
= { { IPSEC_AsNumber
>> 8, IPSEC_AsNumber
& 0xFF } };
9186 mDNSBool wake
= mDNSfalse
;
9187 mDNSIPPort port
= zeroIPPort
;
9189 switch (v4
->protocol
)
9191 #define XX wake ? "Received" : "Ignoring", end-p
9192 case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX
, &v4
->src
, &v4
->dst
);
9196 const TCPHeader
*const tcp
= (const TCPHeader
*)trans
;
9200 // (a) RST is not set, AND
9201 // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
9202 wake
= (!(tcp
->flags
& 4) && (tcp
->flags
& 3) != 1);
9204 // For now, to reduce spurious wakeups, we wake only for TCP SYN,
9205 // except for ssh connections, where we'll wake for plain data packets too
9206 if (!mDNSSameIPPort(port
, SSH
) && !(tcp
->flags
& 2)) wake
= mDNSfalse
;
9208 LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX
,
9209 &v4
->src
, mDNSVal16(tcp
->src
), &v4
->dst
, mDNSVal16(port
),
9210 (tcp
->flags
& 2) ? " SYN" : "",
9211 (tcp
->flags
& 1) ? " FIN" : "",
9212 (tcp
->flags
& 4) ? " RST" : "");
9217 const UDPHeader
*const udp
= (const UDPHeader
*)trans
;
9218 mDNSu16 len
= (mDNSu16
)((mDNSu16
)trans
[4] << 8 | trans
[5]);
9222 // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
9223 if (mDNSSameIPPort(port
, IPSEC
)) wake
= (len
!= 9 || end
< trans
+ 9 || trans
[8] != 0xFF);
9225 // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
9226 // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
9227 // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
9228 // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
9229 if (mDNSSameIPPort(port
, ARD
)) wake
= (len
>= 118 && end
>= trans
+10 && trans
[8] == 0x13 && trans
[9] == 0x88);
9231 LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX
, &v4
->src
, mDNSVal16(udp
->src
), &v4
->dst
, mDNSVal16(port
));
9235 default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX
, v4
->protocol
, &v4
->src
, &v4
->dst
);
9241 AuthRecord
*rr
, *r2
;
9244 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9245 if (rr
->resrec
.InterfaceID
== InterfaceID
&&
9246 rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, v4
->dst
))
9248 const mDNSu8
*const tp
= (v4
->protocol
== 6) ? (const mDNSu8
*)"\x4_tcp" : (const mDNSu8
*)"\x4_udp";
9249 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
9250 if (r2
->resrec
.InterfaceID
== InterfaceID
&& mDNSSameEthAddress(&r2
->WakeUp
.HMAC
, &rr
->WakeUp
.HMAC
) &&
9251 r2
->resrec
.rrtype
== kDNSType_SRV
&& mDNSSameIPPort(r2
->resrec
.rdata
->u
.srv
.port
, port
) &&
9252 SameDomainLabel(ThirdLabel(r2
->resrec
.name
)->c
, tp
))
9254 if (!r2
&& mDNSSameIPPort(port
, IPSEC
)) r2
= rr
; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
9257 rr
->AnnounceCount
= 0;
9258 LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
9259 InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), &v4
->dst
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, r2
));
9260 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9263 LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
9264 InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), &v4
->dst
, &rr
->WakeUp
.HMAC
, tp
, mDNSVal16(port
));
9270 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9272 debugf("Got IPv6 from %.16a to %.16a", &v4
->src
, &v6
->dst
);
9277 mDNSlocal
void ConstructSleepProxyServerName(mDNS
*const m
, domainlabel
*name
)
9279 name
->c
[0] = mDNS_snprintf((char*)name
->c
+1, 62, "%d-%d-%d-%d %#s",
9280 m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
, &m
->nicelabel
);
9283 mDNSlocal
void SleepProxyServerCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
9285 if (result
== mStatus_NameConflict
)
9286 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
9287 else if (result
== mStatus_MemFree
)
9293 m
->SPSState
= (m
->SPSSocket
!= mDNSNULL
);
9297 ConstructSleepProxyServerName(m
, &name
);
9298 mDNS_RegisterService(m
, srs
,
9299 &name
, &SleepProxyServiceType
, &localdomain
,
9300 mDNSNULL
, m
->SPSSocket
->port
, // Host, port
9301 (mDNSu8
*)"", 1, // TXT data, length
9302 mDNSNULL
, 0, // Subtypes (none)
9303 mDNSInterface_Any
, // Interface ID
9304 SleepProxyServerCallback
, mDNSNULL
); // Callback and context
9306 LogSPS("Sleep Proxy Server %#s %s", srs
->RR_SRV
.resrec
.name
->c
, m
->SPSState
? "started" : "stopped");
9311 mDNSexport
void mDNSCoreBeSleepProxyServer(mDNS
*const m
, mDNSu8 sps
, mDNSu8 port
, mDNSu8 marginalpower
, mDNSu8 totpower
)
9313 // If turning off SPS, close our socket
9314 // (Do this first, BEFORE calling mDNS_DeregisterService below)
9315 if (!sps
&& m
->SPSSocket
) { mDNSPlatformUDPClose(m
->SPSSocket
); m
->SPSSocket
= mDNSNULL
; }
9317 // If turning off, or changing type, deregister old name
9318 if (m
->SPSState
== 1 && sps
!= m
->SPSType
)
9319 { m
->SPSState
= 2; mDNS_DeregisterService(m
, &m
->SPSRecords
); }
9321 // Record our new SPS parameters
9323 m
->SPSPortability
= port
;
9324 m
->SPSMarginalPower
= marginalpower
;
9325 m
->SPSTotalPower
= totpower
;
9327 // If turning on, open socket and advertise service
9332 m
->SPSSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
9333 if (!m
->SPSSocket
) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
9335 if (m
->SPSState
== 0) SleepProxyServerCallback(m
, &m
->SPSRecords
, mStatus_MemFree
);
9339 // ***************************************************************************
9340 #if COMPILER_LIKES_PRAGMA_MARK
9342 #pragma mark - Startup and Shutdown
9345 mDNSlocal
void mDNS_GrowCache_internal(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9347 if (storage
&& numrecords
)
9350 debugf("Adding cache storage for %d more records (%d bytes)", numrecords
, numrecords
*sizeof(CacheEntity
));
9351 for (i
=0; i
<numrecords
; i
++) storage
[i
].next
= &storage
[i
+1];
9352 storage
[numrecords
-1].next
= m
->rrcache_free
;
9353 m
->rrcache_free
= storage
;
9354 m
->rrcache_size
+= numrecords
;
9358 mDNSexport
void mDNS_GrowCache(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9361 mDNS_GrowCache_internal(m
, storage
, numrecords
);
9365 mDNSexport mStatus
mDNS_Init(mDNS
*const m
, mDNS_PlatformSupport
*const p
,
9366 CacheEntity
*rrcachestorage
, mDNSu32 rrcachesize
,
9367 mDNSBool AdvertiseLocalAddresses
, mDNSCallback
*Callback
, void *Context
)
9373 if (!rrcachestorage
) rrcachesize
= 0;
9377 m
->CanReceiveUnicastOn5353
= mDNSfalse
; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
9378 m
->AdvertiseLocalAddresses
= AdvertiseLocalAddresses
;
9379 m
->DivertMulticastAdvertisements
= mDNSfalse
;
9380 m
->mDNSPlatformStatus
= mStatus_Waiting
;
9381 m
->UnicastPort4
= zeroIPPort
;
9382 m
->UnicastPort6
= zeroIPPort
;
9383 m
->PrimaryMAC
= zeroEthAddr
;
9384 m
->MainCallback
= Callback
;
9385 m
->MainContext
= Context
;
9386 m
->rec
.r
.resrec
.RecordType
= 0;
9388 // For debugging: To catch and report locking failures
9390 m
->mDNS_reentrancy
= 0;
9391 m
->ShutdownTime
= 0;
9392 m
->lock_rrcache
= 0;
9393 m
->lock_Questions
= 0;
9394 m
->lock_Records
= 0;
9396 // Task Scheduling variables
9397 result
= mDNSPlatformTimeInit();
9398 if (result
!= mStatus_NoError
) return(result
);
9399 m
->timenow_adjust
= (mDNSs32
)mDNSRandom(0xFFFFFFFF);
9400 timenow
= mDNS_TimeNow_NoLock(m
);
9402 m
->timenow
= 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
9403 m
->timenow_last
= timenow
;
9404 m
->NextScheduledEvent
= timenow
;
9405 m
->SuppressSending
= timenow
;
9406 m
->NextCacheCheck
= timenow
+ 0x78000000;
9407 m
->NextScheduledQuery
= timenow
+ 0x78000000;
9408 m
->NextScheduledProbe
= timenow
+ 0x78000000;
9409 m
->NextScheduledResponse
= timenow
+ 0x78000000;
9410 m
->NextScheduledNATOp
= timenow
+ 0x78000000;
9411 m
->NextScheduledSPS
= timenow
+ 0x78000000;
9412 m
->RandomQueryDelay
= 0;
9413 m
->RandomReconfirmDelay
= 0;
9415 m
->SleepState
= SleepState_Awake
;
9417 m
->SystemWakeOnLANEnabled
= mDNSfalse
;
9421 // These fields only required for mDNS Searcher...
9422 m
->Questions
= mDNSNULL
;
9423 m
->NewQuestions
= mDNSNULL
;
9424 m
->CurrentQuestion
= mDNSNULL
;
9425 m
->LocalOnlyQuestions
= mDNSNULL
;
9426 m
->NewLocalOnlyQuestions
= mDNSNULL
;
9427 m
->rrcache_size
= 0;
9428 m
->rrcache_totalused
= 0;
9429 m
->rrcache_active
= 0;
9430 m
->rrcache_report
= 10;
9431 m
->rrcache_free
= mDNSNULL
;
9433 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++) m
->rrcache_hash
[slot
] = mDNSNULL
;
9435 mDNS_GrowCache_internal(m
, rrcachestorage
, rrcachesize
);
9437 // Fields below only required for mDNS Responder...
9438 m
->hostlabel
.c
[0] = 0;
9439 m
->nicelabel
.c
[0] = 0;
9440 m
->MulticastHostname
.c
[0] = 0;
9441 m
->HIHardware
.c
[0] = 0;
9442 m
->HISoftware
.c
[0] = 0;
9443 m
->ResourceRecords
= mDNSNULL
;
9444 m
->DuplicateRecords
= mDNSNULL
;
9445 m
->NewLocalRecords
= mDNSNULL
;
9446 m
->CurrentRecord
= mDNSNULL
;
9447 m
->HostInterfaces
= mDNSNULL
;
9448 m
->ProbeFailTime
= 0;
9449 m
->NumFailedProbes
= 0;
9450 m
->SuppressProbes
= 0;
9452 #ifndef UNICAST_DISABLED
9453 m
->NextuDNSEvent
= timenow
+ 0x78000000;
9454 m
->NextSRVUpdate
= timenow
+ 0x78000000;
9455 m
->SuppressStdPort53Queries
= 0;
9457 m
->ServiceRegistrations
= mDNSNULL
;
9458 m
->DNSServers
= mDNSNULL
;
9460 m
->Router
= zeroAddr
;
9461 m
->AdvertisedV4
= zeroAddr
;
9462 m
->AdvertisedV6
= zeroAddr
;
9464 m
->AuthInfoList
= mDNSNULL
;
9466 m
->ReverseMap
.ThisQInterval
= -1;
9467 m
->StaticHostname
.c
[0] = 0;
9469 m
->Hostnames
= mDNSNULL
;
9470 m
->AutoTunnelHostAddr
.b
[0] = 0;
9471 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
9472 m
->AutoTunnelLabel
.c
[0] = 0;
9474 m
->RegisterSearchDomains
= mDNSfalse
;
9476 // NAT traversal fields
9477 m
->NATTraversals
= mDNSNULL
;
9478 m
->CurrentNATTraversal
= mDNSNULL
;
9479 m
->retryIntervalGetAddr
= 0; // delta between time sent and retry
9480 m
->retryGetAddr
= timenow
+ 0x78000000; // absolute time when we retry
9481 m
->ExternalAddress
= zerov4Addr
;
9483 m
->NATMcastRecvskt
= mDNSNULL
;
9484 m
->LastNATupseconds
= 0;
9485 m
->LastNATReplyLocalTime
= timenow
;
9486 m
->LastNATMapResultCode
= NATErr_None
;
9488 m
->UPnPInterfaceID
= 0;
9489 m
->SSDPSocket
= mDNSNULL
;
9490 m
->SSDPWANPPPConnection
= mDNSfalse
;
9491 m
->UPnPRouterPort
= zeroIPPort
;
9492 m
->UPnPSOAPPort
= zeroIPPort
;
9493 m
->UPnPRouterURL
= mDNSNULL
;
9494 m
->UPnPWANPPPConnection
= mDNSfalse
;
9495 m
->UPnPSOAPURL
= mDNSNULL
;
9496 m
->UPnPRouterAddressString
= mDNSNULL
;
9497 m
->UPnPSOAPAddressString
= mDNSNULL
;
9499 m
->SPSPortability
= 0;
9500 m
->SPSMarginalPower
= 0;
9501 m
->SPSTotalPower
= 0;
9503 m
->SPSProxyListChanged
= mDNSNULL
;
9504 m
->SPSSocket
= mDNSNULL
;
9505 m
->SPSBrowseCallback
= mDNSNULL
;
9506 m
->ProxyRecords
= 0;
9510 #if APPLE_OSX_mDNSResponder
9511 m
->TunnelClients
= mDNSNULL
;
9514 result
= mDNSPlatformInit(m
);
9516 #ifndef UNICAST_DISABLED
9517 // It's better to do this *after* the platform layer has set up the
9518 // interface list and security credentials
9519 uDNS_SetupDNSConfig(m
); // Get initial DNS configuration
9525 mDNSexport
void mDNS_ConfigChanged(mDNS
*const m
)
9527 if (m
->SPSState
== 1)
9529 domainlabel name
, newname
;
9530 domainname type
, domain
;
9531 DeconstructServiceName(m
->SPSRecords
.RR_SRV
.resrec
.name
, &name
, &type
, &domain
);
9532 ConstructSleepProxyServerName(m
, &newname
);
9533 if (!SameDomainLabelCS(name
.c
, newname
.c
))
9535 LogSPS("Renaming SPS from “%#s” to “%#s”", name
.c
, newname
.c
);
9536 // When SleepProxyServerCallback gets the mStatus_MemFree message,
9537 // it will reregister the service under the new name
9539 mDNS_DeregisterService(m
, &m
->SPSRecords
);
9543 if (m
->MainCallback
)
9544 m
->MainCallback(m
, mStatus_ConfigChanged
);
9547 mDNSlocal
void DynDNSHostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
9550 debugf("NameStatusCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
9551 mDNSPlatformDynDNSHostNameStatusChanged(rr
->resrec
.name
, result
);
9554 mDNSlocal
void PurgeOrReconfirmCacheRecord(mDNS
*const m
, CacheRecord
*cr
, const DNSServer
* const ptr
, mDNSBool lameduck
)
9556 mDNSBool purge
= cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
||
9557 cr
->resrec
.rrtype
== kDNSType_A
||
9558 cr
->resrec
.rrtype
== kDNSType_AAAA
||
9559 cr
->resrec
.rrtype
== kDNSType_SRV
;
9563 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
));
9565 if (purge
) mDNS_PurgeCacheResourceRecord(m
, cr
);
9566 else mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
9569 mDNSexport mStatus
uDNS_SetupDNSConfig(mDNS
*const m
)
9577 DNSServer
*ptr
, **p
= &m
->DNSServers
;
9578 const DNSServer
*oldServers
= m
->DNSServers
;
9581 debugf("uDNS_SetupDNSConfig: entry");
9583 if (m
->RegisterSearchDomains
) uDNS_RegisterSearchDomains(m
);
9587 // Let the platform layer get the current DNS information
9588 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
9589 // (no need to hit the network with domain enumeration queries until we actually need that information).
9590 for (ptr
= m
->DNSServers
; ptr
; ptr
= ptr
->next
) ptr
->flags
|= DNSServer_FlagDelete
;
9592 mDNSPlatformSetDNSConfig(m
, mDNStrue
, mDNSfalse
, &fqdn
, mDNSNULL
, mDNSNULL
);
9594 // Update our qDNSServer pointers before we go and free the DNSServer object memory
9595 for (q
= m
->Questions
; q
; q
=q
->next
)
9596 if (!mDNSOpaque16IsZero(q
->TargetQID
))
9598 DNSServer
*s
= GetServerForName(m
, &q
->qname
);
9599 DNSServer
*t
= q
->qDNSServer
;
9602 // If DNS Server for this question has changed, reactivate it
9603 debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
9604 t
, t
? &t
->addr
: mDNSNULL
, mDNSVal16(t
? t
->port
: zeroIPPort
), t
? t
->domain
.c
: (mDNSu8
*)"",
9605 s
, s
? &s
->addr
: mDNSNULL
, mDNSVal16(s
? s
->port
: zeroIPPort
), s
? s
->domain
.c
: (mDNSu8
*)"",
9606 q
->qname
.c
, DNSTypeName(q
->qtype
));
9608 q
->unansweredQueries
= 0;
9609 ActivateUnicastQuery(m
, q
, mDNStrue
);
9613 // Flush all records that match a new resolver
9614 FORALL_CACHERECORDS(slot
, cg
, cr
)
9616 ptr
= GetServerForName(m
, cr
->resrec
.name
);
9617 if (ptr
&& (ptr
->flags
& DNSServer_FlagNew
) && !cr
->resrec
.InterfaceID
)
9618 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNSfalse
);
9623 if (((*p
)->flags
& DNSServer_FlagDelete
) != 0)
9625 // Scan our cache, looking for uDNS records that we would have queried this server for.
9626 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
9627 // different DNS servers can give different answers to the same question.
9629 ptr
->flags
&= ~DNSServer_FlagDelete
; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
9630 FORALL_CACHERECORDS(slot
, cg
, cr
)
9631 if (!cr
->resrec
.InterfaceID
&& GetServerForName(m
, cr
->resrec
.name
) == ptr
)
9632 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNStrue
);
9634 debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr
, &ptr
->addr
, mDNSVal16(ptr
->port
), ptr
->domain
.c
);
9635 mDNSPlatformMemFree(ptr
);
9639 (*p
)->flags
&= ~DNSServer_FlagNew
;
9644 // 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).
9645 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
9646 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
9647 // 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.
9648 if ((m
->DNSServers
!= mDNSNULL
) != (oldServers
!= mDNSNULL
))
9651 FORALL_CACHERECORDS(slot
, cg
, cr
) if (!cr
->resrec
.InterfaceID
) { mDNS_PurgeCacheResourceRecord(m
, cr
); count
++; }
9652 LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
9653 m
->DNSServers
? "DNS server became" : "No DNS servers", count
);
9656 // If we no longer have any DNS servers, we need to force anything that needs to get zone data
9657 // to get that information again (which will fail, since we have no more DNS servers)
9658 if ((m
->DNSServers
== mDNSNULL
) && (oldServers
!= mDNSNULL
)) RestartRecordGetZoneData(m
);
9660 // Did our FQDN change?
9661 if (!SameDomainName(&fqdn
, &m
->FQDN
))
9663 if (m
->FQDN
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &m
->FQDN
);
9665 AssignDomainName(&m
->FQDN
, &fqdn
);
9669 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
9670 mDNS_AddDynDNSHostName(m
, &m
->FQDN
, DynDNSHostNameCallback
, mDNSNULL
);
9676 // handle router and primary interface changes
9677 v4
= v6
= r
= zeroAddr
;
9678 v4
.type
= r
.type
= mDNSAddrType_IPv4
;
9680 if (mDNSPlatformGetPrimaryInterface(m
, &v4
, &v6
, &r
) == mStatus_NoError
&& !mDNSv4AddressIsLinkLocal(&v4
.ip
.v4
))
9682 mDNS_SetPrimaryInterfaceInfo(m
,
9683 !mDNSIPv4AddressIsZero(v4
.ip
.v4
) ? &v4
: mDNSNULL
,
9684 !mDNSIPv6AddressIsZero(v6
.ip
.v6
) ? &v6
: mDNSNULL
,
9685 !mDNSIPv4AddressIsZero(r
.ip
.v4
) ? &r
: mDNSNULL
);
9689 mDNS_SetPrimaryInterfaceInfo(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
9690 if (m
->FQDN
.c
[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1); // Set status to 1 to indicate temporary failure
9693 return mStatus_NoError
;
9696 mDNSexport
void mDNSCoreInitComplete(mDNS
*const m
, mStatus result
)
9698 m
->mDNSPlatformStatus
= result
;
9699 if (m
->MainCallback
)
9702 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
9703 m
->MainCallback(m
, mStatus_NoError
);
9704 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
9709 extern ServiceRecordSet
*CurrentServiceRecordSet
;
9711 mDNSlocal
void DeregLoop(mDNS
*const m
, AuthRecord
*const start
)
9713 m
->CurrentRecord
= start
;
9714 while (m
->CurrentRecord
)
9716 AuthRecord
*rr
= m
->CurrentRecord
;
9717 if (rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
9719 LogInfo("DeregLoop: Deregistering %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9720 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
9722 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
9723 // the list may have been changed in that call.
9724 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
9725 m
->CurrentRecord
= rr
->next
;
9729 mDNSexport
void mDNS_StartExit(mDNS
*const m
)
9731 NetworkInterfaceInfo
*intf
;
9736 m
->ShutdownTime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
9738 mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
9739 mDNSCoreBeSleepProxyServer(m
, 0, 0, 0, 0);
9740 mDNS_ReclaimLockAfterCallback();
9742 #ifndef UNICAST_DISABLED
9746 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
9747 // because we deregister all records and services later in this routine
9748 while (m
->Hostnames
) mDNS_RemoveDynDNSHostName(m
, &m
->Hostnames
->fqdn
);
9750 // For each member of our SearchList, deregister any records it may have created, and cut them from the list.
9751 // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
9752 // and we may crash because the list still contains dangling pointers.
9753 for (s
= SearchList
; s
; s
= s
->next
)
9756 ARListElem
*dereg
= s
->AuthRecs
;
9757 s
->AuthRecs
= s
->AuthRecs
->next
;
9758 mDNS_Deregister_internal(m
, &dereg
->ar
, mDNS_Dereg_normal
); // Memory will be freed in the FreeARElemCallback
9763 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
9764 if (intf
->Advertise
)
9765 DeadvertiseInterface(m
, intf
);
9767 // Shut down all our active NAT Traversals
9768 while (m
->NATTraversals
)
9770 NATTraversalInfo
*t
= m
->NATTraversals
;
9771 mDNS_StopNATOperation_internal(m
, t
); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
9773 // After stopping the NAT Traversal, we zero out the fields.
9774 // This has particularly important implications for our AutoTunnel records --
9775 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
9776 // handlers to just turn around and attempt to re-register those same records.
9777 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
9778 t
->ExternalAddress
= zerov4Addr
;
9779 t
->ExternalPort
= zeroIPPort
;
9781 t
->Result
= mStatus_NoError
;
9784 // Make sure there are nothing but deregistering records remaining in the list
9785 if (m
->CurrentRecord
)
9786 LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
9788 // We're in the process of shutting down, so queries, etc. are no longer available.
9789 // Consequently, determining certain information, e.g. the uDNS update server's IP
9790 // address, will not be possible. The records on the main list are more likely to
9791 // already contain such information, so we deregister the duplicate records first.
9792 LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
9793 DeregLoop(m
, m
->DuplicateRecords
);
9794 LogInfo("mDNS_StartExit: Deregistering resource records");
9795 DeregLoop(m
, m
->ResourceRecords
);
9797 // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
9798 // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
9799 if (m
->NextScheduledResponse
- m
->timenow
< mDNSPlatformOneSecond
)
9801 m
->NextScheduledResponse
= m
->timenow
;
9802 m
->SuppressSending
= 0;
9805 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9806 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
9807 while (CurrentServiceRecordSet
)
9809 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
9810 LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs
->RR_SRV
.resrec
.name
->c
);
9811 uDNS_DeregisterService(m
, srs
);
9812 if (CurrentServiceRecordSet
== srs
)
9813 CurrentServiceRecordSet
= srs
->uDNS_next
;
9817 if (m
->ResourceRecords
) LogInfo("mDNS_StartExit: Sending final record deregistrations");
9818 else LogInfo("mDNS_StartExit: No deregistering records remain");
9820 if (m
->ServiceRegistrations
) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
9821 else LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
9823 for (rr
= m
->DuplicateRecords
; rr
; rr
= rr
->next
)
9824 LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9826 // If any deregistering records remain, send their deregistration announcements before we exit
9827 if (m
->mDNSPlatformStatus
!= mStatus_NoError
) DiscardDeregistrations(m
);
9831 LogInfo("mDNS_StartExit: done");
9834 mDNSexport
void mDNS_FinalExit(mDNS
*const m
)
9836 mDNSu32 rrcache_active
= 0;
9837 mDNSu32 rrcache_totalused
= 0;
9840 ServiceRecordSet
*srs
;
9842 LogInfo("mDNS_FinalExit: mDNSPlatformClose");
9843 mDNSPlatformClose(m
);
9845 rrcache_totalused
= m
->rrcache_totalused
;
9846 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
9848 while (m
->rrcache_hash
[slot
])
9850 CacheGroup
*cg
= m
->rrcache_hash
[slot
];
9853 CacheRecord
*cr
= cg
->members
;
9854 cg
->members
= cg
->members
->next
;
9855 if (cr
->CRActiveQuestion
) rrcache_active
++;
9856 ReleaseCacheRecord(m
, cr
);
9858 cg
->rrcache_tail
= &cg
->members
;
9859 ReleaseCacheGroup(m
, &m
->rrcache_hash
[slot
]);
9862 debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused
, rrcache_active
);
9863 if (rrcache_active
!= m
->rrcache_active
)
9864 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active
, m
->rrcache_active
);
9866 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
9867 LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9869 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
9870 LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs
, srs
->RR_SRV
.resrec
.name
->c
);
9872 LogInfo("mDNS_FinalExit: done");