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.969.2.1 2009/07/23 23:41:25 cheshire
42 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
44 Revision 1.969 2009/06/30 21:18:19 cheshire
45 <rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
47 1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
48 2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
50 Revision 1.968 2009/06/29 23:51:09 cheshire
51 <rdar://problem/6690034> Can't bind to Active Directory
53 Revision 1.967 2009/06/27 00:25:27 cheshire
54 <rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
55 Removed overly-complicate and ineffective multi-packet known-answer snooping code
56 (Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
58 Revision 1.966 2009/06/26 01:55:55 cheshire
59 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
60 Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
61 add additional NSEC records only when there's space to do that without having to generate an additional packet
63 Revision 1.965 2009/06/24 22:14:21 cheshire
64 <rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
66 Revision 1.964 2009/06/03 23:07:13 cheshire
67 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
68 Large records were not being added in cases where an NSEC record was also required
70 Revision 1.963 2009/05/28 00:39:19 cheshire
71 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
72 After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
74 Revision 1.962 2009/05/19 23:40:37 cheshire
75 <rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
76 Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
78 Revision 1.961 2009/05/19 23:00:43 cheshire
79 Improved comments and debugging messages
81 Revision 1.960 2009/05/13 17:25:33 mkrochma
82 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
83 Sleep proxy client should only look for services being advertised via Multicast
85 Revision 1.959 2009/05/12 23:10:31 cheshire
86 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
87 Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
89 Revision 1.958 2009/05/12 19:19:20 cheshire
90 <rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
92 Revision 1.957 2009/05/07 23:56:25 cheshire
93 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
94 To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
96 Revision 1.956 2009/05/07 23:46:27 cheshire
97 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
99 Revision 1.955 2009/05/07 23:40:54 cheshire
100 Minor code rearrangement in preparation for upcoming changes
102 Revision 1.954 2009/05/01 21:28:34 cheshire
103 <rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
104 No longer suspend network operations after we've acknowledged that the machine is going to sleep,
105 because other software may not have yet acknowledged the sleep event, and may be still trying
106 to do unicast DNS queries or other Bonjour operations.
108 Revision 1.953 2009/05/01 19:17:35 cheshire
109 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
111 Revision 1.952 2009/05/01 19:16:45 mcguire
112 <rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
114 Revision 1.951 2009/04/28 23:48:19 jessic2
115 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0
117 Revision 1.950 2009/04/25 01:17:10 mcguire
118 Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
120 Revision 1.949 2009/04/25 01:11:02 mcguire
121 Refactor: create separate function: RestartRecordGetZoneData
123 Revision 1.948 2009/04/24 21:25:16 cheshire
124 <rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
126 Revision 1.947 2009/04/24 19:41:12 mcguire
127 <rdar://problem/6791775> 4 second delay in DNS response
129 Revision 1.946 2009/04/24 19:28:39 mcguire
130 <rdar://problem/6791775> 4 second delay in DNS response
132 Revision 1.945 2009/04/24 00:30:30 cheshire
133 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
134 Added code to generate and process NSEC records
136 Revision 1.944 2009/04/23 22:06:29 cheshire
137 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
138 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
140 Revision 1.943 2009/04/22 01:19:56 jessic2
141 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
143 Revision 1.942 2009/04/21 02:13:29 cheshire
144 <rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
145 Made code less susceptible to being tricked by stale packets echoed back from the network.
147 Revision 1.941 2009/04/15 22:22:23 mcguire
148 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
149 Additional fix: protect against deref of NULL
151 Revision 1.940 2009/04/15 20:42:51 mcguire
152 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
154 Revision 1.939 2009/04/11 00:19:32 jessic2
155 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
157 Revision 1.938 2009/04/06 23:44:57 cheshire
158 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
160 Revision 1.937 2009/04/04 00:14:49 mcguire
161 fix logging in BeginSleepProcessing
163 Revision 1.936 2009/04/04 00:10:59 mcguire
164 don't ignore m->SystemWakeOnLANEnabled when going to sleep
166 Revision 1.935 2009/04/01 17:50:11 mcguire
169 Revision 1.934 2009/03/27 17:17:58 cheshire
170 Improved "Ignoring suspect uDNS response" debugging message
172 Revision 1.933 2009/03/21 02:40:21 cheshire
173 <rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
175 Revision 1.932 2009/03/20 23:53:03 jessic2
176 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
178 Revision 1.931 2009/03/18 19:08:15 cheshire
179 Show old/new sleep sequence numbers in logical order
181 Revision 1.930 2009/03/17 23:40:45 cheshire
182 For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
184 Revision 1.929 2009/03/17 21:55:56 cheshire
185 Fixed mistake in logic for decided when we're ready to go to sleep
187 Revision 1.928 2009/03/17 19:48:12 cheshire
188 <rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
190 Revision 1.927 2009/03/17 01:22:56 cheshire
191 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
192 Initial support for resolving up to three Sleep Proxies in parallel
194 Revision 1.926 2009/03/17 01:05:07 mcguire
195 <rdar://problem/6657640> Reachability fixes on DNS config change
197 Revision 1.925 2009/03/13 01:35:36 mcguire
198 <rdar://problem/6657640> Reachability fixes on DNS config change
200 Revision 1.924 2009/03/10 23:45:20 cheshire
201 Added comments explaining usage of SetSPSProxyListChanged()
203 Revision 1.923 2009/03/09 21:53:02 cheshire
204 <rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
206 Revision 1.922 2009/03/09 21:30:17 cheshire
207 Improved some LogSPS messages; made RestartProbing() subroutine
209 Revision 1.921 2009/03/06 22:53:31 cheshire
210 Don't bother registering with Sleep Proxy if we have no advertised services
212 Revision 1.920 2009/03/06 20:08:55 cheshire
213 <rdar://problem/6601429> Sleep Proxy: Return error responses to clients
215 Revision 1.919 2009/03/05 21:54:43 cheshire
216 Improved "Sleep Proxy Server started / stopped" message
218 Revision 1.918 2009/03/04 01:37:14 cheshire
219 <rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
221 Revision 1.917 2009/03/03 23:14:25 cheshire
222 Got rid of code duplication by making subroutine "SetupOwnerOpt"
224 Revision 1.916 2009/03/03 23:04:43 cheshire
225 For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
227 Revision 1.915 2009/03/03 22:51:53 cheshire
228 <rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
230 Revision 1.914 2009/03/03 00:46:09 cheshire
231 Additional debugging information in ResolveSimultaneousProbe
233 Revision 1.913 2009/02/27 03:08:47 cheshire
234 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
236 Revision 1.912 2009/02/27 02:31:28 cheshire
237 Improved "Record not found in list" debugging message
239 Revision 1.911 2009/02/21 01:42:11 cheshire
242 Revision 1.910 2009/02/19 01:50:53 cheshire
243 Converted some LogInfo messages to LogSPS
245 Revision 1.909 2009/02/14 00:04:59 cheshire
246 Left-justify interface names
248 Revision 1.908 2009/02/13 19:40:07 cheshire
249 Improved alignment of LogSPS messages
251 Revision 1.907 2009/02/13 18:16:05 cheshire
252 Fixed some compile warnings
254 Revision 1.906 2009/02/13 06:10:17 cheshire
255 Convert LogOperation messages to LogInfo
257 Revision 1.905 2009/02/12 20:57:24 cheshire
258 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
260 Revision 1.904 2009/02/11 02:37:29 cheshire
261 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
262 Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
263 so that it happens correctly even when we delay re-sleep due to a very short wakeup.
265 Revision 1.903 2009/02/09 23:34:31 cheshire
266 Additional logging for debugging unknown packets
268 Revision 1.902 2009/02/07 05:57:01 cheshire
269 Fixed debugging log message
271 Revision 1.901 2009/02/07 02:57:31 cheshire
272 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
274 Revision 1.900 2009/02/02 21:29:24 cheshire
275 <rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
276 If Negative response for our special Microsoft Active Directory "local SOA" check has no
277 SOA record in the authority section, assume we should cache the negative result for 24 hours
279 Revision 1.899 2009/01/31 00:37:50 cheshire
280 When marking cache records for deletion in response to a uDNS response,
281 make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
283 Revision 1.898 2009/01/30 23:49:20 cheshire
284 Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
286 Revision 1.897 2009/01/30 22:04:49 cheshire
287 Workaround to reduce load on root name servers when caching the SOA record for "."
289 Revision 1.896 2009/01/30 22:00:05 cheshire
290 Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
292 Revision 1.895 2009/01/30 17:46:39 cheshire
293 Improved debugging messages for working out why spurious name conflicts are happening
295 Revision 1.894 2009/01/30 00:22:09 cheshire
296 <rdar://problem/6540743> No announcement after probing & no conflict notice
298 Revision 1.893 2009/01/29 22:27:03 mcguire
299 <rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
301 Revision 1.892 2009/01/24 01:38:23 cheshire
302 Fixed error in logic for targeted queries
304 Revision 1.891 2009/01/22 02:14:25 cheshire
305 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
307 Revision 1.890 2009/01/22 00:45:02 cheshire
308 Improved SPS debugging log messages; we are eligible to start answering ARP requests
309 after we send our first announcement, not after we send our last probe
311 Revision 1.889 2009/01/21 03:43:56 mcguire
312 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
314 Revision 1.888 2009/01/20 00:27:43 mcguire
315 <rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
317 Revision 1.887 2009/01/17 05:14:37 cheshire
318 Convert SendQueries Probe messages to LogSPS messages
320 Revision 1.886 2009/01/17 03:43:09 cheshire
321 Added SPSLogging switch to facilitate Sleep Proxy Server debugging
323 Revision 1.885 2009/01/16 22:44:18 cheshire
324 <rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
326 Revision 1.884 2009/01/16 21:43:52 cheshire
327 Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
329 Revision 1.883 2009/01/16 21:11:18 cheshire
330 When purging expired Sleep Proxy records, need to check DuplicateRecords list too
332 Revision 1.882 2009/01/16 19:54:28 cheshire
333 Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
335 Revision 1.881 2009/01/14 01:38:38 mcguire
336 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
338 Revision 1.880 2009/01/10 01:51:19 cheshire
339 q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
341 Revision 1.879 2009/01/10 01:43:52 cheshire
342 Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
344 Revision 1.878 2009/01/10 01:38:10 cheshire
345 Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
347 Revision 1.877 2009/01/10 01:36:08 cheshire
348 Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
350 Revision 1.876 2009/01/09 22:56:06 cheshire
351 Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
353 Revision 1.875 2009/01/09 22:54:46 cheshire
354 When tranferring record from DuplicateRecords list to ResourceRecords list,
355 need to copy across state of 'Answered Local-Only-Questions' flag
357 Revision 1.874 2009/01/07 23:07:24 cheshire
358 <rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
360 Revision 1.873 2008/12/17 00:18:59 mkrochma
361 Change some LogMsg to LogOperation before submitting
363 Revision 1.872 2008/12/12 01:30:40 cheshire
364 Update platform-layer BPF filters when we add or remove AddressProxy records
366 Revision 1.871 2008/12/10 02:25:31 cheshire
367 Minor fixes to use of LogClientOperations symbol
369 Revision 1.870 2008/12/10 02:11:41 cheshire
370 ARMv5 compiler doesn't like uncommented stuff after #endif
372 Revision 1.869 2008/12/05 02:35:24 mcguire
373 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
375 Revision 1.868 2008/12/04 21:08:51 mcguire
376 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
378 Revision 1.867 2008/11/26 21:19:36 cheshire
379 <rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
381 Revision 1.866 2008/11/26 20:32:46 cheshire
382 <rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
383 Update advertised name when Sleep Proxy "intent" metric changes
385 Revision 1.865 2008/11/26 19:49:25 cheshire
386 Record originally-requested port in sr->NATinfo.IntPort
388 Revision 1.864 2008/11/26 19:02:37 cheshire
389 Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
391 Revision 1.863 2008/11/26 03:59:03 cheshire
392 Wait 30 seconds before starting ARP Announcements
394 Revision 1.862 2008/11/25 23:43:07 cheshire
395 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
396 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
398 Revision 1.861 2008/11/25 22:46:30 cheshire
399 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
401 Revision 1.860 2008/11/25 05:07:15 cheshire
402 <rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
404 Revision 1.859 2008/11/20 02:07:56 cheshire
405 <rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
407 Revision 1.858 2008/11/20 01:38:36 cheshire
408 For consistency with other parts of the code, changed code to only check
409 that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
411 Revision 1.857 2008/11/14 22:55:18 cheshire
414 Revision 1.856 2008/11/14 21:08:28 cheshire
415 Only put owner option in query packet if we have a non-zero MAC address to put
416 Only process owner options in received query packets if the MAC address in the option is non-zero
418 Revision 1.855 2008/11/14 02:29:54 cheshire
419 If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
421 Revision 1.854 2008/11/14 00:00:53 cheshire
422 After client machine wakes up, Sleep Proxy machine need to remove any records
423 it was temporarily holding as proxy for that client
425 Revision 1.853 2008/11/13 19:07:30 cheshire
426 Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
428 Revision 1.852 2008/11/12 23:23:11 cheshire
429 Before waking a host, check to see if it has an SRV record advertising
430 a service on the port in question, and if not, don't bother waking it.
432 Revision 1.851 2008/11/12 01:54:15 cheshire
433 <rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
434 It turns out it is beneficial to have the domain on the end, because it allows better name compression
436 Revision 1.850 2008/11/11 01:56:57 cheshire
437 Improved name conflict log messages
439 Revision 1.849 2008/11/06 23:50:43 cheshire
440 Allow plain (non-SYN) ssh data packets to wake sleeping host
442 Revision 1.848 2008/11/05 02:40:28 mkrochma
443 Change mDNS_SetFQDN syslog mesage to debugf
445 Revision 1.847 2008/11/04 23:06:50 cheshire
446 Split RDataBody union definition into RDataBody and RDataBody2, and removed
447 SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
449 Revision 1.846 2008/11/04 22:21:44 cheshire
450 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
452 Revision 1.845 2008/11/03 23:52:05 cheshire
453 Improved ARP debugging messages to differentiate ARP Announcements from Requests
455 Revision 1.844 2008/10/31 23:43:51 cheshire
456 Fixed compile error in Posix build
458 Revision 1.843 2008/10/31 22:55:04 cheshire
459 Initial support for structured SPS names
461 Revision 1.842 2008/10/30 00:12:07 cheshire
462 Fixed spin when PutSPSRec fails to put a record because it's too big to fit
464 Revision 1.841 2008/10/29 23:23:38 cheshire
465 Refined cache size reporting to go in steps of 1000 when number is above 1000
467 Revision 1.840 2008/10/29 21:34:10 cheshire
468 Removed some old debugging messages
470 Revision 1.839 2008/10/29 21:31:32 cheshire
471 Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
473 Revision 1.838 2008/10/28 18:30:37 cheshire
474 Added debugging message in mDNSCoreReceiveRawPacket
476 Revision 1.837 2008/10/24 23:58:05 cheshire
477 Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
479 Revision 1.836 2008/10/24 23:18:18 cheshire
480 If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
482 Revision 1.835 2008/10/24 23:07:59 cheshire
483 Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
485 Revision 1.834 2008/10/24 23:03:24 cheshire
486 Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
488 Revision 1.833 2008/10/24 23:01:26 cheshire
489 To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
491 Revision 1.832 2008/10/24 22:58:24 cheshire
492 For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
494 Revision 1.831 2008/10/24 22:50:41 cheshire
495 When waking SPS client, include interface name in syslog message
497 Revision 1.830 2008/10/24 20:50:34 cheshire
498 Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
500 Revision 1.829 2008/10/23 23:55:57 cheshire
501 Fixed some missing "const" declarations
503 Revision 1.828 2008/10/23 22:25:56 cheshire
504 Renamed field "id" to more descriptive "updateid"
506 Revision 1.827 2008/10/23 03:06:25 cheshire
507 Fixed "Waking host" log message
509 Revision 1.826 2008/10/22 23:21:30 cheshire
510 Make sure we have enough bytes before reading into the transport-level header
512 Revision 1.825 2008/10/22 22:31:53 cheshire
513 Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
515 Revision 1.824 2008/10/22 20:00:31 cheshire
516 If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
518 Revision 1.823 2008/10/22 19:55:35 cheshire
519 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
521 Revision 1.822 2008/10/22 01:41:39 cheshire
522 Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
524 Revision 1.821 2008/10/22 01:12:53 cheshire
525 Answer ARP Requests for any IP address we're proxying for
527 Revision 1.820 2008/10/21 01:11:11 cheshire
528 Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
530 Revision 1.819 2008/10/20 22:16:27 cheshire
531 Updated comments; increased cache shedding threshold from 3000 to 4000
533 Revision 1.818 2008/10/16 22:01:54 cheshire
534 Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
536 Revision 1.817 2008/10/16 21:40:49 cheshire
537 Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
539 Revision 1.816 2008/10/15 23:12:36 cheshire
540 On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
542 Revision 1.815 2008/10/15 20:46:38 cheshire
543 When transferring records to SPS, include Lease Option
545 Revision 1.814 2008/10/15 19:51:27 cheshire
546 Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
548 Revision 1.813 2008/10/15 00:09:23 cheshire
549 When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
551 Revision 1.812 2008/10/15 00:01:40 cheshire
552 When going to sleep, discover and resolve SPS, and if successful, transfer records to it
554 Revision 1.811 2008/10/14 23:51:57 cheshire
555 Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
557 Revision 1.810 2008/10/14 21:37:55 cheshire
558 Removed unnecessary m->BeSleepProxyServer variable
560 Revision 1.809 2008/10/10 23:45:48 cheshire
561 For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
562 not a wide-area unicast hostname
564 Revision 1.808 2008/10/09 18:59:19 cheshire
565 Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
567 Revision 1.807 2008/10/07 15:56:58 cheshire
568 Fixed "unused variable" warnings in non-debug builds
570 Revision 1.806 2008/10/04 00:53:37 cheshire
571 On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
573 Revision 1.805 2008/10/03 18:17:28 cheshire
574 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
575 Update advertised Sleep Proxy Server name if user changes computer name
577 Revision 1.804 2008/10/03 01:26:06 mcguire
578 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
579 Put back Duplicate Record check
581 Revision 1.803 2008/10/02 23:38:56 mcguire
582 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
584 Revision 1.802 2008/10/02 23:13:48 cheshire
585 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
586 Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
588 Revision 1.801 2008/10/02 22:51:04 cheshire
589 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
590 Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
592 Revision 1.800 2008/10/02 22:13:15 cheshire
593 <rdar://problem/6230680> 100ms delay on shutdown
594 Additional refinement: Also need to clear m->SuppressSending
596 Revision 1.799 2008/09/29 20:12:37 cheshire
597 Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
599 Revision 1.798 2008/09/26 19:53:14 cheshire
600 Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
602 Revision 1.797 2008/09/25 20:40:59 cheshire
603 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
604 In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
606 Revision 1.796 2008/09/25 20:17:10 cheshire
607 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
608 Added defensive code to make sure *all* records of a ServiceRecordSet have
609 completed deregistering before we pass on the mStatus_MemFree message
611 Revision 1.795 2008/09/25 00:30:11 cheshire
612 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
614 Revision 1.794 2008/09/24 23:48:05 cheshire
615 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
616 it only needs to access the embedded SRV member of the set
618 Revision 1.793 2008/09/23 04:11:53 cheshire
619 <rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
621 Revision 1.792 2008/09/23 02:30:07 cheshire
622 Get rid of PutResourceRecordCappedTTL()
624 Revision 1.791 2008/09/20 00:34:21 mcguire
625 <rdar://problem/6129039> BTMM: Add support for WANPPPConnection
627 Revision 1.790 2008/09/18 22:46:34 cheshire
628 <rdar://problem/6230680> 100ms delay on shutdown
630 Revision 1.789 2008/09/18 06:15:06 mkrochma
631 <rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
633 Revision 1.788 2008/09/16 21:11:41 cheshire
634 <rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
636 Revision 1.787 2008/09/05 22:53:24 cheshire
637 Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
639 Revision 1.786 2008/09/05 22:23:28 cheshire
640 Moved initialization of "question->LocalSocket" to more logical place
642 Revision 1.785 2008/08/14 19:20:55 cheshire
643 <rdar://problem/6143846> Negative responses over TCP incorrectly rejected
645 Revision 1.784 2008/08/13 00:47:53 mcguire
646 Handle failures when packet logging
648 Revision 1.783 2008/07/25 07:09:51 mcguire
649 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
651 Revision 1.782 2008/07/24 20:23:03 cheshire
652 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
654 Revision 1.781 2008/07/18 21:37:35 mcguire
655 <rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
657 Revision 1.780 2008/07/18 02:24:36 cheshire
658 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
659 Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
660 we're still on our first or second query after an interface registration or wake from sleep).
662 Revision 1.779 2008/07/18 01:05:23 cheshire
663 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
665 Revision 1.778 2008/06/26 17:24:11 mkrochma
666 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
668 Revision 1.777 2008/06/19 01:20:48 mcguire
669 <rdar://problem/4206534> Use all configured DNS servers
671 Revision 1.776 2008/04/17 20:14:14 cheshire
672 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
674 Revision 1.775 2008/03/26 01:53:34 mcguire
675 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
677 Revision 1.774 2008/03/17 17:46:08 mcguire
678 When activating an LLQ, reset all the important state and destroy any tcp connection,
679 so that everything will be restarted as if the question had just been asked.
680 Also reset servPort, so that the SOA query will be re-issued.
682 Revision 1.773 2008/03/14 22:52:36 mcguire
683 <rdar://problem/5321824> write status to the DS
684 Update status when any unicast LLQ is started
686 Revision 1.772 2008/03/06 02:48:34 mcguire
687 <rdar://problem/5321824> write status to the DS
689 Revision 1.771 2008/02/26 22:04:44 cheshire
690 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
691 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
692 question while it's still in our 'm->NewQuestions' section of the list
694 Revision 1.770 2008/02/22 23:09:02 cheshire
695 <rdar://problem/5338420> BTMM: Not processing additional records
697 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
698 2. Once we decide a record is acceptable, we can break out of the loop
700 Revision 1.769 2008/02/22 00:00:19 cheshire
701 <rdar://problem/5338420> BTMM: Not processing additional records
703 Revision 1.768 2008/02/19 23:26:50 cheshire
704 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
706 Revision 1.767 2007/12/22 02:25:29 cheshire
707 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
709 Revision 1.766 2007/12/15 01:12:27 cheshire
710 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
712 Revision 1.765 2007/12/15 00:18:51 cheshire
713 Renamed question->origLease to question->ReqLease
715 Revision 1.764 2007/12/14 00:49:53 cheshire
716 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
717 the CurrentServiceRecordSet mechanism to guard against services being deleted,
718 just like the record deregistration loop uses m->CurrentRecord.
720 Revision 1.763 2007/12/13 20:20:17 cheshire
721 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
722 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
723 inline a function defined in a different compilation unit) and therefore optimized better.
725 Revision 1.762 2007/12/13 00:13:03 cheshire
726 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
728 Revision 1.761 2007/12/13 00:03:31 cheshire
729 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
731 Revision 1.760 2007/12/08 00:36:19 cheshire
732 <rdar://problem/5636422> Updating TXT records is too slow
733 Remove unnecessary delays on announcing record updates, and on processing them on reception
735 Revision 1.759 2007/12/07 22:41:29 cheshire
736 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
737 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
739 Revision 1.758 2007/12/07 00:45:57 cheshire
740 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
742 Revision 1.757 2007/12/06 00:22:27 mcguire
743 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
745 Revision 1.756 2007/12/05 01:52:30 cheshire
746 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
747 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
749 Revision 1.755 2007/12/03 23:36:45 cheshire
750 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
751 Need to check GetServerForName() result is non-null before dereferencing pointer
753 Revision 1.754 2007/12/01 01:21:27 jgraessley
754 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
756 Revision 1.753 2007/12/01 00:44:15 cheshire
757 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
759 Revision 1.752 2007/11/14 01:10:51 cheshire
760 Fixed LogOperation() message wording
762 Revision 1.751 2007/10/30 23:49:41 cheshire
763 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
764 LLQ state was not being transferred properly between duplicate questions
766 Revision 1.750 2007/10/29 23:58:52 cheshire
767 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
768 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
770 Revision 1.749 2007/10/29 21:28:36 cheshire
771 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
773 Revision 1.748 2007/10/29 20:02:50 cheshire
774 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
776 Revision 1.747 2007/10/26 22:53:50 cheshire
777 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
778 instead of replicating the logic in both places
780 Revision 1.746 2007/10/25 22:48:50 cheshire
781 Added LogOperation message saying when we restart GetZoneData for record and service registrations
783 Revision 1.745 2007/10/25 20:48:47 cheshire
784 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
786 Revision 1.744 2007/10/25 20:06:14 cheshire
787 Don't try to do SOA queries using private DNS (TLS over TCP) queries
789 Revision 1.743 2007/10/25 00:12:46 cheshire
790 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
791 Retrigger service registrations whenever a new network interface is added
793 Revision 1.742 2007/10/24 22:40:06 cheshire
794 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
795 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
797 Revision 1.741 2007/10/24 00:50:29 cheshire
798 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
799 Retrigger record registrations whenever a new network interface is added
801 Revision 1.740 2007/10/23 00:38:03 cheshire
802 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
803 or code will spin sending the same cache expiration query repeatedly
805 Revision 1.739 2007/10/22 23:46:41 cheshire
806 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
807 Need to clear question->nta pointer after calling CancelGetZoneData()
809 Revision 1.738 2007/10/19 22:08:49 cheshire
810 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
811 Additional fixes and refinements
813 Revision 1.737 2007/10/18 23:06:42 cheshire
814 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
815 Additional fixes and refinements
817 Revision 1.736 2007/10/18 20:23:17 cheshire
818 Moved SuspendLLQs into mDNS.c, since it's only called from one place
820 Revision 1.735 2007/10/18 00:12:34 cheshire
821 Fixed "unused variable" compiler warning
823 Revision 1.734 2007/10/17 22:49:54 cheshire
824 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
826 Revision 1.733 2007/10/17 22:37:23 cheshire
827 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
829 Revision 1.732 2007/10/17 21:53:51 cheshire
830 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
832 Revision 1.731 2007/10/17 18:37:50 cheshire
833 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
834 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
836 Revision 1.730 2007/10/16 21:16:07 cheshire
837 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
839 Revision 1.729 2007/10/05 17:56:10 cheshire
840 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
842 Revision 1.728 2007/10/04 23:18:14 cheshire
843 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
845 Revision 1.727 2007/10/04 22:51:57 cheshire
846 Added debugging LogOperation message to show when we're sending cache expiration queries
848 Revision 1.726 2007/10/03 00:14:24 cheshire
849 Removed write to null to generate stack trace for SetNextQueryTime locking failure
851 Revision 1.725 2007/10/02 21:11:08 cheshire
852 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
854 Revision 1.724 2007/10/02 20:10:23 cheshire
855 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
857 Revision 1.723 2007/10/02 19:56:54 cheshire
858 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
860 Revision 1.722 2007/10/01 22:59:46 cheshire
861 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
862 Need to shut down NATTraversals on exit
864 Revision 1.721 2007/10/01 18:42:07 cheshire
865 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
867 Revision 1.720 2007/09/29 20:40:19 cheshire
868 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
870 Revision 1.719 2007/09/27 22:23:56 cheshire
871 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
872 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
874 Revision 1.718 2007/09/27 22:02:33 cheshire
875 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
877 Revision 1.717 2007/09/27 21:21:39 cheshire
878 Export CompleteDeregistration so it's callable from other files
880 Revision 1.716 2007/09/27 02:12:21 cheshire
881 Updated GrantCacheExtensions degugging message to show new record lifetime
883 Revision 1.715 2007/09/27 01:20:06 cheshire
884 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
886 Revision 1.714 2007/09/27 00:37:01 cheshire
887 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
889 Revision 1.713 2007/09/27 00:25:39 cheshire
890 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
891 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
893 Revision 1.712 2007/09/26 23:16:58 cheshire
894 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
896 Revision 1.711 2007/09/26 22:06:02 cheshire
897 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
899 Revision 1.710 2007/09/26 00:49:46 cheshire
900 Improve packet logging to show sent and received packets,
901 transport protocol (UDP/TCP/TLS) and source/destination address:port
903 Revision 1.709 2007/09/21 21:12:36 cheshire
904 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
906 Revision 1.708 2007/09/20 23:13:37 cheshire
907 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
908 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
910 Revision 1.707 2007/09/20 02:29:37 cheshire
911 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
913 Revision 1.706 2007/09/20 01:13:19 cheshire
914 Export CacheGroupForName so it's callable from other files
916 Revision 1.705 2007/09/20 01:12:06 cheshire
917 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
919 Revision 1.704 2007/09/19 22:47:25 cheshire
920 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
922 Revision 1.703 2007/09/14 01:46:59 cheshire
923 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
925 Revision 1.702 2007/09/13 22:06:46 cheshire
926 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
927 Need to accept DNS responses where the query ID field matches, even if the source address does not
929 Revision 1.701 2007/09/12 23:22:32 cheshire
930 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
932 Revision 1.700 2007/09/12 23:03:08 cheshire
933 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
935 Revision 1.699 2007/09/12 22:19:28 cheshire
936 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
938 Revision 1.698 2007/09/12 22:13:27 cheshire
939 Remove DynDNSHostNames cleanly on shutdown
941 Revision 1.697 2007/09/12 01:44:47 cheshire
942 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
944 Revision 1.696 2007/09/12 01:26:08 cheshire
945 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
947 Revision 1.695 2007/09/11 19:19:16 cheshire
948 Correct capitalization of "uPNP" to "UPnP"
950 Revision 1.694 2007/09/10 22:06:51 cheshire
951 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
953 Revision 1.693 2007/09/07 22:24:36 vazquez
954 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
956 Revision 1.692 2007/09/07 00:12:09 cheshire
957 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
959 Revision 1.691 2007/09/05 22:25:01 vazquez
960 <rdar://problem/5400521> update_record mDNSResponder leak
962 Revision 1.690 2007/09/05 21:48:01 cheshire
963 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
964 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
965 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
966 otherwise those records will expire and vanish from the cache.
968 Revision 1.689 2007/09/05 02:29:06 cheshire
969 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
970 Additional fixes to code implementing "NoAnswer" logic
972 Revision 1.688 2007/08/31 22:56:39 cheshire
973 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
975 Revision 1.687 2007/08/31 19:53:14 cheshire
976 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
977 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
979 Revision 1.686 2007/08/30 00:01:56 cheshire
980 Added comment about SetTargetToHostName()
982 Revision 1.685 2007/08/29 01:19:24 cheshire
983 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
984 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
986 Revision 1.684 2007/08/28 23:58:42 cheshire
987 Rename HostTarget -> AutoTarget
989 Revision 1.683 2007/08/28 23:53:21 cheshire
990 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
992 Revision 1.682 2007/08/27 20:28:19 cheshire
993 Improve "suspect uDNS response" log message
995 Revision 1.681 2007/08/24 23:37:23 cheshire
996 Added debugging message to show when ExtraResourceRecord callback gets invoked
998 Revision 1.680 2007/08/24 00:15:19 cheshire
999 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
1001 Revision 1.679 2007/08/23 21:47:09 vazquez
1002 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
1003 make sure we clean up port mappings on base stations by sending a lease value of 0,
1004 and only send NAT-PMP packets on private networks; also save some memory by
1005 not using packet structs in NATTraversals.
1007 Revision 1.678 2007/08/01 16:09:13 cheshire
1008 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
1010 Revision 1.677 2007/08/01 01:58:24 cheshire
1011 Added RecordType sanity check in mDNS_Register_internal
1013 Revision 1.676 2007/08/01 00:04:13 cheshire
1014 <rdar://problem/5261696> Crash in tcpKQSocketCallback
1015 Half-open TCP connections were not being cancelled properly
1017 Revision 1.675 2007/07/31 02:28:35 vazquez
1018 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
1020 Revision 1.674 2007/07/31 01:57:23 cheshire
1021 Adding code to respect TTL received in uDNS responses turned out to
1022 expose other problems; backing out change for now.
1024 Revision 1.673 2007/07/30 23:31:26 cheshire
1025 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
1027 Revision 1.672 2007/07/28 01:25:56 cheshire
1028 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
1030 Revision 1.671 2007/07/27 22:32:54 cheshire
1031 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
1032 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
1034 Revision 1.670 2007/07/27 20:54:43 cheshire
1035 Fixed code to respect real record TTL received in uDNS responses
1037 Revision 1.669 2007/07/27 20:09:32 cheshire
1038 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
1040 Revision 1.668 2007/07/27 19:58:47 cheshire
1041 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
1043 Revision 1.667 2007/07/27 19:52:10 cheshire
1044 Don't increment m->rrcache_active for no-cache add events
1046 Revision 1.666 2007/07/27 19:30:39 cheshire
1047 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
1048 to properly reflect tri-state nature of the possible responses
1050 Revision 1.665 2007/07/27 18:44:01 cheshire
1051 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
1053 Revision 1.664 2007/07/27 18:38:56 cheshire
1054 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
1056 Revision 1.663 2007/07/25 03:05:02 vazquez
1058 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
1059 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
1060 and a myriad of other security problems
1062 Revision 1.662 2007/07/24 20:22:46 cheshire
1063 Make sure all fields of main mDNS object are initialized correctly
1065 Revision 1.661 2007/07/21 00:54:45 cheshire
1066 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
1068 Revision 1.660 2007/07/20 20:00:45 cheshire
1069 "Legacy Browse" is better called "Automatic Browse"
1071 Revision 1.659 2007/07/20 00:54:18 cheshire
1072 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
1074 Revision 1.658 2007/07/18 02:28:57 cheshire
1075 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
1077 Revision 1.657 2007/07/18 00:57:10 cheshire
1078 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1079 Only need to call AddNewClientTunnel() for IPv6 addresses
1081 Revision 1.656 2007/07/16 23:54:48 cheshire
1082 <rdar://problem/5338850> Crash when removing or changing DNS keys
1084 Revision 1.655 2007/07/16 20:11:37 vazquez
1085 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
1086 Init LNT stuff and handle SSDP packets
1088 Revision 1.654 2007/07/12 23:30:23 cheshire
1089 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
1091 Revision 1.653 2007/07/12 02:51:27 cheshire
1092 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1094 Revision 1.652 2007/07/11 23:43:42 cheshire
1095 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
1097 Revision 1.651 2007/07/11 22:44:40 cheshire
1098 <rdar://problem/5328801> SIGHUP should purge the cache
1100 Revision 1.650 2007/07/11 21:34:09 cheshire
1101 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
1102 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
1104 Revision 1.649 2007/07/11 02:52:52 cheshire
1105 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
1106 In uDNS_RegisterService, set HostTarget for AutoTunnel services
1108 Revision 1.648 2007/07/09 23:48:12 cheshire
1109 Add parentheses around bitwise operation for clarity
1111 Revision 1.647 2007/07/06 21:17:55 cheshire
1112 Initialize m->retryGetAddr to timenow + 0x78000000;
1114 Revision 1.646 2007/07/06 18:55:49 cheshire
1115 Initialize m->NextScheduledNATOp
1117 Revision 1.645 2007/06/29 22:55:54 cheshire
1118 Move declaration of DNSServer *s; Fixed incomplete comment.
1120 Revision 1.644 2007/06/29 00:07:29 vazquez
1121 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
1123 Revision 1.643 2007/06/20 01:10:12 cheshire
1124 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
1126 Revision 1.642 2007/06/15 21:54:50 cheshire
1127 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
1129 Revision 1.641 2007/05/25 00:30:24 cheshire
1130 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
1131 status matches. This is particularly important when doing a private query for an SOA record,
1132 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
1133 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
1135 Revision 1.640 2007/05/25 00:25:44 cheshire
1136 <rdar://problem/5227737> Need to enhance putRData to output all current known types
1138 Revision 1.639 2007/05/23 00:51:33 cheshire
1139 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
1140 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
1141 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
1143 Revision 1.638 2007/05/23 00:43:16 cheshire
1144 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
1146 Revision 1.637 2007/05/14 23:53:00 cheshire
1147 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
1149 Revision 1.636 2007/05/10 23:27:15 cheshire
1150 Update mDNS_Deregister_internal debugging messages
1152 Revision 1.635 2007/05/07 20:43:45 cheshire
1153 <rdar://problem/4241419> Reduce the number of queries and announcements
1155 Revision 1.634 2007/05/04 22:09:08 cheshire
1156 Only do "restarting exponential backoff sequence" for mDNS questions
1157 In mDNS_RegisterInterface, only retrigger mDNS questions
1158 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
1160 Revision 1.633 2007/05/04 21:45:12 cheshire
1161 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
1163 Revision 1.632 2007/05/04 20:20:50 cheshire
1164 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1165 Need to set srs->nta = mDNSNULL; when regState_NoTarget
1167 Revision 1.631 2007/05/04 00:39:42 cheshire
1168 <rdar://problem/4410011> Eliminate looping SOA lookups
1169 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
1170 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
1172 Revision 1.630 2007/05/03 22:40:38 cheshire
1173 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
1175 Revision 1.629 2007/05/03 00:15:51 cheshire
1176 <rdar://problem/4410011> Eliminate looping SOA lookups
1178 Revision 1.628 2007/05/02 22:21:33 cheshire
1179 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1181 Revision 1.627 2007/04/30 19:29:13 cheshire
1182 Fix display of port number in "Updating DNS Server" message
1184 Revision 1.626 2007/04/30 04:21:13 cheshire
1185 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
1187 Revision 1.625 2007/04/28 01:34:21 cheshire
1188 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
1189 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
1191 Revision 1.624 2007/04/27 21:04:30 cheshire
1192 On network configuration change, need to call uDNS_RegisterSearchDomains
1194 Revision 1.623 2007/04/27 19:28:01 cheshire
1195 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
1196 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
1197 -- it would start a query and then quickly cancel it, and then when
1198 StartGetZoneData completed, it had a dangling pointer and crashed.)
1200 Revision 1.622 2007/04/26 16:09:22 cheshire
1201 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
1203 Revision 1.621 2007/04/26 15:43:22 cheshire
1204 Make sure DNSServer *s is non-null before using value in LogOperation
1206 Revision 1.620 2007/04/26 13:11:05 cheshire
1207 Fixed crash when logging out of VPN
1209 Revision 1.619 2007/04/26 00:35:15 cheshire
1210 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
1211 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
1212 inside the firewall may give answers where a public one gives none, and vice versa.)
1214 Revision 1.618 2007/04/25 19:26:01 cheshire
1215 m->NextScheduledQuery was getting set too early in SendQueries()
1216 Improved "SendQueries didn't send all its queries" debugging message
1218 Revision 1.617 2007/04/25 17:48:22 cheshire
1219 Update debugging message
1221 Revision 1.616 2007/04/25 16:38:32 cheshire
1222 If negative cache entry already exists, reactivate it instead of creating a new one
1224 Revision 1.615 2007/04/25 02:14:38 cheshire
1225 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
1226 Additional fixes to make LLQs work properly
1228 Revision 1.614 2007/04/23 21:52:45 cheshire
1229 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
1231 Revision 1.613 2007/04/23 04:58:20 cheshire
1232 <rdar://problem/5072548> Crash when setting extremely large TXT records
1234 Revision 1.612 2007/04/22 20:39:38 cheshire
1235 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
1237 Revision 1.611 2007/04/22 18:16:29 cheshire
1238 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
1240 Revision 1.610 2007/04/22 06:02:02 cheshire
1241 <rdar://problem/4615977> Query should immediately return failure when no server
1243 Revision 1.609 2007/04/20 21:17:24 cheshire
1244 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
1246 Revision 1.608 2007/04/20 19:45:31 cheshire
1247 In LogClientOperations mode, dump out unknown DNS packets in their entirety
1249 Revision 1.607 2007/04/19 23:56:25 cheshire
1250 Don't do cache-flush processing for LLQ answers
1252 Revision 1.606 2007/04/19 22:50:53 cheshire
1253 <rdar://problem/4246187> Identical client queries should reference a single shared core query
1255 Revision 1.605 2007/04/19 20:06:41 cheshire
1256 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
1258 Revision 1.604 2007/04/19 18:03:04 cheshire
1259 Add "const" declaration
1261 Revision 1.603 2007/04/06 21:00:25 cheshire
1262 Fix log message typo
1264 Revision 1.602 2007/04/05 22:55:35 cheshire
1265 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1267 Revision 1.601 2007/04/04 21:48:52 cheshire
1268 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1270 Revision 1.600 2007/04/04 01:31:33 cheshire
1271 Improve debugging message
1273 Revision 1.599 2007/04/04 00:03:26 cheshire
1274 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
1276 Revision 1.598 2007/04/03 19:43:16 cheshire
1277 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1279 Revision 1.597 2007/03/31 00:32:32 cheshire
1280 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
1282 Revision 1.596 2007/03/28 20:59:26 cheshire
1283 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1285 Revision 1.595 2007/03/26 23:48:16 cheshire
1286 <rdar://problem/4848295> Advertise model information via Bonjour
1287 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
1289 Revision 1.594 2007/03/26 23:05:05 cheshire
1290 <rdar://problem/5089257> Don't cache TSIG records
1292 Revision 1.593 2007/03/23 17:40:08 cheshire
1293 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
1295 Revision 1.592 2007/03/22 18:31:48 cheshire
1296 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1298 Revision 1.591 2007/03/22 00:49:19 cheshire
1299 <rdar://problem/4848295> Advertise model information via Bonjour
1301 Revision 1.590 2007/03/21 23:05:59 cheshire
1302 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1304 Revision 1.589 2007/03/20 15:37:19 cheshire
1305 Delete unnecessary log message
1307 Revision 1.588 2007/03/20 00:24:44 cheshire
1308 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
1310 Revision 1.587 2007/03/16 22:10:56 cheshire
1311 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
1313 Revision 1.586 2007/03/10 03:26:44 cheshire
1314 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1316 Revision 1.585 2007/03/10 02:02:58 cheshire
1317 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1318 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1320 Revision 1.584 2007/02/28 01:51:27 cheshire
1321 Added comment about reverse-order IP address
1323 Revision 1.583 2007/01/27 03:19:33 cheshire
1324 Need to initialize question->sock
1326 Revision 1.582 2007/01/25 00:40:16 cheshire
1327 Unified CNAME-following functionality into cache management code (which means CNAME-following
1328 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1330 Revision 1.581 2007/01/23 02:56:11 cheshire
1331 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1333 Revision 1.580 2007/01/19 21:17:33 cheshire
1334 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1336 Revision 1.579 2007/01/19 18:39:10 cheshire
1337 Fix a bunch of parameters that should have been declared "const"
1339 Revision 1.578 2007/01/10 22:51:57 cheshire
1340 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1342 Revision 1.577 2007/01/10 02:05:21 cheshire
1343 Delay uDNS_SetupDNSConfig() until *after* the platform layer
1344 has set up the interface list and security credentials
1346 Revision 1.576 2007/01/09 02:40:57 cheshire
1347 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1348 moved it to mDNS_Init() in mDNS.c (core code)
1350 Revision 1.575 2007/01/09 00:17:25 cheshire
1351 Improve "ERROR m->CurrentRecord already set" debugging messages
1353 Revision 1.574 2007/01/05 08:30:41 cheshire
1354 Trim excessive "Log" checkin history from before 2006
1355 (checkin history still available via "cvs log ..." of course)
1357 Revision 1.573 2007/01/05 06:34:03 cheshire
1358 Improve "ERROR m->CurrentQuestion already set" debugging messages
1360 Revision 1.572 2007/01/04 23:11:11 cheshire
1361 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1362 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1364 Revision 1.571 2007/01/04 21:45:20 cheshire
1365 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1366 to do additional lock sanity checking around callback invocations
1368 Revision 1.570 2007/01/04 20:57:47 cheshire
1369 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
1371 Revision 1.569 2007/01/04 20:27:27 cheshire
1372 Change a LogMsg() to debugf()
1374 Revision 1.568 2007/01/04 02:39:53 cheshire
1375 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1377 Revision 1.567 2006/12/21 00:01:37 cheshire
1378 Tidy up code alignment
1380 Revision 1.566 2006/12/20 04:07:34 cheshire
1381 Remove uDNS_info substructure from AuthRecord_struct
1383 Revision 1.565 2006/12/19 22:49:23 cheshire
1384 Remove uDNS_info substructure from ServiceRecordSet_struct
1386 Revision 1.564 2006/12/19 02:38:20 cheshire
1387 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1389 Revision 1.563 2006/12/19 02:18:48 cheshire
1390 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1392 Revision 1.562 2006/12/16 01:58:31 cheshire
1393 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1395 Revision 1.561 2006/12/01 07:38:53 herscher
1396 Only perform cache workaround fix if query is wide-area
1398 Revision 1.560 2006/11/30 23:07:56 herscher
1399 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1401 Revision 1.559 2006/11/27 08:20:57 cheshire
1402 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
1404 Revision 1.558 2006/11/10 07:44:03 herscher
1405 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1407 Revision 1.557 2006/11/10 01:12:51 cheshire
1408 <rdar://problem/4829718> Incorrect TTL corrections
1410 Revision 1.556 2006/11/10 00:54:14 cheshire
1411 <rdar://problem/4816598> Changing case of Computer Name doesn't work
1413 Revision 1.555 2006/10/30 20:03:37 cheshire
1414 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
1416 Revision 1.554 2006/10/20 05:35:04 herscher
1417 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1419 Revision 1.553 2006/10/05 03:42:43 herscher
1420 Remove embedded uDNS_info struct in DNSQuestion_struct
1422 Revision 1.552 2006/09/15 21:20:15 cheshire
1423 Remove uDNS_info substructure from mDNS_struct
1425 Revision 1.551 2006/08/14 23:24:22 cheshire
1426 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1428 Revision 1.550 2006/07/27 17:58:34 cheshire
1429 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
1431 Revision 1.549 2006/07/20 22:07:31 mkrochma
1432 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
1433 More fixes for uninitialized variables
1435 Revision 1.548 2006/07/20 19:30:19 mkrochma
1436 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
1438 Revision 1.547 2006/07/15 02:31:30 cheshire
1439 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
1441 Revision 1.546 2006/07/07 01:09:09 cheshire
1442 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
1443 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
1445 Revision 1.545 2006/07/05 23:10:30 cheshire
1446 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1447 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
1449 Revision 1.544 2006/06/29 07:42:14 cheshire
1450 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
1452 Revision 1.543 2006/06/29 01:38:43 cheshire
1453 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
1455 Revision 1.542 2006/06/27 23:40:29 cheshire
1456 Fix typo in comment: mis-spelled "compile"
1458 Revision 1.541 2006/06/27 19:46:24 cheshire
1459 Updated comments and debugging messages
1461 Revision 1.540 2006/06/15 21:35:16 cheshire
1462 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
1463 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
1465 Revision 1.539 2006/06/08 23:45:46 cheshire
1466 Change SimultaneousProbe messages from debugf() to LogOperation()
1468 Revision 1.538 2006/03/19 17:13:06 cheshire
1469 <rdar://problem/4483117> Need faster purging of stale records
1470 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
1471 and reconfirm whole chain of antecedents ot once
1473 Revision 1.537 2006/03/19 02:00:07 cheshire
1474 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1476 Revision 1.536 2006/03/08 23:29:53 cheshire
1477 <rdar://problem/4468716> Improve "Service Renamed" log message
1479 Revision 1.535 2006/03/02 20:41:17 cheshire
1480 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1481 Minor code tidying and comments to reduce the risk of similar programming errors in future
1483 Revision 1.534 2006/03/02 03:25:46 cheshire
1484 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1485 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
1487 Revision 1.533 2006/02/26 00:54:41 cheshire
1488 Fixes to avoid code generation warning/error on FreeBSD 7
1492 #include "DNSCommon.h" // Defines general DNS untility routines
1493 #include "uDNS.h" // Defines entry points into unicast-specific routines
1495 // Disable certain benign warnings with Microsoft compilers
1496 #if(defined(_MSC_VER))
1497 // Disable "conditional expression is constant" warning for debug macros.
1498 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1499 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1500 #pragma warning(disable:4127)
1502 // Disable "assignment within conditional expression".
1503 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1504 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1505 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1506 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1507 #pragma warning(disable:4706)
1510 // Forward declarations
1511 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
);
1512 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
);
1514 // ***************************************************************************
1515 #if COMPILER_LIKES_PRAGMA_MARK
1516 #pragma mark - Program Constants
1521 mDNSlocal
const mDNSInterfaceID mDNSInterfaceMark
= (mDNSInterfaceID
)~0;
1523 // Any records bigger than this are considered 'large' records
1524 #define SmallRecordLimit 1024
1526 #define kMaxUpdateCredits 10
1527 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1529 mDNSexport
const char *const mDNS_DomainTypeNames
[] =
1531 "b._dns-sd._udp.", // Browse
1532 "db._dns-sd._udp.", // Default Browse
1533 "lb._dns-sd._udp.", // Automatic Browse
1534 "r._dns-sd._udp.", // Registration
1535 "dr._dns-sd._udp." // Default Registration
1538 #ifdef UNICAST_DISABLED
1539 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1542 // ***************************************************************************
1543 #if COMPILER_LIKES_PRAGMA_MARK
1545 #pragma mark - General Utility Functions
1548 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
1549 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
1551 mDNSexport
void SetNextQueryTime(mDNS
*const m
, const DNSQuestion
*const q
)
1553 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1554 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1557 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1) *(long*)0 = 0;
1560 if (ActiveQuestion(q
))
1562 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
1564 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
1565 if (!mDNSOpaque16IsZero(q
->TargetQID
) && !q
->LongLived
&& m
->SuppressStdPort53Queries
&& (sendtime
- m
->SuppressStdPort53Queries
< 0))
1566 sendtime
= m
->SuppressStdPort53Queries
;
1568 if (m
->NextScheduledQuery
- sendtime
> 0)
1569 m
->NextScheduledQuery
= sendtime
;
1573 mDNSexport CacheGroup
*CacheGroupForName(const mDNS
*const m
, const mDNSu32 slot
, const mDNSu32 namehash
, const domainname
*const name
)
1576 for (cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1577 if (cg
->namehash
== namehash
&& SameDomainName(cg
->name
, name
))
1582 mDNSlocal CacheGroup
*CacheGroupForRecord(const mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
1584 return(CacheGroupForName(m
, slot
, rr
->namehash
, rr
->name
));
1587 mDNSlocal mDNSBool
AddressIsLocalSubnet(mDNS
*const m
, const mDNSInterfaceID InterfaceID
, const mDNSAddr
*addr
)
1589 NetworkInterfaceInfo
*intf
;
1591 if (addr
->type
== mDNSAddrType_IPv4
)
1593 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
1594 if (mDNSv4AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1595 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1596 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1597 if (((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) & intf
->mask
.ip
.v4
.NotAnInteger
) == 0)
1601 if (addr
->type
== mDNSAddrType_IPv6
)
1603 if (mDNSv6AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1604 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1605 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1606 if ((((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) & intf
->mask
.ip
.v6
.l
[0]) == 0) &&
1607 (((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) & intf
->mask
.ip
.v6
.l
[1]) == 0) &&
1608 (((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) & intf
->mask
.ip
.v6
.l
[2]) == 0) &&
1609 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) & intf
->mask
.ip
.v6
.l
[3]) == 0))
1616 mDNSlocal NetworkInterfaceInfo
*FirstInterfaceForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1618 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1619 while (intf
&& intf
->InterfaceID
!= InterfaceID
) intf
= intf
->next
;
1623 mDNSlocal
char *InterfaceNameForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1625 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
1626 return(intf
? intf
->ifname
: "<NULL InterfaceID>");
1629 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1630 // Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
1631 mDNSlocal
void AnswerLocalQuestionWithLocalAuthRecord(mDNS
*const m
, DNSQuestion
*q
, AuthRecord
*rr
, QC_result AddRecord
)
1633 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1634 if (AddRecord
) rr
->AnsweredLocalQ
= mDNStrue
;
1635 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1636 if (q
->QuestionCallback
&& !q
->NoAnswer
)
1638 q
->CurrentAnswers
+= AddRecord
? 1 : -1;
1639 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
1641 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1644 // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
1645 // all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
1646 // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1647 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1648 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1649 mDNSlocal
void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS
*const m
, AuthRecord
*rr
, QC_result AddRecord
)
1651 if (m
->CurrentQuestion
)
1652 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
1654 m
->CurrentQuestion
= m
->LocalOnlyQuestions
;
1655 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewLocalOnlyQuestions
)
1657 DNSQuestion
*q
= m
->CurrentQuestion
;
1658 m
->CurrentQuestion
= q
->next
;
1659 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1660 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1663 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1664 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
1666 m
->CurrentQuestion
= m
->Questions
;
1667 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
1669 DNSQuestion
*q
= m
->CurrentQuestion
;
1670 m
->CurrentQuestion
= q
->next
;
1671 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1672 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1676 m
->CurrentQuestion
= mDNSNULL
;
1679 // ***************************************************************************
1680 #if COMPILER_LIKES_PRAGMA_MARK
1682 #pragma mark - Resource Record Utility Functions
1685 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1687 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1688 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1689 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1690 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1692 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1693 (ResourceRecordIsValidAnswer(RR) && \
1694 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1696 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1697 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1699 #define InitialAnnounceCount ((mDNSu8)8)
1701 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1702 // This means that because the announce interval is doubled after sending the first packet, the first
1703 // observed on-the-wire inter-packet interval between announcements is actually one second.
1704 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1705 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1706 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1707 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1709 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1710 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1711 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1713 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1714 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1715 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1716 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1718 #define MaxUnansweredQueries 4
1720 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1721 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1722 // TTL and rdata may differ.
1723 // This is used for cache flush management:
1724 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1725 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1727 // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
1729 #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
1731 mDNSlocal mDNSBool
SameResourceRecordNameClassInterface(const AuthRecord
*const r1
, const AuthRecord
*const r2
)
1733 if (!r1
) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse
); }
1734 if (!r2
) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse
); }
1735 if (r1
->resrec
.InterfaceID
&&
1736 r2
->resrec
.InterfaceID
&&
1737 r1
->resrec
.InterfaceID
!= r2
->resrec
.InterfaceID
) return(mDNSfalse
);
1739 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
&&
1740 r1
->resrec
.namehash
== r2
->resrec
.namehash
&&
1741 SameDomainName(r1
->resrec
.name
, r2
->resrec
.name
));
1744 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1745 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1746 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1747 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1748 // so a response of any type should match, even if it is not actually the type the client plans to use.
1750 // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
1751 // and require the rrtypes to match for the rdata to be considered potentially conflicting
1752 mDNSlocal mDNSBool
PacketRRMatchesSignature(const CacheRecord
*const pktrr
, const AuthRecord
*const authrr
)
1754 if (!pktrr
) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse
); }
1755 if (!authrr
) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse
); }
1756 if (pktrr
->resrec
.InterfaceID
&&
1757 authrr
->resrec
.InterfaceID
&&
1758 pktrr
->resrec
.InterfaceID
!= authrr
->resrec
.InterfaceID
) return(mDNSfalse
);
1759 if (!(authrr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) || authrr
->WakeUp
.HMAC
.l
[0])
1760 if (pktrr
->resrec
.rrtype
!= authrr
->resrec
.rrtype
) return(mDNSfalse
);
1762 pktrr
->resrec
.rrclass
== authrr
->resrec
.rrclass
&&
1763 pktrr
->resrec
.namehash
== authrr
->resrec
.namehash
&&
1764 SameDomainName(pktrr
->resrec
.name
, authrr
->resrec
.name
));
1767 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1768 // This is the information that the requester believes to be correct.
1769 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1770 // This is the information that we believe to be correct.
1771 // We've already determined that we plan to give this answer on this interface
1772 // (either the record is non-specific, or it is specific to this interface)
1773 // so now we just need to check the name, type, class, rdata and TTL.
1774 mDNSlocal mDNSBool
ShouldSuppressKnownAnswer(const CacheRecord
*const ka
, const AuthRecord
*const rr
)
1776 // If RR signature is different, or data is different, then don't suppress our answer
1777 if (!IdenticalResourceRecord(&ka
->resrec
, &rr
->resrec
)) return(mDNSfalse
);
1779 // If the requester's indicated TTL is less than half the real TTL,
1780 // we need to give our answer before the requester's copy expires.
1781 // If the requester's indicated TTL is at least half the real TTL,
1782 // then we can suppress our answer this time.
1783 // If the requester's indicated TTL is greater than the TTL we believe,
1784 // then that's okay, and we don't need to do anything about it.
1785 // (If two responders on the network are offering the same information,
1786 // that's okay, and if they are offering the information with different TTLs,
1787 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1788 return(mDNSBool
)(ka
->resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/ 2);
1791 mDNSlocal
void SetNextAnnounceProbeTime(mDNS
*const m
, const AuthRecord
*const rr
)
1793 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1795 //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1796 if (m
->NextScheduledProbe
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1797 m
->NextScheduledProbe
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1799 else if (rr
->AnnounceCount
&& ResourceRecordIsValidAnswer(rr
))
1801 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1802 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1806 mDNSlocal
void InitializeLastAPTime(mDNS
*const m
, AuthRecord
*const rr
)
1808 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1809 rr
->ThisAPInterval
= rr
->AddressProxy
.type
? mDNSPlatformOneSecond
: DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
);
1811 // To allow us to aggregate probes when a group of services are registered together,
1812 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1813 // 1/4 second wait; probe
1814 // 1/4 second wait; probe
1815 // 1/4 second wait; probe
1816 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1820 // If we have no probe suppression time set, or it is in the past, set it now
1821 if (m
->SuppressProbes
== 0 || m
->SuppressProbes
- m
->timenow
< 0)
1823 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ DefaultProbeIntervalForTypeUnique
);
1824 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1825 if (m
->SuppressProbes
- m
->NextScheduledProbe
>= 0)
1826 m
->SuppressProbes
= m
->NextScheduledProbe
;
1827 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1828 if (m
->SuppressProbes
- m
->NextScheduledQuery
>= 0)
1829 m
->SuppressProbes
= m
->NextScheduledQuery
;
1833 rr
->LastAPTime
= m
->SuppressProbes
- rr
->ThisAPInterval
;
1834 // Set LastMCTime to now, to inhibit multicast responses
1835 // (no need to send additional multicast responses when we're announcing anyway)
1836 rr
->LastMCTime
= m
->timenow
;
1837 rr
->LastMCInterface
= mDNSInterfaceMark
;
1839 // If this is a record type that's not going to probe, then delay its first announcement so that
1840 // it will go out synchronized with the first announcement for the other records that *are* probing.
1841 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1842 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1843 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1844 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1845 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1846 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
)
1847 rr
->LastAPTime
+= DefaultProbeIntervalForTypeUnique
* DefaultProbeCountForTypeUnique
+ rr
->ThisAPInterval
/ 2;
1849 // The exception is unique records that have already been verified and are just being updated
1850 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1851 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
1852 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1854 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1855 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1856 // After three probes one second apart with no answer, we conclude the client is now sleeping
1857 // and we can begin broadcasting our announcements to take over ownership of that IP address.
1858 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1859 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1860 if (rr
->AddressProxy
.type
) rr
->LastAPTime
= m
->timenow
;
1862 // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
1863 if (rr
->WakeUp
.HMAC
.l
[0] && rr
->resrec
.rrtype
== kDNSType_AAAA
)
1864 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
+ mDNSPlatformOneSecond
* 10;
1866 SetNextAnnounceProbeTime(m
, rr
);
1869 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1870 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1871 mDNSlocal
void SetTargetToHostName(mDNS
*const m
, AuthRecord
*const rr
)
1873 domainname
*const target
= GetRRDomainNameTarget(&rr
->resrec
);
1874 const domainname
*newname
= &m
->MulticastHostname
;
1876 if (!target
) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr
->resrec
.rrtype
);
1878 if (!(rr
->ForceMCast
|| rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&rr
->namestorage
)))
1880 const domainname
*const n
= GetServiceTarget(m
, rr
);
1884 if (target
&& SameDomainName(target
, newname
))
1885 debugf("SetTargetToHostName: Target of %##s is already %##s", rr
->resrec
.name
->c
, target
->c
);
1887 if (target
&& !SameDomainName(target
, newname
))
1889 AssignDomainName(target
, newname
);
1890 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
1892 // If we're in the middle of probing this record, we need to start again,
1893 // because changing its rdata may change the outcome of the tie-breaker.
1894 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1895 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
1897 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1898 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1899 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1900 if (rr
->RequireGoodbye
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
)
1901 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1902 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1904 rr
->AnnounceCount
= InitialAnnounceCount
;
1905 rr
->RequireGoodbye
= mDNSfalse
;
1906 InitializeLastAPTime(m
, rr
);
1910 mDNSlocal
void AcknowledgeRecord(mDNS
*const m
, AuthRecord
*const rr
)
1912 if (rr
->RecordCallback
)
1914 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1915 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1916 rr
->Acknowledged
= mDNStrue
;
1917 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1918 rr
->RecordCallback(m
, rr
, mStatus_NoError
);
1919 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1923 mDNSlocal
void ActivateUnicastRegistration(mDNS
*const m
, AuthRecord
*const rr
)
1926 rr
->AnnounceCount
= 0;
1927 rr
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
1928 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1929 rr
->state
= regState_FetchingZoneData
;
1930 rr
->uselease
= mDNStrue
;
1933 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1934 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1935 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1936 #define RecordIsLocalDuplicate(A,B) \
1937 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1939 // Exported so uDNS.c can call this
1940 mDNSexport mStatus
mDNS_Register_internal(mDNS
*const m
, AuthRecord
*const rr
)
1942 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
1944 AuthRecord
**p
= &m
->ResourceRecords
;
1945 AuthRecord
**d
= &m
->DuplicateRecords
;
1947 if ((mDNSs32
)rr
->resrec
.rroriginalttl
<= 0)
1948 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1950 if (!rr
->resrec
.RecordType
)
1951 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1953 if (m
->ShutdownTime
)
1954 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m
, rr
)); return(mStatus_ServiceNotRunning
); }
1956 if (m
->DivertMulticastAdvertisements
&& !AuthRecord_uDNS(rr
))
1958 mDNSInterfaceID previousID
= rr
->resrec
.InterfaceID
;
1959 if (rr
->resrec
.InterfaceID
== mDNSInterface_Any
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1960 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
1962 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
1963 if (intf
&& !intf
->Advertise
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1965 if (rr
->resrec
.InterfaceID
!= previousID
)
1966 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m
, rr
));
1969 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
1970 while (*d
&& *d
!= rr
) d
=&(*d
)->next
;
1973 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1974 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1975 return(mStatus_AlreadyRegistered
);
1978 if (rr
->DependentOn
)
1980 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1981 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
1984 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1985 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1986 return(mStatus_Invalid
);
1988 if (!(rr
->DependentOn
->resrec
.RecordType
& (kDNSRecordTypeUnique
| kDNSRecordTypeVerified
)))
1990 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1991 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->DependentOn
->resrec
.RecordType
);
1992 return(mStatus_Invalid
);
1996 // If this resource record is referencing a specific interface, make sure it exists
1997 if (rr
->resrec
.InterfaceID
&& rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
1999 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2002 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr
->resrec
.InterfaceID
);
2003 return(mStatus_BadReferenceErr
);
2007 rr
->next
= mDNSNULL
;
2009 // Field Group 1: The actual information pertaining to this resource record
2010 // Set up by client prior to call
2012 // Field Group 2: Persistent metadata for Authoritative Records
2013 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2014 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2015 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2016 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2017 // rr->Callback = already set in mDNS_SetupResourceRecord
2018 // rr->Context = already set in mDNS_SetupResourceRecord
2019 // rr->RecordType = already set in mDNS_SetupResourceRecord
2020 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2021 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2022 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
2023 if (rr
->AutoTarget
&& target
) target
->c
[0] = 0;
2025 // Field Group 3: Transient state for Authoritative Records
2026 rr
->Acknowledged
= mDNSfalse
;
2027 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
2028 rr
->AnnounceCount
= InitialAnnounceCount
;
2029 rr
->RequireGoodbye
= mDNSfalse
;
2030 rr
->AnsweredLocalQ
= mDNSfalse
;
2031 rr
->IncludeInProbe
= mDNSfalse
;
2032 rr
->ImmedUnicast
= mDNSfalse
;
2033 rr
->SendNSECNow
= mDNSNULL
;
2034 rr
->ImmedAnswer
= mDNSNULL
;
2035 rr
->ImmedAdditional
= mDNSNULL
;
2036 rr
->SendRNow
= mDNSNULL
;
2037 rr
->v4Requester
= zerov4Addr
;
2038 rr
->v6Requester
= zerov6Addr
;
2039 rr
->NextResponse
= mDNSNULL
;
2040 rr
->NR_AnswerTo
= mDNSNULL
;
2041 rr
->NR_AdditionalTo
= mDNSNULL
;
2042 if (!rr
->AutoTarget
) InitializeLastAPTime(m
, rr
);
2043 // rr->LastAPTime = Set for us in InitializeLastAPTime()
2044 // rr->LastMCTime = Set for us in InitializeLastAPTime()
2045 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
2046 rr
->NewRData
= mDNSNULL
;
2047 rr
->newrdlength
= 0;
2048 rr
->UpdateCallback
= mDNSNULL
;
2049 rr
->UpdateCredits
= kMaxUpdateCredits
;
2050 rr
->NextUpdateCredit
= 0;
2051 rr
->UpdateBlocked
= 0;
2053 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
2054 if (rr
->WakeUp
.HMAC
.l
[0] && !rr
->AddressProxy
.type
) rr
->AnnounceCount
= 2;
2056 // Field Group 4: Transient uDNS state for Authoritative Records
2057 rr
->state
= regState_Zero
;
2061 rr
->updateid
= zeroID
;
2062 rr
->zone
= rr
->resrec
.name
;
2063 rr
->UpdateServer
= zeroAddr
;
2064 rr
->UpdatePort
= zeroIPPort
;
2069 rr
->InFlightRData
= 0;
2070 rr
->InFlightRDLen
= 0;
2071 rr
->QueuedRData
= 0;
2072 rr
->QueuedRDLen
= 0;
2074 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
2075 // rr->resrec.name->c = MUST be set by client
2076 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
2077 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
2078 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
2079 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2082 SetTargetToHostName(m
, rr
); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2085 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
2086 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
2089 if (!ValidateDomainName(rr
->resrec
.name
))
2090 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2092 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2093 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2094 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2095 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rr
->resrec
.rdlength
== 0) { rr
->resrec
.rdlength
= 1; rr
->resrec
.rdata
->u
.txt
.c
[0] = 0; }
2097 // Don't do this until *after* we've set rr->resrec.rdlength
2098 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
2099 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2101 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
2102 rr
->resrec
.rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(&rr
->resrec
);
2104 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
2106 // If this is supposed to be unique, make sure we don't have any name conflicts
2107 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2109 const AuthRecord
*s1
= rr
->RRSet
? rr
->RRSet
: rr
;
2110 for (r
= m
->ResourceRecords
; r
; r
=r
->next
)
2112 const AuthRecord
*s2
= r
->RRSet
? r
->RRSet
: r
;
2113 if (s1
!= s2
&& SameResourceRecordSignature(r
, rr
) && !IdenticalSameNameRecord(&r
->resrec
, &rr
->resrec
))
2116 if (r
) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2118 debugf("Name conflict %p %##s (%s)", rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2119 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2120 rr
->resrec
.rroriginalttl
= 0;
2121 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2122 m
->NextScheduledResponse
= m
->timenow
;
2127 // Now that we've finished building our new record, make sure it's not identical to one we already have
2128 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (RecordIsLocalDuplicate(r
, rr
)) break;
2132 debugf("Adding to duplicate list %p %s", rr
, ARDisplayString(m
,rr
));
2134 // If the previous copy of this record is already verified unique,
2135 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2136 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
2137 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2138 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& r
->resrec
.RecordType
== kDNSRecordTypeVerified
)
2143 debugf("Adding to active record list %p %s", rr
, ARDisplayString(m
,rr
));
2144 if (!m
->NewLocalRecords
) m
->NewLocalRecords
= rr
;
2148 if (!AuthRecord_uDNS(rr
))
2150 // For records that are not going to probe, acknowledge them right away
2151 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
&& rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
2152 AcknowledgeRecord(m
, rr
);
2154 #ifndef UNICAST_DISABLED
2157 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
2158 ActivateUnicastRegistration(m
, rr
);
2162 return(mStatus_NoError
);
2165 mDNSlocal
void RecordProbeFailure(mDNS
*const m
, const AuthRecord
*const rr
)
2167 m
->ProbeFailTime
= m
->timenow
;
2168 m
->NumFailedProbes
++;
2169 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2170 // If a bunch of hosts have all been configured with the same name, then they'll all
2171 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2172 // up to name-10. After that they'll start adding random increments in the range 1-100,
2173 // so they're more likely to branch out in the available namespace and settle on a set of
2174 // unique names quickly. If after five more tries the host is still conflicting, then we
2175 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
2176 if (m
->NumFailedProbes
>= 15)
2178 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
2179 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2180 m
->NumFailedProbes
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2184 mDNSlocal
void CompleteRDataUpdate(mDNS
*const m
, AuthRecord
*const rr
)
2186 RData
*OldRData
= rr
->resrec
.rdata
;
2187 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
); // Update our rdata
2188 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
2189 if (rr
->UpdateCallback
)
2190 rr
->UpdateCallback(m
, rr
, OldRData
); // ... and let the client know
2193 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2194 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2195 // Exported so uDNS.c can call this
2196 mDNSexport mStatus
mDNS_Deregister_internal(mDNS
*const m
, AuthRecord
*const rr
, mDNS_Dereg_type drt
)
2199 mDNSu8 RecordType
= rr
->resrec
.RecordType
;
2200 AuthRecord
**p
= &m
->ResourceRecords
; // Find this record in our list of active records
2202 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2206 // We found our record on the main list. See if there are any duplicates that need special handling.
2207 if (drt
== mDNS_Dereg_conflict
) // If this was a conflict, see that all duplicates get the same treatment
2209 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2210 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2211 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
) if (RecordIsLocalDuplicate(r2
, rr
)) r2
->ProbeCount
= 0xFF;
2215 // Before we delete the record (and potentially send a goodbye packet)
2216 // first see if we have a record on the duplicate list ready to take over from it.
2217 AuthRecord
**d
= &m
->DuplicateRecords
;
2218 while (*d
&& !RecordIsLocalDuplicate(*d
, rr
)) d
=&(*d
)->next
;
2221 AuthRecord
*dup
= *d
;
2222 debugf("Duplicate record %p taking over from %p %##s (%s)",
2223 dup
, rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2224 *d
= dup
->next
; // Cut replacement record from DuplicateRecords list
2225 dup
->next
= rr
->next
; // And then...
2226 rr
->next
= dup
; // ... splice it in right after the record we're about to delete
2227 dup
->resrec
.RecordType
= rr
->resrec
.RecordType
;
2228 dup
->ProbeCount
= rr
->ProbeCount
;
2229 dup
->AnnounceCount
= rr
->AnnounceCount
;
2230 dup
->RequireGoodbye
= rr
->RequireGoodbye
;
2231 dup
->AnsweredLocalQ
= rr
->AnsweredLocalQ
;
2232 dup
->ImmedAnswer
= rr
->ImmedAnswer
;
2233 dup
->ImmedUnicast
= rr
->ImmedUnicast
;
2234 dup
->ImmedAdditional
= rr
->ImmedAdditional
;
2235 dup
->v4Requester
= rr
->v4Requester
;
2236 dup
->v6Requester
= rr
->v6Requester
;
2237 dup
->ThisAPInterval
= rr
->ThisAPInterval
;
2238 dup
->LastAPTime
= rr
->LastAPTime
;
2239 dup
->LastMCTime
= rr
->LastMCTime
;
2240 dup
->LastMCInterface
= rr
->LastMCInterface
;
2241 dup
->UpdateServer
= rr
->UpdateServer
;
2242 dup
->UpdatePort
= rr
->UpdatePort
;
2243 dup
->Private
= rr
->Private
;
2244 dup
->state
= rr
->state
;
2245 rr
->RequireGoodbye
= mDNSfalse
;
2246 rr
->AnsweredLocalQ
= mDNSfalse
;
2252 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2253 p
= &m
->DuplicateRecords
;
2254 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2255 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2256 if (*p
) rr
->RequireGoodbye
= mDNSfalse
;
2257 if (*p
) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2258 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2263 // No need to log an error message if we already know this is a potentially repeated deregistration
2264 if (drt
!= mDNS_Dereg_repeat
)
2265 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr
, ARDisplayString(m
,rr
));
2266 return(mStatus_BadReferenceErr
);
2269 // If this is a shared record and we've announced it at least once,
2270 // we need to retract that announcement before we delete the record
2272 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2273 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
2274 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2275 // mechanism to cope with the client callback modifying the question list while that's happening.
2276 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2277 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2278 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2279 // records, thereby invoking yet more callbacks, without limit.
2280 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2281 // actual goodbye packets.
2283 #ifndef UNICAST_DISABLED
2284 if (AuthRecord_uDNS(rr
) && rr
->RequireGoodbye
)
2286 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2287 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2288 uDNS_DeregisterRecord(m
, rr
);
2289 // At this point unconditionally we bail out
2290 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2291 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2292 // process and will complete asynchronously. Either way we don't need to do anything more here.
2293 return(mStatus_NoError
);
2295 #endif // UNICAST_DISABLED
2297 if (RecordType
== kDNSRecordTypeShared
&& (rr
->RequireGoodbye
|| rr
->AnsweredLocalQ
))
2299 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m
, rr
));
2300 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2301 rr
->resrec
.rroriginalttl
= 0;
2302 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2303 if (m
->NextScheduledResponse
- (m
->timenow
+ mDNSPlatformOneSecond
/10) >= 0)
2304 m
->NextScheduledResponse
= (m
->timenow
+ mDNSPlatformOneSecond
/10);
2308 *p
= rr
->next
; // Cut this record from the list
2309 // If someone is about to look at this, bump the pointer forward
2310 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
2311 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
2312 rr
->next
= mDNSNULL
;
2314 if (RecordType
== kDNSRecordTypeUnregistered
)
2315 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m
, rr
));
2316 else if (RecordType
== kDNSRecordTypeDeregistering
)
2317 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m
, rr
));
2320 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m
, rr
));
2321 rr
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2324 if ((drt
== mDNS_Dereg_conflict
|| drt
== mDNS_Dereg_repeat
) && RecordType
== kDNSRecordTypeShared
)
2325 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2326 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2328 // If we have an update queued up which never executed, give the client a chance to free that memory
2329 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
2331 if (rr
->nta
) { CancelGetZoneData(m
, rr
->nta
); rr
->nta
= mDNSNULL
; }
2332 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2334 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2335 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2336 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2337 // so any attempt to touch rr after this is likely to lead to a crash.
2338 if (drt
!= mDNS_Dereg_conflict
)
2340 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2341 if (rr
->RecordCallback
)
2342 rr
->RecordCallback(m
, rr
, mStatus_MemFree
); // MUST NOT touch rr after this
2343 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2347 RecordProbeFailure(m
, rr
);
2348 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2349 if (rr
->RecordCallback
)
2350 rr
->RecordCallback(m
, rr
, mStatus_NameConflict
); // MUST NOT touch rr after this
2351 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2352 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2353 // Note that with all the client callbacks going on, by the time we get here all the
2354 // records we marked may have been explicitly deregistered by the client anyway.
2355 r2
= m
->DuplicateRecords
;
2358 if (r2
->ProbeCount
!= 0xFF) r2
= r2
->next
;
2359 else { mDNS_Deregister_internal(m
, r2
, mDNS_Dereg_conflict
); r2
= m
->DuplicateRecords
; }
2363 return(mStatus_NoError
);
2366 // ***************************************************************************
2367 #if COMPILER_LIKES_PRAGMA_MARK
2369 #pragma mark - Packet Sending Functions
2372 mDNSlocal
void AddRecordToResponseList(AuthRecord
***nrpp
, AuthRecord
*rr
, AuthRecord
*add
)
2374 if (rr
->NextResponse
== mDNSNULL
&& *nrpp
!= &rr
->NextResponse
)
2377 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2378 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2379 // The referenced record will definitely be acceptable (by recursive application of this rule)
2380 if (add
&& add
->NR_AdditionalTo
) add
= add
->NR_AdditionalTo
;
2381 rr
->NR_AdditionalTo
= add
;
2382 *nrpp
= &rr
->NextResponse
;
2384 debugf("AddRecordToResponseList: %##s (%s) already in list", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2387 mDNSlocal
void AddAdditionalsToResponseList(mDNS
*const m
, AuthRecord
*ResponseRecords
, AuthRecord
***nrpp
, const mDNSInterfaceID InterfaceID
)
2389 AuthRecord
*rr
, *rr2
;
2390 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // For each record we plan to put
2392 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2393 // later in the "for" loop, and we will follow further "additional" links then.)
2394 if (rr
->Additional1
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional1
, InterfaceID
))
2395 AddRecordToResponseList(nrpp
, rr
->Additional1
, rr
);
2397 if (rr
->Additional2
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional2
, InterfaceID
))
2398 AddRecordToResponseList(nrpp
, rr
->Additional2
, rr
);
2400 // For SRV records, automatically add the Address record(s) for the target host
2401 if (rr
->resrec
.rrtype
== kDNSType_SRV
)
2403 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2404 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2405 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2406 rr
->resrec
.rdatahash
== rr2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2407 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, rr2
->resrec
.name
))
2408 AddRecordToResponseList(nrpp
, rr2
, rr
);
2410 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
)) // For A or AAAA, put counterpart as additional
2412 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2413 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2414 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2415 rr
->resrec
.namehash
== rr2
->resrec
.namehash
&& // ... and have the same name
2416 SameDomainName(rr
->resrec
.name
, rr2
->resrec
.name
))
2417 AddRecordToResponseList(nrpp
, rr2
, rr
);
2419 else if (rr
->resrec
.rrtype
== kDNSType_PTR
) // For service PTR, see if we want to add DeviceInfo record
2421 if (ResourceRecordIsValidInterfaceAnswer(&m
->DeviceInfo
, InterfaceID
) &&
2422 SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2423 AddRecordToResponseList(nrpp
, &m
->DeviceInfo
, rr
);
2428 mDNSlocal
void SendDelayedUnicastResponse(mDNS
*const m
, const mDNSAddr
*const dest
, const mDNSInterfaceID InterfaceID
)
2431 AuthRecord
*ResponseRecords
= mDNSNULL
;
2432 AuthRecord
**nrp
= &ResponseRecords
;
2434 // Make a list of all our records that need to be unicast to this destination
2435 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2437 // If we find we can no longer unicast this answer, clear ImmedUnicast
2438 if (rr
->ImmedAnswer
== mDNSInterfaceMark
||
2439 mDNSSameIPv4Address(rr
->v4Requester
, onesIPv4Addr
) ||
2440 mDNSSameIPv6Address(rr
->v6Requester
, onesIPv6Addr
) )
2441 rr
->ImmedUnicast
= mDNSfalse
;
2443 if (rr
->ImmedUnicast
&& rr
->ImmedAnswer
== InterfaceID
)
2444 if ((dest
->type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->v4Requester
, dest
->ip
.v4
)) ||
2445 (dest
->type
== mDNSAddrType_IPv6
&& mDNSSameIPv6Address(rr
->v6Requester
, dest
->ip
.v6
)))
2447 rr
->ImmedAnswer
= mDNSNULL
; // Clear the state fields
2448 rr
->ImmedUnicast
= mDNSfalse
;
2449 rr
->v4Requester
= zerov4Addr
;
2450 rr
->v6Requester
= zerov6Addr
;
2451 if (rr
->NextResponse
== mDNSNULL
&& nrp
!= &rr
->NextResponse
) // rr->NR_AnswerTo
2452 { rr
->NR_AnswerTo
= (mDNSu8
*)~0; *nrp
= rr
; nrp
= &rr
->NextResponse
; }
2456 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
2458 while (ResponseRecords
)
2460 mDNSu8
*responseptr
= m
->omsg
.data
;
2462 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2464 // Put answers in the packet
2465 while (ResponseRecords
&& ResponseRecords
->NR_AnswerTo
)
2467 rr
= ResponseRecords
;
2468 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2469 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2470 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2471 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2472 if (!newptr
&& m
->omsg
.h
.numAnswers
) break; // If packet full, send it now
2473 if (newptr
) responseptr
= newptr
;
2474 ResponseRecords
= rr
->NextResponse
;
2475 rr
->NextResponse
= mDNSNULL
;
2476 rr
->NR_AnswerTo
= mDNSNULL
;
2477 rr
->NR_AdditionalTo
= mDNSNULL
;
2478 rr
->RequireGoodbye
= mDNStrue
;
2481 // Add additionals, if there's space
2482 while (ResponseRecords
&& !ResponseRecords
->NR_AnswerTo
)
2484 rr
= ResponseRecords
;
2485 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2486 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2487 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2488 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2490 if (newptr
) responseptr
= newptr
;
2491 if (newptr
&& m
->omsg
.h
.numAnswers
) rr
->RequireGoodbye
= mDNStrue
;
2492 else if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) rr
->ImmedAnswer
= mDNSInterfaceMark
;
2493 ResponseRecords
= rr
->NextResponse
;
2494 rr
->NextResponse
= mDNSNULL
;
2495 rr
->NR_AnswerTo
= mDNSNULL
;
2496 rr
->NR_AdditionalTo
= mDNSNULL
;
2499 if (m
->omsg
.h
.numAnswers
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, mDNSInterface_Any
, mDNSNULL
, dest
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2503 mDNSexport
void CompleteDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2505 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2506 // it should go ahead and immediately dispose of this registration
2507 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
2508 rr
->RequireGoodbye
= mDNSfalse
;
2509 if (rr
->AnsweredLocalQ
) { AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNSfalse
); rr
->AnsweredLocalQ
= mDNSfalse
; }
2510 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
); // Don't touch rr after this
2513 // Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2514 // the record list and/or question list.
2515 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2516 mDNSlocal
void DiscardDeregistrations(mDNS
*const m
)
2518 if (m
->CurrentRecord
)
2519 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
2520 m
->CurrentRecord
= m
->ResourceRecords
;
2522 while (m
->CurrentRecord
)
2524 AuthRecord
*rr
= m
->CurrentRecord
;
2525 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2526 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2528 m
->CurrentRecord
= rr
->next
;
2532 mDNSlocal mStatus
GetLabelDecimalValue(const mDNSu8
*const src
, mDNSu8
*dst
)
2535 if (src
[0] < 1 || src
[0] > 3) return(mStatus_Invalid
);
2536 for (i
=1; i
<=src
[0]; i
++)
2538 if (src
[i
] < '0' || src
[i
] > '9') return(mStatus_Invalid
);
2539 val
= val
* 10 + src
[i
] - '0';
2541 if (val
> 255) return(mStatus_Invalid
);
2543 return(mStatus_NoError
);
2546 mDNSlocal mStatus
GetIPv4FromName(mDNSAddr
*const a
, const domainname
*const name
)
2548 int skip
= CountLabels(name
) - 6;
2549 if (skip
< 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2550 if (GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+3)->c
, &a
->ip
.v4
.b
[0]) ||
2551 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+2)->c
, &a
->ip
.v4
.b
[1]) ||
2552 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+1)->c
, &a
->ip
.v4
.b
[2]) ||
2553 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+0)->c
, &a
->ip
.v4
.b
[3])) return mStatus_Invalid
;
2554 a
->type
= mDNSAddrType_IPv4
;
2555 return(mStatus_NoError
);
2558 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
2559 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
2560 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2562 mDNSlocal mStatus
GetIPv6FromName(mDNSAddr
*const a
, const domainname
*const name
)
2565 const domainname
*n
;
2567 int skip
= CountLabels(name
) - 34;
2568 if (skip
< 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2570 n
= SkipLeadingLabels(name
, skip
);
2571 for (i
=0; i
<16; i
++)
2573 if (n
->c
[0] != 1) return mStatus_Invalid
;
2574 l
= HexVal(n
->c
[1]);
2575 n
= (const domainname
*)(n
->c
+ 2);
2577 if (n
->c
[0] != 1) return mStatus_Invalid
;
2578 h
= HexVal(n
->c
[1]);
2579 n
= (const domainname
*)(n
->c
+ 2);
2581 if (l
<0 || h
<0) return mStatus_Invalid
;
2582 a
->ip
.v6
.b
[15-i
] = (h
<< 4) | l
;
2585 a
->type
= mDNSAddrType_IPv6
;
2586 return(mStatus_NoError
);
2589 mDNSlocal mDNSs32
ReverseMapDomainType(const domainname
*const name
)
2591 int skip
= CountLabels(name
) - 2;
2594 const domainname
*suffix
= SkipLeadingLabels(name
, skip
);
2595 if (SameDomainName(suffix
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4
;
2596 if (SameDomainName(suffix
, (const domainname
*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6
;
2598 return(mDNSAddrType_None
);
2601 mDNSlocal
void SendARP(mDNS
*const m
, const mDNSu8 op
, const AuthRecord
*const rr
,
2602 const mDNSu8
*const spa
, const mDNSu8
*const tha
, const mDNSu8
*const tpa
, const mDNSu8
*const dst
)
2605 mDNSu8
*ptr
= m
->omsg
.data
;
2606 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2607 if (!intf
) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr
->resrec
.InterfaceID
, ARDisplayString(m
,rr
)); return; }
2609 // 0x00 Destination address
2610 for (i
=0; i
<6; i
++) *ptr
++ = dst
[i
];
2612 // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
2613 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
2615 // 0x0C ARP Ethertype (0x0806)
2616 *ptr
++ = 0x08; *ptr
++ = 0x06;
2619 *ptr
++ = 0x00; *ptr
++ = 0x01; // Hardware address space; Ethernet = 1
2620 *ptr
++ = 0x08; *ptr
++ = 0x00; // Protocol address space; IP = 0x0800
2621 *ptr
++ = 6; // Hardware address length
2622 *ptr
++ = 4; // Protocol address length
2623 *ptr
++ = 0x00; *ptr
++ = op
; // opcode; Request = 1, Response = 2
2625 // 0x16 Sender hardware address (our MAC address)
2626 for (i
=0; i
<6; i
++) *ptr
++ = intf
->MAC
.b
[i
];
2628 // 0x1C Sender protocol address
2629 for (i
=0; i
<4; i
++) *ptr
++ = spa
[i
];
2631 // 0x20 Target hardware address
2632 for (i
=0; i
<6; i
++) *ptr
++ = tha
[i
];
2634 // 0x26 Target protocol address
2635 for (i
=0; i
<4; i
++) *ptr
++ = tpa
[i
];
2637 // 0x2A Total ARP Packet length 42 bytes
2638 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, rr
->resrec
.InterfaceID
);
2641 mDNSlocal
void SetupOwnerOpt(const mDNS
*const m
, const NetworkInterfaceInfo
*const intf
, rdataOPT
*const owner
)
2643 owner
->u
.owner
.vers
= 0;
2644 owner
->u
.owner
.seq
= m
->SleepSeqNum
;
2645 owner
->u
.owner
.HMAC
= m
->PrimaryMAC
;
2646 owner
->u
.owner
.IMAC
= intf
->MAC
;
2647 owner
->u
.owner
.password
= zeroEthAddr
;
2649 // Don't try to compute the optlen until *after* we've set up the data fields
2650 owner
->opt
= kDNSOpt_Owner
;
2651 owner
->optlen
= DNSOpt_Owner_Space(owner
) - 4;
2654 mDNSlocal
void GrantUpdateCredit(AuthRecord
*rr
)
2656 if (++rr
->UpdateCredits
>= kMaxUpdateCredits
) rr
->NextUpdateCredit
= 0;
2657 else rr
->NextUpdateCredit
= NonZeroTime(rr
->NextUpdateCredit
+ kUpdateCreditRefreshInterval
);
2660 // Note about acceleration of announcements to facilitate automatic coalescing of
2661 // multiple independent threads of announcements into a single synchronized thread:
2662 // The announcements in the packet may be at different stages of maturity;
2663 // One-second interval, two-second interval, four-second interval, and so on.
2664 // After we've put in all the announcements that are due, we then consider
2665 // whether there are other nearly-due announcements that are worth accelerating.
2666 // To be eligible for acceleration, a record MUST NOT be older (further along
2667 // its timeline) than the most mature record we've already put in the packet.
2668 // In other words, younger records can have their timelines accelerated to catch up
2669 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
2670 // Older records cannot have their timelines accelerated; this would just widen
2671 // the gap between them and their younger bretheren and get them even more out of sync.
2673 // Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
2674 // the record list and/or question list.
2675 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2676 mDNSlocal
void SendResponses(mDNS
*const m
)
2679 AuthRecord
*rr
, *r2
;
2680 mDNSs32 maxExistingAnnounceInterval
= 0;
2681 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
2683 m
->NextScheduledResponse
= m
->timenow
+ 0x78000000;
2685 if (m
->SleepState
== SleepState_Transferring
) RetrySPSRegistrations(m
);
2687 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2688 if (rr
->ImmedUnicast
)
2690 mDNSAddr v4
= { mDNSAddrType_IPv4
, {{{0}}} };
2691 mDNSAddr v6
= { mDNSAddrType_IPv6
, {{{0}}} };
2692 v4
.ip
.v4
= rr
->v4Requester
;
2693 v6
.ip
.v6
= rr
->v6Requester
;
2694 if (!mDNSIPv4AddressIsZero(rr
->v4Requester
)) SendDelayedUnicastResponse(m
, &v4
, rr
->ImmedAnswer
);
2695 if (!mDNSIPv6AddressIsZero(rr
->v6Requester
)) SendDelayedUnicastResponse(m
, &v6
, rr
->ImmedAnswer
);
2696 if (rr
->ImmedUnicast
)
2698 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m
, rr
));
2699 rr
->ImmedUnicast
= mDNSfalse
;
2704 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
2707 // Run through our list of records, and decide which ones we're going to announce on all interfaces
2708 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2710 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
2711 if (TimeToAnnounceThisRecord(rr
, m
->timenow
) && ResourceRecordIsValidAnswer(rr
))
2713 if (rr
->AddressProxy
.type
)
2715 rr
->AnnounceCount
--;
2716 rr
->ThisAPInterval
*= 2;
2717 rr
->LastAPTime
= m
->timenow
;
2718 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2720 LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr
->AnnounceCount
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
,rr
));
2721 SendARP(m
, 1, rr
, rr
->AddressProxy
.ip
.v4
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, onesEthAddr
.b
);
2723 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2725 //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
2726 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2731 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2732 if (maxExistingAnnounceInterval
< rr
->ThisAPInterval
)
2733 maxExistingAnnounceInterval
= rr
->ThisAPInterval
;
2734 if (rr
->UpdateBlocked
) rr
->UpdateBlocked
= 0;
2739 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
2740 // Eligible records that are more than half-way to their announcement time are accelerated
2741 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2742 if ((rr
->resrec
.InterfaceID
&& rr
->ImmedAnswer
) ||
2743 (rr
->ThisAPInterval
<= maxExistingAnnounceInterval
&&
2744 TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2) &&
2745 !rr
->AddressProxy
.type
&& // Don't include ARP Annoucements when considering which records to accelerate
2746 ResourceRecordIsValidAnswer(rr
)))
2747 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2749 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
2750 // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
2751 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
2752 // then all that means is that it won't get sent -- which would not be the end of the world.
2753 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2755 if (rr
->ImmedAnswer
&& rr
->resrec
.rrtype
== kDNSType_SRV
)
2756 for (r2
=m
->ResourceRecords
; r2
; r2
=r2
->next
) // Scan list of resource records
2757 if (RRTypeIsAddressType(r2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2758 ResourceRecordIsValidAnswer(r2
) && // ... which are valid for answer ...
2759 rr
->LastMCTime
- r2
->LastMCTime
>= 0 && // ... which we have not sent recently ...
2760 rr
->resrec
.rdatahash
== r2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2761 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, r2
->resrec
.name
) &&
2762 (rr
->ImmedAnswer
== mDNSInterfaceMark
|| rr
->ImmedAnswer
== r2
->resrec
.InterfaceID
))
2763 r2
->ImmedAdditional
= r2
->resrec
.InterfaceID
; // ... then mark this address record for sending too
2764 // We also make sure we send the DeviceInfo TXT record too, if necessary
2765 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
2766 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
2767 if (rr
->ImmedAnswer
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->resrec
.rrtype
== kDNSType_PTR
)
2768 if (ResourceRecordIsValidAnswer(&m
->DeviceInfo
) && SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2770 if (!m
->DeviceInfo
.ImmedAnswer
) m
->DeviceInfo
.ImmedAnswer
= rr
->ImmedAnswer
;
2771 else m
->DeviceInfo
.ImmedAnswer
= mDNSInterfaceMark
;
2775 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
2776 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
2777 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
2778 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
2779 // -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface
2780 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
2781 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2782 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2784 if (rr
->ImmedAnswer
) // If we're sending this as answer, see that its whole RRSet is similarly marked
2786 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2787 if (ResourceRecordIsValidAnswer(r2
))
2788 if (r2
->ImmedAnswer
!= mDNSInterfaceMark
&&
2789 r2
->ImmedAnswer
!= rr
->ImmedAnswer
&& SameResourceRecordSignature(r2
, rr
))
2790 r2
->ImmedAnswer
= !r2
->ImmedAnswer
? rr
->ImmedAnswer
: mDNSInterfaceMark
;
2792 else if (rr
->ImmedAdditional
) // If we're sending this as additional, see that its whole RRSet is similarly marked
2794 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2795 if (ResourceRecordIsValidAnswer(r2
))
2796 if (r2
->ImmedAdditional
!= rr
->ImmedAdditional
&& SameResourceRecordSignature(r2
, rr
))
2797 r2
->ImmedAdditional
= rr
->ImmedAdditional
;
2801 // Now set SendRNow state appropriately
2802 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2804 if (rr
->ImmedAnswer
== mDNSInterfaceMark
) // Sending this record on all appropriate interfaces
2806 rr
->SendRNow
= !intf
? mDNSNULL
: (rr
->resrec
.InterfaceID
) ? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
2807 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional if sending as answer
2808 rr
->LastMCTime
= m
->timenow
;
2809 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2810 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
2811 if (TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2))
2813 rr
->AnnounceCount
--;
2814 rr
->ThisAPInterval
*= 2;
2815 rr
->LastAPTime
= m
->timenow
;
2816 debugf("Announcing %##s (%s) %d", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->AnnounceCount
);
2819 else if (rr
->ImmedAnswer
) // Else, just respond to a single query on single interface:
2821 rr
->SendRNow
= rr
->ImmedAnswer
; // Just respond on that interface
2822 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional too
2823 rr
->LastMCTime
= m
->timenow
;
2824 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2826 SetNextAnnounceProbeTime(m
, rr
);
2827 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2831 // *** 2. Loop through interface list, sending records as appropriate
2837 int numAnnounce
= 0;
2839 mDNSu8
*responseptr
= m
->omsg
.data
;
2841 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2843 // First Pass. Look for:
2844 // 1. Deregistering records that need to send their goodbye packet
2845 // 2. Updated records that need to retract their old data
2846 // 3. Answers and announcements we need to send
2847 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2849 if (rr
->SendRNow
== intf
->InterfaceID
)
2852 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2854 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2855 if (newptr
) { responseptr
= newptr
; numDereg
++; }
2857 else if (rr
->NewRData
&& !m
->SleepState
) // If we have new data for this record
2859 RData
*OldRData
= rr
->resrec
.rdata
;
2860 mDNSu16 oldrdlength
= rr
->resrec
.rdlength
;
2861 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2862 if (ResourceRecordIsValidAnswer(rr
) && rr
->RequireGoodbye
)
2864 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2865 if (newptr
) { responseptr
= newptr
; numDereg
++; rr
->RequireGoodbye
= mDNSfalse
; }
2867 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2868 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
2869 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2870 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2871 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2872 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2873 if (newptr
) { responseptr
= newptr
; rr
->RequireGoodbye
= mDNStrue
; }
2874 SetNewRData(&rr
->resrec
, OldRData
, oldrdlength
);
2878 mDNSu8 active
= (m
->SleepState
!= SleepState_Sleeping
|| intf
->SPSAddr
[0].type
|| intf
->SPSAddr
[1].type
|| intf
->SPSAddr
[2].type
);
2879 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2880 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2881 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, active
? rr
->resrec
.rroriginalttl
: 0);
2882 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2885 responseptr
= newptr
;
2886 rr
->RequireGoodbye
= active
;
2887 if (rr
->LastAPTime
== m
->timenow
) numAnnounce
++; else numAnswer
++;
2890 // The first time through (pktcount==0), if this record is verified unique
2891 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2892 if (!pktcount
&& active
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= (mDNSInterfaceID
)1;
2895 if (newptr
) // If succeeded in sending, advance to next interface
2897 // If sending on all interfaces, go to next interface; else we're finished now
2898 if (rr
->ImmedAnswer
== mDNSInterfaceMark
&& rr
->resrec
.InterfaceID
== mDNSInterface_Any
)
2899 rr
->SendRNow
= GetNextActiveInterfaceID(intf
);
2901 rr
->SendRNow
= mDNSNULL
;
2906 // Second Pass. Add additional records, if there's space.
2907 newptr
= responseptr
;
2908 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2909 if (rr
->ImmedAdditional
== intf
->InterfaceID
)
2910 if (ResourceRecordIsValidAnswer(rr
))
2912 // If we have at least one answer already in the packet, then plan to add additionals too
2913 mDNSBool SendAdditional
= (m
->omsg
.h
.numAnswers
> 0);
2915 // If we're not planning to send any additionals, but this record is a unique one, then
2916 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2917 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2918 if (!SendAdditional
&& (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
))
2920 const AuthRecord
*a
;
2921 for (a
= m
->ResourceRecords
; a
; a
=a
->next
)
2922 if (a
->LastMCTime
== m
->timenow
&&
2923 a
->LastMCInterface
== intf
->InterfaceID
&&
2924 SameResourceRecordSignature(a
, rr
)) { SendAdditional
= mDNStrue
; break; }
2926 if (!SendAdditional
) // If we don't want to send this after all,
2927 rr
->ImmedAdditional
= mDNSNULL
; // then cancel its ImmedAdditional field
2928 else if (newptr
) // Else, try to add it if we can
2930 // The first time through (pktcount==0), if this record is verified unique
2931 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2932 if (!pktcount
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= (mDNSInterfaceID
)1;
2934 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2935 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2936 newptr
= PutResourceRecord(&m
->omsg
, newptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2937 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2940 responseptr
= newptr
;
2941 rr
->ImmedAdditional
= mDNSNULL
;
2942 rr
->RequireGoodbye
= mDNStrue
;
2943 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2944 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2945 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2946 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2947 rr
->LastMCTime
= m
->timenow
;
2948 rr
->LastMCInterface
= intf
->InterfaceID
;
2953 // Third Pass. Add NSEC records, if there's space.
2954 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2955 if (rr
->SendNSECNow
== (mDNSInterfaceID
)1 || rr
->SendNSECNow
== intf
->InterfaceID
)
2958 mDNS_SetupResourceRecord(&nsec
, mDNSNULL
, mDNSInterface_Any
, kDNSType_NSEC
, rr
->resrec
.rroriginalttl
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
2959 nsec
.resrec
.rrclass
|= kDNSClass_UniqueRRSet
;
2960 AssignDomainName(&nsec
.namestorage
, rr
->resrec
.name
);
2961 mDNSPlatformMemZero(nsec
.rdatastorage
.u
.nsec
.bitmap
, sizeof(nsec
.rdatastorage
.u
.nsec
.bitmap
));
2962 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2963 if (ResourceRecordIsValidAnswer(r2
) && SameResourceRecordNameClassInterface(r2
, rr
))
2965 if (r2
->resrec
.rrtype
>= kDNSQType_ANY
) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m
, r2
)); break; }
2966 else nsec
.rdatastorage
.u
.nsec
.bitmap
[r2
->resrec
.rrtype
>> 3] |= 128 >> (r2
->resrec
.rrtype
& 7);
2968 newptr
= responseptr
;
2969 if (!r2
) // If we successfully built our NSEC record, add it to the packet now
2971 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &nsec
.resrec
);
2972 if (newptr
) responseptr
= newptr
;
2975 // If we successfully put the NSEC record, clear the SendNSECNow flag
2976 // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
2977 if (newptr
|| rr
->SendNSECNow
== (mDNSInterfaceID
)1)
2979 rr
->SendNSECNow
= mDNSNULL
;
2980 // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
2981 for (r2
= rr
->next
; r2
; r2
=r2
->next
)
2982 if (SameResourceRecordNameClassInterface(r2
, rr
))
2983 if (r2
->SendNSECNow
== (mDNSInterfaceID
)1 || r2
->SendNSECNow
== intf
->InterfaceID
)
2984 r2
->SendNSECNow
= mDNSNULL
;
2988 if (m
->omsg
.h
.numAnswers
> 0 || m
->omsg
.h
.numAdditionals
)
2990 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2991 numDereg
, numDereg
== 1 ? "" : "s",
2992 numAnnounce
, numAnnounce
== 1 ? "" : "s",
2993 numAnswer
, numAnswer
== 1 ? "" : "s",
2994 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s", intf
->InterfaceID
);
2995 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2996 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2997 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
2998 if (++pktcount
>= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount
); break; }
2999 // There might be more things to send on this interface, so go around one more time and try again.
3001 else // Nothing more to send on this interface; go to next
3003 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3004 #if MDNS_DEBUGMSGS && 0
3005 const char *const msg
= next
? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3006 debugf(msg
, intf
, next
);
3009 pktcount
= 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
3014 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3017 if (m
->CurrentRecord
)
3018 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3019 m
->CurrentRecord
= m
->ResourceRecords
;
3020 while (m
->CurrentRecord
)
3022 rr
= m
->CurrentRecord
;
3023 m
->CurrentRecord
= rr
->next
;
3027 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3028 LogMsg("SendResponses: No active interface to send: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
3029 rr
->SendRNow
= mDNSNULL
;
3032 if (rr
->ImmedAnswer
)
3034 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
3036 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
3037 CompleteDeregistration(m
, rr
); // Don't touch rr after this
3040 rr
->ImmedAnswer
= mDNSNULL
;
3041 rr
->ImmedUnicast
= mDNSfalse
;
3042 rr
->v4Requester
= zerov4Addr
;
3043 rr
->v6Requester
= zerov6Addr
;
3047 verbosedebugf("SendResponses: Next in %ld ticks", m
->NextScheduledResponse
- m
->timenow
);
3050 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3051 // so we want to be lazy about how frequently we do it.
3052 // 1. If a cache record is currently referenced by *no* active questions,
3053 // then we don't mind expiring it up to a minute late (who will know?)
3054 // 2. Else, if a cache record is due for some of its final expiration queries,
3055 // we'll allow them to be late by up to 2% of the TTL
3056 // 3. Else, if a cache record has completed all its final expiration queries without success,
3057 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3058 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3059 // so allow at most 1/10 second lateness
3060 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
3061 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
3062 #define CacheCheckGracePeriod(RR) ( \
3063 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
3064 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
3065 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
3066 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
3067 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
3069 // Note: MUST call SetNextCacheCheckTime any time we change:
3071 // rr->resrec.rroriginalttl
3072 // rr->UnansweredQueries
3073 // rr->CRActiveQuestion
3074 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3075 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3076 mDNSlocal
void SetNextCacheCheckTime(mDNS
*const m
, CacheRecord
*const rr
)
3078 rr
->NextRequiredQuery
= RRExpireTime(rr
);
3080 // If we have an active question, then see if we want to schedule a refresher query for this record.
3081 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3082 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3084 rr
->NextRequiredQuery
-= TicksTTL(rr
)/20 * (MaxUnansweredQueries
- rr
->UnansweredQueries
);
3085 rr
->NextRequiredQuery
+= mDNSRandom((mDNSu32
)TicksTTL(rr
)/50);
3086 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3087 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
),
3088 (rr
->NextRequiredQuery
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
));
3091 if (m
->NextCacheCheck
- (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
)) > 0)
3092 m
->NextCacheCheck
= (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
));
3094 if (rr
->DelayDelivery
)
3095 if (m
->NextCacheCheck
- rr
->DelayDelivery
> 0)
3096 m
->NextCacheCheck
= rr
->DelayDelivery
;
3099 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
3100 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
3101 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
3102 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3104 mDNSlocal mStatus
mDNS_Reconfirm_internal(mDNS
*const m
, CacheRecord
*const rr
, mDNSu32 interval
)
3106 if (interval
< kMinimumReconfirmTime
)
3107 interval
= kMinimumReconfirmTime
;
3108 if (interval
> 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
3109 interval
= 0x10000000;
3111 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3112 if (RRExpireTime(rr
) - m
->timenow
> (mDNSs32
)((interval
* 4) / 3))
3114 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3115 // For all the reconfirmations in a given batch, we want to use the same random value
3116 // so that the reconfirmation questions can be grouped into a single query packet
3117 if (!m
->RandomReconfirmDelay
) m
->RandomReconfirmDelay
= 1 + mDNSRandom(0x3FFFFFFF);
3118 interval
+= m
->RandomReconfirmDelay
% ((interval
/3) + 1);
3119 rr
->TimeRcvd
= m
->timenow
- (mDNSs32
)interval
* 3;
3120 rr
->resrec
.rroriginalttl
= (interval
* 4 + mDNSPlatformOneSecond
- 1) / mDNSPlatformOneSecond
;
3121 SetNextCacheCheckTime(m
, rr
);
3123 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
3124 RRExpireTime(rr
) - m
->timenow
, CRDisplayString(m
, rr
), rr
->CRActiveQuestion
);
3125 return(mStatus_NoError
);
3128 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
3130 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3131 // It also appends to the list of known answer records that need to be included,
3132 // and updates the forcast for the size of the known answer section.
3133 mDNSlocal mDNSBool
BuildQuestion(mDNS
*const m
, DNSMessage
*query
, mDNSu8
**queryptr
, DNSQuestion
*q
,
3134 CacheRecord
***kalistptrptr
, mDNSu32
*answerforecast
)
3136 mDNSBool ucast
= (q
->LargeAnswers
|| q
->RequestUnicast
) && m
->CanReceiveUnicastOn5353
;
3137 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3138 const mDNSu8
*const limit
= query
->data
+ NormalMaxDNSMessageData
;
3139 mDNSu8
*newptr
= putQuestion(query
, *queryptr
, limit
, &q
->qname
, q
->qtype
, (mDNSu16
)(q
->qclass
| ucbit
));
3142 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3145 else if (newptr
+ *answerforecast
>= limit
)
3147 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3148 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ *answerforecast
- query
->data
);
3149 query
->h
.numQuestions
--;
3154 mDNSu32 forecast
= *answerforecast
;
3155 const mDNSu32 slot
= HashSlot(&q
->qname
);
3156 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3158 CacheRecord
**ka
= *kalistptrptr
; // Make a working copy of the pointer we're going to update
3160 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3161 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3162 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not already in the known answer list
3163 rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3164 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3165 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
> // and its half-way-to-expiry time is at least 1 second away
3166 mDNSPlatformOneSecond
) // (also ensures we never include goodbye records with TTL=1)
3168 *ka
= rr
; // Link this record into our known answer chain
3169 ka
= &rr
->NextInKAList
;
3170 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3171 forecast
+= 12 + rr
->resrec
.rdestimate
;
3172 // If we're trying to put more than one question in this packet, and it doesn't fit
3173 // then undo that last question and try again next time
3174 if (query
->h
.numQuestions
> 1 && newptr
+ forecast
>= limit
)
3176 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3177 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ forecast
- query
->data
);
3178 query
->h
.numQuestions
--;
3179 ka
= *kalistptrptr
; // Go back to where we started and retract these answer records
3180 while (*ka
) { CacheRecord
*c
= *ka
; *ka
= mDNSNULL
; ka
= &c
->NextInKAList
; }
3181 return(mDNSfalse
); // Return false, so we'll try again in the next packet
3185 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3186 *queryptr
= newptr
; // Update the packet pointer
3187 *answerforecast
= forecast
; // Update the forecast
3188 *kalistptrptr
= ka
; // Update the known answer list pointer
3189 if (ucast
) q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3191 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // For every resource record in our cache,
3192 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3193 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not in the known answer list
3194 SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) // which answers our question
3196 rr
->UnansweredQueries
++; // indicate that we're expecting a response
3197 rr
->LastUnansweredTime
= m
->timenow
;
3198 SetNextCacheCheckTime(m
, rr
);
3205 // When we have a query looking for a specified name, but there appear to be no answers with
3206 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
3207 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
3208 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
3209 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
3210 // A typical reconfirmation scenario might go like this:
3211 // Depth 0: Name "myhost.local" has no address records
3212 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
3213 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
3214 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
3215 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
3216 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
3217 mDNSlocal
void ReconfirmAntecedents(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const int depth
)
3222 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth
, name
->c
);
3223 FORALL_CACHERECORDS(slot
, cg
, cr
)
3225 domainname
*crtarget
= GetRRDomainNameTarget(&cr
->resrec
);
3226 if (crtarget
&& cr
->resrec
.rdatahash
== namehash
&& SameDomainName(crtarget
, name
))
3228 LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth
, CRDisplayString(m
, cr
));
3229 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
3230 if (depth
< 5) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, depth
+1);
3235 // If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
3236 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
3237 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
3238 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
3239 mDNSlocal
const CacheRecord
*CacheHasAddressTypeForName(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
)
3241 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(name
), namehash
, name
);
3242 const CacheRecord
*cr
= cg
? cg
->members
: mDNSNULL
;
3243 while (cr
&& !RRTypeIsAddressType(cr
->resrec
.rrtype
)) cr
=cr
->next
;
3247 mDNSlocal
const CacheRecord
*FindSPSInCache1(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*const c0
, const CacheRecord
*const c1
)
3249 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(&q
->qname
), q
->qnamehash
, &q
->qname
);
3250 const CacheRecord
*cr
, *bestcr
= mDNSNULL
;
3251 mDNSu32 bestmetric
= 1000000;
3252 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
3253 if (cr
->resrec
.rrtype
== kDNSType_PTR
&& cr
->resrec
.rdlength
>= 6) // If record is PTR type, with long enough name,
3254 if (cr
!= c0
&& cr
!= c1
) // that's not one we've seen before,
3255 if (SameNameRecordAnswersQuestion(&cr
->resrec
, q
)) // and answers our browse query,
3256 if (!IdenticalSameNameRecord(&cr
->resrec
, &m
->SPSRecords
.RR_PTR
.resrec
)) // and is not our own advertised service...
3258 mDNSu32 metric
= SPSMetric(cr
->resrec
.rdata
->u
.name
.c
);
3259 if (bestmetric
> metric
) { bestmetric
= metric
; bestcr
= cr
; }
3264 // Finds the three best Sleep Proxies we currently have in our cache
3265 mDNSexport
void FindSPSInCache(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*sps
[3])
3267 sps
[0] = FindSPSInCache1(m
, q
, mDNSNULL
, mDNSNULL
);
3268 sps
[1] = !sps
[0] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], mDNSNULL
);
3269 sps
[2] = !sps
[1] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], sps
[1]);
3272 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3273 mDNSlocal
void ExpireDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
)
3276 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3279 mDNSlocal
void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
, mDNSInterfaceID InterfaceID
)
3282 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3285 mDNSlocal mDNSBool
SuppressOnThisInterface(const DupSuppressInfo ds
[DupSuppressInfoSize
], const NetworkInterfaceInfo
* const intf
)
3288 mDNSBool v4
= !intf
->IPv4Available
; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3289 mDNSBool v6
= !intf
->IPv6Available
; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3290 for (i
=0; i
<DupSuppressInfoSize
; i
++)
3291 if (ds
[i
].InterfaceID
== intf
->InterfaceID
)
3293 if (ds
[i
].Type
== mDNSAddrType_IPv4
) v4
= mDNStrue
;
3294 else if (ds
[i
].Type
== mDNSAddrType_IPv6
) v6
= mDNStrue
;
3295 if (v4
&& v6
) return(mDNStrue
);
3300 mDNSlocal
int RecordDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 Time
, mDNSInterfaceID InterfaceID
, mDNSs32 Type
)
3304 // See if we have this one in our list somewhere already
3305 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Type
== Type
) break;
3307 // If not, find a slot we can re-use
3308 if (i
>= DupSuppressInfoSize
)
3311 for (j
=1; j
<DupSuppressInfoSize
&& ds
[i
].InterfaceID
; j
++)
3312 if (!ds
[j
].InterfaceID
|| ds
[j
].Time
- ds
[i
].Time
< 0)
3316 // Record the info about this query we saw
3318 ds
[i
].InterfaceID
= InterfaceID
;
3324 mDNSlocal mDNSBool
AccelerateThisQuery(mDNS
*const m
, DNSQuestion
*q
)
3326 // If more than 90% of the way to the query time, we should unconditionally accelerate it
3327 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/10))
3330 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3331 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/2))
3333 // We forecast: qname (n) type (2) class (2)
3334 mDNSu32 forecast
= (mDNSu32
)DomainNameLength(&q
->qname
) + 4;
3335 const mDNSu32 slot
= HashSlot(&q
->qname
);
3336 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3337 const CacheRecord
*rr
;
3338 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3339 if (rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3340 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3341 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
>= 0 && // and it is less than half-way to expiry
3342 rr
->NextRequiredQuery
- (m
->timenow
+ q
->ThisQInterval
) > 0)// and we'll ask at least once again before NextRequiredQuery
3344 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3345 forecast
+= 12 + rr
->resrec
.rdestimate
;
3346 if (forecast
>= 512) return(mDNSfalse
); // If this would add 512 bytes or more to the packet, don't accelerate
3354 // How Standard Queries are generated:
3355 // 1. The Question Section contains the question
3356 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3358 // How Probe Queries are generated:
3359 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3360 // if some other host is already using *any* records with this name, we want to know about it.
3361 // 2. The Authority Section contains the proposed values we intend to use for one or more
3362 // of our records with that name (analogous to the Update section of DNS Update packets)
3363 // because if some other host is probing at the same time, we each want to know what the other is
3364 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3366 mDNSlocal
void SendQueries(mDNS
*const m
)
3374 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3375 mDNSs32 maxExistingQuestionInterval
= 0;
3376 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
3377 CacheRecord
*KnownAnswerList
= mDNSNULL
;
3379 // 1. If time for a query, work out what we need to do
3380 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
3384 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
3385 // to their NextRequiredQuery to be worth batching them together with this one
3386 FORALL_CACHERECORDS(slot
, cg
, rr
)
3387 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3388 if (m
->timenow
+ TicksTTL(rr
)/50 - rr
->NextRequiredQuery
>= 0)
3390 debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr
->UnansweredQueries
, CRDisplayString(m
, rr
));
3391 q
= rr
->CRActiveQuestion
;
3392 ExpireDupSuppressInfoOnInterface(q
->DupSuppress
, m
->timenow
- TicksTTL(rr
)/20, rr
->resrec
.InterfaceID
);
3393 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
3394 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
3395 if (q
->Target
.type
) q
->SendQNow
= mDNSInterfaceMark
; // If targeted query, mark it
3396 else if (!mDNSOpaque16IsZero(q
->TargetQID
)) { q
->LastQTime
= m
->timenow
- q
->ThisQInterval
; rr
->UnansweredQueries
++; }
3397 else if (q
->SendQNow
== mDNSNULL
) q
->SendQNow
= rr
->resrec
.InterfaceID
;
3398 else if (q
->SendQNow
!= rr
->resrec
.InterfaceID
) q
->SendQNow
= mDNSInterfaceMark
;
3401 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
3402 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
3404 // Scan our list of questions to see which:
3405 // *WideArea* queries need to be sent
3406 // *unicast* queries need to be sent
3407 // *multicast* queries we're definitely going to send
3408 if (m
->CurrentQuestion
)
3409 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3410 m
->CurrentQuestion
= m
->Questions
;
3411 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3413 q
= m
->CurrentQuestion
;
3414 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
)) uDNS_CheckCurrentQuestion(m
);
3415 else if (mDNSOpaque16IsZero(q
->TargetQID
) && q
->Target
.type
&& (q
->SendQNow
|| TimeToSendThisQuestion(q
, m
->timenow
)))
3417 mDNSu8
*qptr
= m
->omsg
.data
;
3418 const mDNSu8
*const limit
= m
->omsg
.data
+ sizeof(m
->omsg
.data
);
3420 // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
3421 if (!q
->LocalSocket
) q
->LocalSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
3424 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, QueryFlags
);
3425 qptr
= putQuestion(&m
->omsg
, qptr
, limit
, &q
->qname
, q
->qtype
, q
->qclass
);
3426 mDNSSendDNSMessage(m
, &m
->omsg
, qptr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->Target
, q
->TargetPort
, mDNSNULL
, mDNSNULL
);
3427 q
->ThisQInterval
*= QuestionIntervalStep
;
3429 if (q
->ThisQInterval
> MaxQuestionInterval
)
3430 q
->ThisQInterval
= MaxQuestionInterval
;
3431 q
->LastQTime
= m
->timenow
;
3432 q
->LastQTxTime
= m
->timenow
;
3433 q
->RecentAnswerPkts
= 0;
3434 q
->SendQNow
= mDNSNULL
;
3435 q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3437 else if (mDNSOpaque16IsZero(q
->TargetQID
) && !q
->Target
.type
&& TimeToSendThisQuestion(q
, m
->timenow
))
3439 //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3440 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3441 if (maxExistingQuestionInterval
< q
->ThisQInterval
)
3442 maxExistingQuestionInterval
= q
->ThisQInterval
;
3444 // If m->CurrentQuestion wasn't modified out from under us, advance it now
3445 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
3446 // m->CurrentQuestion point to the right question
3447 if (q
== m
->CurrentQuestion
) m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
3449 m
->CurrentQuestion
= mDNSNULL
;
3451 // Scan our list of questions
3452 // (a) to see if there are any more that are worth accelerating, and
3453 // (b) to update the state variables for *all* the questions we're going to send
3454 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
3455 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
3456 // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
3457 m
->NextScheduledQuery
= m
->timenow
+ 0x78000000;
3458 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3460 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
||
3461 (!q
->Target
.type
&& ActiveQuestion(q
) && q
->ThisQInterval
<= maxExistingQuestionInterval
&& AccelerateThisQuery(m
,q
))))
3463 // If at least halfway to next query time, advance to next interval
3464 // If less than halfway to next query time, then
3465 // treat this as logically a repeat of the last transmission, without advancing the interval
3466 if (m
->timenow
- (q
->LastQTime
+ q
->ThisQInterval
/2) >= 0)
3468 //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3469 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3470 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
3471 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->ThisQInterval
/ InitialQuestionInterval
, q
->RequestUnicast
);
3472 q
->ThisQInterval
*= QuestionIntervalStep
;
3473 if (q
->ThisQInterval
> MaxQuestionInterval
)
3474 q
->ThisQInterval
= MaxQuestionInterval
;
3475 else if (q
->CurrentAnswers
== 0 && q
->ThisQInterval
== InitialQuestionInterval
* QuestionIntervalStep3
&& !q
->RequestUnicast
&&
3476 !(RRTypeIsAddressType(q
->qtype
) && CacheHasAddressTypeForName(m
, &q
->qname
, q
->qnamehash
)))
3478 // Generally don't need to log this.
3479 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
3480 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
3481 // and when there simply happen to be no instances of the service the client is looking
3482 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
3483 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3484 q
->qname
.c
, DNSTypeName(q
->qtype
));
3485 // Sending third query, and no answers yet; time to begin doubting the source
3486 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
3490 // Mark for sending. (If no active interfaces, then don't even try.)
3491 q
->SendOnAll
= (q
->SendQNow
== mDNSInterfaceMark
);
3494 q
->SendQNow
= !intf
? mDNSNULL
: (q
->InterfaceID
) ? q
->InterfaceID
: intf
->InterfaceID
;
3495 q
->LastQTime
= m
->timenow
;
3498 // If we recorded a duplicate suppression for this question less than half an interval ago,
3499 // then we consider it recent enough that we don't need to do an identical query ourselves.
3500 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
- q
->ThisQInterval
/2);
3502 q
->LastQTxTime
= m
->timenow
;
3503 q
->RecentAnswerPkts
= 0;
3504 if (q
->RequestUnicast
) q
->RequestUnicast
--;
3506 // For all questions (not just the ones we're sending) check what the next scheduled event will be
3507 SetNextQueryTime(m
,q
);
3511 // 2. Scan our authoritative RR list to see what probes we might need to send
3512 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
3514 m
->NextScheduledProbe
= m
->timenow
+ 0x78000000;
3516 if (m
->CurrentRecord
)
3517 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3518 m
->CurrentRecord
= m
->ResourceRecords
;
3519 while (m
->CurrentRecord
)
3521 AuthRecord
*rr
= m
->CurrentRecord
;
3522 m
->CurrentRecord
= rr
->next
;
3523 if (!AuthRecord_uDNS(rr
) && rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) // For all records that are still probing...
3525 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3526 if (m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) < 0)
3528 SetNextAnnounceProbeTime(m
, rr
);
3530 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3531 else if (rr
->ProbeCount
)
3533 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3535 LogSPS("SendQueries ARP Probe %d %s %s", rr
->ProbeCount
, InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), ARDisplayString(m
,rr
));
3536 SendARP(m
, 1, rr
, zerov4Addr
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, rr
->WakeUp
.IMAC
.b
);
3538 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3540 //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
3541 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
3543 // Mark for sending. (If no active interfaces, then don't even try.)
3544 rr
->SendRNow
= (!intf
|| rr
->WakeUp
.HMAC
.l
[0]) ? mDNSNULL
: rr
->resrec
.InterfaceID
? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
3545 rr
->LastAPTime
= m
->timenow
;
3546 // When we have a late conflict that resets a record to probing state we use a special marker value greater
3547 // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
3548 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
3549 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
3551 SetNextAnnounceProbeTime(m
, rr
);
3552 if (rr
->ProbeCount
== 0)
3554 // If this is the last probe for this record, then see if we have any matching records
3555 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
3557 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
)
3558 if (r2
->resrec
.RecordType
== kDNSRecordTypeUnique
&& RecordIsLocalDuplicate(r2
, rr
))
3560 // ... then acknowledge this record to the client.
3561 // We do this optimistically, just as we're about to send the third probe.
3562 // This helps clients that both advertise and browse, and want to filter themselves
3563 // from the browse results list, because it helps ensure that the registration
3564 // confirmation will be delivered 1/4 second *before* the browse "add" event.
3565 // A potential downside is that we could deliver a registration confirmation and then find out
3566 // moments later that there's a name conflict, but applications have to be prepared to handle
3567 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
3568 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
);
3571 // else, if it has now finished probing, move it to state Verified,
3572 // and update m->NextScheduledResponse so it will be announced
3575 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
); // Defensive, just in case it got missed somehow
3576 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
3577 rr
->ThisAPInterval
= DefaultAnnounceIntervalForTypeUnique
;
3578 rr
->LastAPTime
= m
->timenow
- DefaultAnnounceIntervalForTypeUnique
;
3579 SetNextAnnounceProbeTime(m
, rr
);
3583 m
->CurrentRecord
= m
->DuplicateRecords
;
3584 while (m
->CurrentRecord
)
3586 AuthRecord
*rr
= m
->CurrentRecord
;
3587 m
->CurrentRecord
= rr
->next
;
3588 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& rr
->ProbeCount
== 0 && !rr
->Acknowledged
)
3589 AcknowledgeRecord(m
, rr
);
3593 // 3. Now we know which queries and probes we're sending,
3594 // go through our interface list sending the appropriate queries on each interface
3597 const int os
= !intf
->MAC
.l
[0] ? 0 : DNSOpt_Header_Space
+ mDNSSameEthAddress(&m
->PrimaryMAC
, &intf
->MAC
) ? DNSOpt_OwnerData_ID_Space
: DNSOpt_OwnerData_ID_Wake_Space
;
3598 int OwnerRecordSpace
= 0;
3600 mDNSu8
*queryptr
= m
->omsg
.data
;
3601 mDNSu8
*limit
= m
->omsg
.data
+ AbsoluteMaxDNSMessageData
;
3602 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, QueryFlags
);
3603 if (KnownAnswerList
) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
3604 if (!KnownAnswerList
)
3606 // Start a new known-answer list
3607 CacheRecord
**kalistptr
= &KnownAnswerList
;
3608 mDNSu32 answerforecast
= 0;
3610 // Put query questions in this packet
3611 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3613 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
== intf
->InterfaceID
))
3615 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3616 SuppressOnThisInterface(q
->DupSuppress
, intf
) ? "Suppressing" : "Putting ",
3617 q
->qname
.c
, DNSTypeName(q
->qtype
), queryptr
- m
->omsg
.data
, queryptr
+ answerforecast
- m
->omsg
.data
);
3619 // If we're suppressing this question, or we successfully put it, update its SendQNow state
3620 if (SuppressOnThisInterface(q
->DupSuppress
, intf
) ||
3621 BuildQuestion(m
, &m
->omsg
, &queryptr
, q
, &kalistptr
, &answerforecast
))
3622 q
->SendQNow
= (q
->InterfaceID
|| !q
->SendOnAll
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3624 // Once we've put at least one question, cut back our limit to the normal single-packet size
3625 if (m
->omsg
.h
.numQuestions
) limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
;
3629 // Put probe questions in this packet
3630 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3631 if (rr
->SendRNow
== intf
->InterfaceID
)
3633 mDNSBool ucast
= (rr
->ProbeCount
>= DefaultProbeCountForTypeUnique
-1) && m
->CanReceiveUnicastOn5353
;
3634 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3635 mDNSu8
*newptr
= putQuestion(&m
->omsg
, queryptr
, limit
, rr
->resrec
.name
, kDNSQType_ANY
, (mDNSu16
)(rr
->resrec
.rrclass
| ucbit
));
3636 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3637 mDNSu32 forecast
= answerforecast
+ 12 + rr
->resrec
.rdestimate
;
3638 if (newptr
&& newptr
+ forecast
+ os
< limit
)
3641 limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
;
3642 answerforecast
= forecast
;
3643 OwnerRecordSpace
= os
;
3644 rr
->SendRNow
= (rr
->resrec
.InterfaceID
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3645 rr
->IncludeInProbe
= mDNStrue
;
3646 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
3647 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->ProbeCount
);
3651 verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
3652 m
->omsg
.h
.numQuestions
--;
3657 if (m
->omsg
.h
.numQuestions
) limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
- OwnerRecordSpace
;
3659 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3660 while (KnownAnswerList
)
3662 CacheRecord
*ka
= KnownAnswerList
;
3663 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- ka
->TimeRcvd
)) / mDNSPlatformOneSecond
;
3664 mDNSu8
*newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAnswers
, &ka
->resrec
, ka
->resrec
.rroriginalttl
- SecsSinceRcvd
, limit
);
3667 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
3668 ka
->resrec
.name
->c
, DNSTypeName(ka
->resrec
.rrtype
), queryptr
- m
->omsg
.data
, newptr
- m
->omsg
.data
);
3670 limit
= m
->omsg
.data
+ NormalMaxDNSMessageData
- OwnerRecordSpace
;
3671 KnownAnswerList
= ka
->NextInKAList
;
3672 ka
->NextInKAList
= mDNSNULL
;
3676 // If we ran out of space and we have more than one question in the packet, that's an error --
3677 // we shouldn't have put more than one question if there was a risk of us running out of space.
3678 if (m
->omsg
.h
.numQuestions
> 1)
3679 LogMsg("SendQueries: Put %d answers; No more space for known answers", m
->omsg
.h
.numAnswers
);
3680 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_TC
;
3685 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3686 if (rr
->IncludeInProbe
)
3688 mDNSu8
*newptr
= PutResourceRecord(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAuthorities
, &rr
->resrec
);
3689 rr
->IncludeInProbe
= mDNSfalse
;
3690 if (newptr
) queryptr
= newptr
;
3691 else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m
,rr
));
3694 if (OwnerRecordSpace
)
3697 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
3698 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
3699 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
3700 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
3701 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[0]);
3702 LogSPS("SendQueries putting %s", ARDisplayString(m
, &opt
));
3703 queryptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAdditionals
,
3704 &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
3706 LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3707 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAdditionals
, ARDisplayString(m
, &opt
));
3710 if (queryptr
> m
->omsg
.data
)
3712 if ((m
->omsg
.h
.flags
.b
[0] & kDNSFlag0_TC
) && m
->omsg
.h
.numQuestions
> 1)
3713 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m
->omsg
.h
.numQuestions
);
3714 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
3715 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
3716 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
3717 m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAuthorities
== 1 ? "" : "s", intf
->InterfaceID
);
3718 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3719 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3720 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
3721 if (++pktcount
>= 1000)
3722 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount
); break; }
3723 // There might be more records left in the known answer list, or more questions to send
3724 // on this interface, so go around one more time and try again.
3726 else // Nothing more to send on this interface; go to next
3728 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3729 #if MDNS_DEBUGMSGS && 0
3730 const char *const msg
= next
? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
3731 debugf(msg
, intf
, next
);
3737 // 4. Final housekeeping
3739 // 4a. Debugging check: Make sure we announced all our records
3740 for (ar
= m
->ResourceRecords
; ar
; ar
=ar
->next
)
3743 if (ar
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3744 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m
, ar
));
3745 ar
->SendRNow
= mDNSNULL
;
3748 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3749 // that their interface which went away might come back again, the logic will want to send queries
3750 // for those records, but we can't because their interface isn't here any more, so to keep the
3751 // state machine ticking over we just pretend we did so.
3752 // If the interface does not come back in time, the cache record will expire naturally
3753 FORALL_CACHERECORDS(slot
, cg
, cr
)
3754 if (cr
->CRActiveQuestion
&& cr
->UnansweredQueries
< MaxUnansweredQueries
&& m
->timenow
- cr
->NextRequiredQuery
>= 0)
3756 cr
->UnansweredQueries
++;
3757 cr
->CRActiveQuestion
->SendQNow
= mDNSNULL
;
3758 SetNextCacheCheckTime(m
, cr
);
3761 // 4c. Debugging check: Make sure we sent all our planned questions
3762 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3763 // we legitimately couldn't send because the interface is no longer available
3764 for (q
= m
->Questions
; q
; q
=q
->next
)
3767 LogMsg("SendQueries: No active interface to send: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3768 q
->SendQNow
= mDNSNULL
;
3772 mDNSlocal
void SendWakeup(mDNS
*const m
, mDNSInterfaceID InterfaceID
, mDNSEthAddr
*EthAddr
, mDNSOpaque48
*password
)
3775 mDNSu8
*ptr
= m
->omsg
.data
;
3777 if (!InterfaceID
) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
3779 // 0x00 Destination address
3780 for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3782 // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
3783 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
3785 // 0x0C Ethertype (0x0842)
3789 // 0x0E Wakeup sync sequence
3790 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
3793 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3796 for (i
=0; i
<6; i
++) *ptr
++ = password
->b
[i
];
3798 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3800 // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
3801 // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
3802 // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
3803 // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
3804 // So, we send one of each, unicast first, then broadcast second.
3805 for (i
=0; i
<6; i
++) m
->omsg
.data
[i
] = 0xFF;
3806 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3809 // ***************************************************************************
3810 #if COMPILER_LIKES_PRAGMA_MARK
3812 #pragma mark - RR List Management & Task Management
3815 // Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3816 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
3817 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
3818 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
3819 mDNSexport
void AnswerCurrentQuestionWithResourceRecord(mDNS
*const m
, CacheRecord
*const rr
, const QC_result AddRecord
)
3821 DNSQuestion
*const q
= m
->CurrentQuestion
;
3822 mDNSBool followcname
= rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& AddRecord
&&
3823 rr
->resrec
.rrtype
== kDNSType_CNAME
&& q
->qtype
!= kDNSType_CNAME
;
3824 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q
->CurrentAnswers
, AddRecord
? "Add" : "Rmv", rr
->resrec
.rroriginalttl
, CRDisplayString(m
, rr
));
3826 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
3827 // may be called twice, once when the record is received, and again when it's time to notify local clients.
3828 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3830 rr
->LastUsed
= m
->timenow
;
3831 if (AddRecord
== QC_add
&& !q
->DuplicateOf
&& rr
->CRActiveQuestion
!= q
)
3833 if (!rr
->CRActiveQuestion
) m
->rrcache_active
++; // If not previously active, increment rrcache_active count
3834 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
3835 rr
->CRActiveQuestion
= q
; // We know q is non-null
3836 SetNextCacheCheckTime(m
, rr
);
3840 // (a) a no-cache add, where we've already done at least one 'QM' query, or
3841 // (b) a normal add, where we have at least one unique-type answer,
3842 // then there's no need to keep polling the network.
3843 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3844 // We do this for mDNS questions and uDNS one-shot questions, but not for
3845 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
3846 if ((AddRecord
== QC_addnocache
&& !q
->RequestUnicast
) ||
3847 (AddRecord
== QC_add
&& (q
->ExpectUnique
|| (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))))
3848 if (ActiveQuestion(q
) && (mDNSOpaque16IsZero(q
->TargetQID
) || !q
->LongLived
))
3850 q
->LastQTime
= m
->timenow
;
3851 q
->LastQTxTime
= m
->timenow
;
3852 q
->RecentAnswerPkts
= 0;
3853 q
->ThisQInterval
= MaxQuestionInterval
;
3854 q
->RequestUnicast
= mDNSfalse
;
3855 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3858 if (rr
->DelayDelivery
) return; // We'll come back later when CacheRecordDeferredAdd() calls us
3860 // Only deliver negative answers if client has explicitly requested them
3861 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
|| (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
)))
3862 if (!AddRecord
|| !q
->ReturnIntermed
) return;
3864 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
3865 if (q
->QuestionCallback
&& !q
->NoAnswer
&& (!followcname
|| q
->ReturnIntermed
))
3867 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
3868 if (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
))
3871 MakeNegativeCacheRecord(m
, &neg
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 1, rr
->resrec
.InterfaceID
);
3872 q
->QuestionCallback(m
, q
, &neg
.resrec
, AddRecord
);
3875 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
3876 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3878 // Note: Proceed with caution here because client callback function is allowed to do anything,
3879 // including starting/stopping queries, registering/deregistering records, etc.
3881 if (followcname
&& m
->CurrentQuestion
== q
&& q
->CNAMEReferrals
< 10)
3883 const mDNSu32 c
= q
->CNAMEReferrals
+ 1;
3884 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
3885 // and track CNAMEs coming and going, we should really create a subordinate query here,
3886 // which we would subsequently cancel and retract if the CNAME referral record were removed.
3887 // In reality this is such a corner case we'll ignore it until someone actually needs it.
3888 LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m
, rr
));
3889 mDNS_StopQuery_internal(m
, q
); // Stop old query
3890 AssignDomainName(&q
->qname
, &rr
->resrec
.rdata
->u
.name
); // Update qname
3891 q
->qnamehash
= DomainNameHashValue(&q
->qname
); // and namehash
3892 mDNS_StartQuery_internal(m
, q
); // start new query
3893 q
->CNAMEReferrals
= c
; // and keep count of how many times we've done this
3897 mDNSlocal
void CacheRecordDeferredAdd(mDNS
*const m
, CacheRecord
*rr
)
3899 rr
->DelayDelivery
= 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3900 if (m
->CurrentQuestion
)
3901 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3902 m
->CurrentQuestion
= m
->Questions
;
3903 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3905 DNSQuestion
*q
= m
->CurrentQuestion
;
3906 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3907 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3908 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3909 m
->CurrentQuestion
= q
->next
;
3911 m
->CurrentQuestion
= mDNSNULL
;
3914 mDNSlocal mDNSs32
CheckForSoonToExpireRecords(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const mDNSu32 slot
)
3916 const mDNSs32 threshhold
= m
->timenow
+ mDNSPlatformOneSecond
; // See if there are any records expiring within one second
3917 const mDNSs32 start
= m
->timenow
- 0x10000000;
3918 mDNSs32 delay
= start
;
3919 CacheGroup
*cg
= CacheGroupForName(m
, slot
, namehash
, name
);
3920 const CacheRecord
*rr
;
3921 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
3922 if (threshhold
- RRExpireTime(rr
) >= 0) // If we have records about to expire within a second
3923 if (delay
- RRExpireTime(rr
) < 0) // then delay until after they've been deleted
3924 delay
= RRExpireTime(rr
);
3925 if (delay
- start
> 0) return(NonZeroTime(delay
));
3929 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3930 // If new questions are created as a result of invoking client callbacks, they will be added to
3931 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3932 // rr is a new CacheRecord just received into our cache
3933 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3934 // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3935 // which may change the record list and/or question list.
3936 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3937 mDNSlocal
void CacheRecordAdd(mDNS
*const m
, CacheRecord
*rr
)
3941 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3942 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3943 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3945 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3947 // If this question is one that's actively sending queries, and it's received ten answers within one
3948 // second of sending the last query packet, then that indicates some radical network topology change,
3949 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
3950 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
3951 // because we will anyway send another query within a few seconds. The first reset query is sent out
3952 // randomized over the next four seconds to reduce possible synchronization between machines.
3953 if (q
->LastAnswerPktNum
!= m
->PktNum
)
3955 q
->LastAnswerPktNum
= m
->PktNum
;
3956 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
) && ++q
->RecentAnswerPkts
>= 10 &&
3957 q
->ThisQInterval
> InitialQuestionInterval
* QuestionIntervalStep3
&& m
->timenow
- q
->LastQTxTime
< mDNSPlatformOneSecond
)
3959 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
3960 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->RecentAnswerPkts
, q
->ThisQInterval
);
3961 q
->LastQTime
= m
->timenow
- InitialQuestionInterval
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*4);
3962 q
->ThisQInterval
= InitialQuestionInterval
;
3963 SetNextQueryTime(m
,q
);
3966 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
3967 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->resrec
.rroriginalttl
);
3968 q
->CurrentAnswers
++;
3969 q
->unansweredQueries
= 0;
3970 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
3971 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
3972 if (q
->CurrentAnswers
> 4000)
3974 static int msgcount
= 0;
3975 if (msgcount
++ < 10)
3976 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
3977 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->CurrentAnswers
);
3978 rr
->resrec
.rroriginalttl
= 0;
3979 rr
->UnansweredQueries
= MaxUnansweredQueries
;
3984 if (!rr
->DelayDelivery
)
3986 if (m
->CurrentQuestion
)
3987 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3988 m
->CurrentQuestion
= m
->Questions
;
3989 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3991 q
= m
->CurrentQuestion
;
3992 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3993 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3994 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3995 m
->CurrentQuestion
= q
->next
;
3997 m
->CurrentQuestion
= mDNSNULL
;
4000 SetNextCacheCheckTime(m
, rr
);
4003 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4004 // If new questions are created as a result of invoking client callbacks, they will be added to
4005 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4006 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4007 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4008 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4009 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4010 // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4011 // which may change the record list and/or question list.
4012 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4013 mDNSlocal
void NoCacheAnswer(mDNS
*const m
, CacheRecord
*rr
)
4015 LogMsg("No cache space: Delivering non-cached result for %##s", m
->rec
.r
.resrec
.name
->c
);
4016 if (m
->CurrentQuestion
)
4017 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4018 m
->CurrentQuestion
= m
->Questions
;
4019 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
4020 // since we're not caching the record and we'll get no opportunity to do this later
4021 while (m
->CurrentQuestion
)
4023 DNSQuestion
*q
= m
->CurrentQuestion
;
4024 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4025 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_addnocache
); // QC_addnocache means "don't expect remove events for this"
4026 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4027 m
->CurrentQuestion
= q
->next
;
4029 m
->CurrentQuestion
= mDNSNULL
;
4032 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
4033 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
4034 // If new questions are created as a result of invoking client callbacks, they will be added to
4035 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4036 // rr is an existing cache CacheRecord that just expired and is being deleted
4037 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4038 // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4039 // which may change the record list and/or question list.
4040 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4041 mDNSlocal
void CacheRecordRmv(mDNS
*const m
, CacheRecord
*rr
)
4043 if (m
->CurrentQuestion
)
4044 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4045 m
->CurrentQuestion
= m
->Questions
;
4047 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
4048 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
4049 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
4051 DNSQuestion
*q
= m
->CurrentQuestion
;
4052 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4054 verbosedebugf("CacheRecordRmv %p %s", rr
, CRDisplayString(m
, rr
));
4055 q
->FlappingInterface1
= mDNSNULL
;
4056 q
->FlappingInterface2
= mDNSNULL
;
4057 if (q
->CurrentAnswers
== 0)
4058 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4059 q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4062 q
->CurrentAnswers
--;
4063 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
--;
4064 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
--;
4066 if (rr
->resrec
.rdata
->MaxRDLength
) // Never generate "remove" events for negative results
4068 if (q
->CurrentAnswers
== 0)
4070 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
4071 q
->qname
.c
, DNSTypeName(q
->qtype
));
4072 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
4074 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_rmv
);
4077 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4078 m
->CurrentQuestion
= q
->next
;
4080 m
->CurrentQuestion
= mDNSNULL
;
4083 mDNSlocal
void ReleaseCacheEntity(mDNS
*const m
, CacheEntity
*e
)
4085 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4087 for (i
=0; i
<sizeof(*e
); i
++) ((char*)e
)[i
] = 0xFF;
4089 e
->next
= m
->rrcache_free
;
4090 m
->rrcache_free
= e
;
4091 m
->rrcache_totalused
--;
4094 mDNSlocal
void ReleaseCacheGroup(mDNS
*const m
, CacheGroup
**cp
)
4096 CacheEntity
*e
= (CacheEntity
*)(*cp
);
4097 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4098 if ((*cp
)->rrcache_tail
!= &(*cp
)->members
)
4099 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4100 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
4101 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4102 if ((*cp
)->name
!= (domainname
*)((*cp
)->namestorage
)) mDNSPlatformMemFree((*cp
)->name
);
4103 (*cp
)->name
= mDNSNULL
;
4104 *cp
= (*cp
)->next
; // Cut record from list
4105 ReleaseCacheEntity(m
, e
);
4108 mDNSlocal
void ReleaseCacheRecord(mDNS
*const m
, CacheRecord
*r
)
4110 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
4111 if (r
->resrec
.rdata
&& r
->resrec
.rdata
!= (RData
*)&r
->smallrdatastorage
) mDNSPlatformMemFree(r
->resrec
.rdata
);
4112 r
->resrec
.rdata
= mDNSNULL
;
4113 ReleaseCacheEntity(m
, (CacheEntity
*)r
);
4116 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4117 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4118 // callbacks for old records are delivered before callbacks for newer records.
4119 mDNSlocal
void CheckCacheExpiration(mDNS
*const m
, CacheGroup
*const cg
)
4121 CacheRecord
**rp
= &cg
->members
;
4123 if (m
->lock_rrcache
) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4124 m
->lock_rrcache
= 1;
4128 CacheRecord
*const rr
= *rp
;
4129 mDNSs32 event
= RRExpireTime(rr
);
4130 if (m
->timenow
- event
>= 0) // If expired, delete it
4132 *rp
= rr
->next
; // Cut it from the list
4133 verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
4134 m
->timenow
- rr
->TimeRcvd
, rr
->resrec
.rroriginalttl
, rr
->CRActiveQuestion
, CRDisplayString(m
, rr
));
4135 if (rr
->CRActiveQuestion
) // If this record has one or more active questions, tell them it's going away
4137 CacheRecordRmv(m
, rr
);
4138 m
->rrcache_active
--;
4140 ReleaseCacheRecord(m
, rr
);
4142 else // else, not expired; see if we need to query
4144 if (rr
->DelayDelivery
&& rr
->DelayDelivery
- m
->timenow
> 0)
4145 event
= rr
->DelayDelivery
;
4148 if (rr
->DelayDelivery
) CacheRecordDeferredAdd(m
, rr
);
4149 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
4151 if (m
->timenow
- rr
->NextRequiredQuery
< 0) // If not yet time for next query
4152 event
= rr
->NextRequiredQuery
; // then just record when we want the next query
4153 else // else trigger our question to go out now
4155 // Set NextScheduledQuery to timenow so that SendQueries() will run.
4156 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
4157 m
->NextScheduledQuery
= m
->timenow
;
4158 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4159 // which will correctly update m->NextCacheCheck for us.
4160 event
= m
->timenow
+ 0x3FFFFFFF;
4164 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4165 (event
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
), CRDisplayString(m
, rr
));
4166 if (m
->NextCacheCheck
- (event
+ CacheCheckGracePeriod(rr
)) > 0)
4167 m
->NextCacheCheck
= (event
+ CacheCheckGracePeriod(rr
));
4171 if (cg
->rrcache_tail
!= rp
) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg
->rrcache_tail
, rp
);
4172 cg
->rrcache_tail
= rp
;
4173 m
->lock_rrcache
= 0;
4176 mDNSlocal
void AnswerNewQuestion(mDNS
*const m
)
4178 mDNSBool ShouldQueryImmediately
= mDNStrue
;
4179 DNSQuestion
*q
= m
->NewQuestions
; // Grab the question we're going to answer
4180 const mDNSu32 slot
= HashSlot(&q
->qname
);
4181 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4183 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4185 if (cg
) CheckCacheExpiration(m
, cg
);
4186 m
->NewQuestions
= q
->next
; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4188 if (m
->lock_rrcache
) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4189 // This should be safe, because calling the client's question callback may cause the
4190 // question list to be modified, but should not ever cause the rrcache list to be modified.
4191 // If the client's question callback deletes the question, then m->CurrentQuestion will
4192 // be advanced, and we'll exit out of the loop
4193 m
->lock_rrcache
= 1;
4194 if (m
->CurrentQuestion
)
4195 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4196 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4198 if (q
->NoAnswer
== NoAnswer_Fail
)
4200 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4201 MakeNegativeCacheRecord(m
, &m
->rec
.r
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60, mDNSInterface_Any
);
4202 q
->NoAnswer
= NoAnswer_Normal
; // Temporarily turn off answer suppression
4203 AnswerCurrentQuestionWithResourceRecord(m
, &m
->rec
.r
, QC_addnocache
);
4204 q
->NoAnswer
= NoAnswer_Fail
; // Restore NoAnswer state
4205 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4208 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4209 if (m
->CurrentQuestion
== q
&& q
->InterfaceID
== mDNSInterface_Any
)
4211 if (m
->CurrentRecord
)
4212 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4213 m
->CurrentRecord
= m
->ResourceRecords
;
4214 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4216 AuthRecord
*rr
= m
->CurrentRecord
;
4217 m
->CurrentRecord
= rr
->next
;
4218 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
4219 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4221 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4222 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4225 m
->CurrentRecord
= mDNSNULL
;
4228 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
4230 if (m
->CurrentQuestion
== q
)
4233 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4234 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
))
4236 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
4237 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- rr
->TimeRcvd
)) / mDNSPlatformOneSecond
;
4238 if (rr
->resrec
.rroriginalttl
<= SecsSinceRcvd
)
4240 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
4241 rr
->resrec
.rroriginalttl
, SecsSinceRcvd
, CRDisplayString(m
, rr
), m
->timenow
, rr
->TimeRcvd
);
4242 continue; // Go to next one in loop
4245 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
4246 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4247 if ((rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) || (q
->ExpectUnique
))
4248 ShouldQueryImmediately
= mDNSfalse
;
4249 q
->CurrentAnswers
++;
4250 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
4251 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
4252 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
4253 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4255 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
) && RRTypeIsAddressType(q
->qtype
))
4256 ShouldQueryImmediately
= mDNSfalse
;
4259 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving cache answers");
4261 if (m
->CurrentQuestion
== q
&& ShouldQueryImmediately
&& ActiveQuestion(q
))
4263 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4264 q
->ThisQInterval
= InitialQuestionInterval
;
4265 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4266 if (mDNSOpaque16IsZero(q
->TargetQID
)) // For mDNS, spread packets to avoid a burst of simultaneous queries
4268 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
4269 if (!m
->RandomQueryDelay
)
4270 m
->RandomQueryDelay
= (mDNSPlatformOneSecond
+ mDNSRandom(mDNSPlatformOneSecond
*5) - 1) / 50 + 1;
4271 q
->LastQTime
+= m
->RandomQueryDelay
;
4274 if (m
->NextScheduledQuery
- (q
->LastQTime
+ q
->ThisQInterval
) > 0)
4275 m
->NextScheduledQuery
= (q
->LastQTime
+ q
->ThisQInterval
);
4278 m
->CurrentQuestion
= mDNSNULL
;
4279 m
->lock_rrcache
= 0;
4282 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4283 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
4284 mDNSlocal
void AnswerNewLocalOnlyQuestion(mDNS
*const m
)
4286 DNSQuestion
*q
= m
->NewLocalOnlyQuestions
; // Grab the question we're going to answer
4287 m
->NewLocalOnlyQuestions
= q
->next
; // Advance NewLocalOnlyQuestions to the next (if any)
4289 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4291 if (m
->CurrentQuestion
)
4292 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4293 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4295 if (m
->CurrentRecord
)
4296 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4297 m
->CurrentRecord
= m
->ResourceRecords
;
4299 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4301 AuthRecord
*rr
= m
->CurrentRecord
;
4302 m
->CurrentRecord
= rr
->next
;
4303 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4305 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4306 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4310 m
->CurrentQuestion
= mDNSNULL
;
4311 m
->CurrentRecord
= mDNSNULL
;
4314 mDNSlocal CacheEntity
*GetCacheEntity(mDNS
*const m
, const CacheGroup
*const PreserveCG
)
4316 CacheEntity
*e
= mDNSNULL
;
4318 if (m
->lock_rrcache
) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL
); }
4319 m
->lock_rrcache
= 1;
4321 // If we have no free records, ask the client layer to give us some more memory
4322 if (!m
->rrcache_free
&& m
->MainCallback
)
4324 if (m
->rrcache_totalused
!= m
->rrcache_size
)
4325 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4326 m
->rrcache_totalused
, m
->rrcache_size
);
4328 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4329 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4330 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4331 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
4332 // and recycle them, instead of allocating more memory.
4333 if (m
->rrcache_size
> 5000 && m
->rrcache_size
/ 32 > m
->rrcache_active
)
4334 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4335 m
->rrcache_size
, m
->rrcache_active
);
4338 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4339 m
->MainCallback(m
, mStatus_GrowCache
);
4340 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4344 // If we still have no free records, recycle all the records we can.
4345 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4346 if (!m
->rrcache_free
)
4348 mDNSu32 oldtotalused
= m
->rrcache_totalused
;
4350 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4352 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4355 CacheRecord
**rp
= &(*cp
)->members
;
4358 // Records that answer still-active questions are not candidates for recycling
4359 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4360 if ((*rp
)->CRActiveQuestion
|| (*rp
)->NextInCFList
)
4364 CacheRecord
*rr
= *rp
;
4365 *rp
= (*rp
)->next
; // Cut record from list
4366 ReleaseCacheRecord(m
, rr
);
4369 if ((*cp
)->rrcache_tail
!= rp
)
4370 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot
, (*cp
)->rrcache_tail
, rp
);
4371 (*cp
)->rrcache_tail
= rp
;
4372 if ((*cp
)->members
|| (*cp
)==PreserveCG
) cp
=&(*cp
)->next
;
4373 else ReleaseCacheGroup(m
, cp
);
4376 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4377 oldtotalused
- m
->rrcache_totalused
, oldtotalused
, m
->rrcache_totalused
);
4380 if (m
->rrcache_free
) // If there are records in the free list, take one
4382 e
= m
->rrcache_free
;
4383 m
->rrcache_free
= e
->next
;
4384 if (++m
->rrcache_totalused
>= m
->rrcache_report
)
4386 LogInfo("RR Cache now using %ld objects", m
->rrcache_totalused
);
4387 if (m
->rrcache_report
< 100) m
->rrcache_report
+= 10;
4388 else if (m
->rrcache_report
< 1000) m
->rrcache_report
+= 100;
4389 else m
->rrcache_report
+= 1000;
4391 mDNSPlatformMemZero(e
, sizeof(*e
));
4394 m
->lock_rrcache
= 0;
4399 mDNSlocal CacheRecord
*GetCacheRecord(mDNS
*const m
, CacheGroup
*cg
, mDNSu16 RDLength
)
4401 CacheRecord
*r
= (CacheRecord
*)GetCacheEntity(m
, cg
);
4404 r
->resrec
.rdata
= (RData
*)&r
->smallrdatastorage
; // By default, assume we're usually going to be using local storage
4405 if (RDLength
> InlineCacheRDSize
) // If RDLength is too big, allocate extra storage
4407 r
->resrec
.rdata
= (RData
*)mDNSPlatformMemAllocate(sizeofRDataHeader
+ RDLength
);
4408 if (r
->resrec
.rdata
) r
->resrec
.rdata
->MaxRDLength
= r
->resrec
.rdlength
= RDLength
;
4409 else { ReleaseCacheEntity(m
, (CacheEntity
*)r
); r
= mDNSNULL
; }
4415 mDNSlocal CacheGroup
*GetCacheGroup(mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
4417 mDNSu16 namelen
= DomainNameLength(rr
->name
);
4418 CacheGroup
*cg
= (CacheGroup
*)GetCacheEntity(m
, mDNSNULL
);
4419 if (!cg
) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr
->name
->c
); return(mDNSNULL
); }
4420 cg
->next
= m
->rrcache_hash
[slot
];
4421 cg
->namehash
= rr
->namehash
;
4422 cg
->members
= mDNSNULL
;
4423 cg
->rrcache_tail
= &cg
->members
;
4424 cg
->name
= (domainname
*)cg
->namestorage
;
4425 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4426 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4427 if (namelen
> InlineCacheGroupNameSize
) cg
->name
= mDNSPlatformMemAllocate(namelen
);
4430 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr
->name
->c
);
4431 ReleaseCacheEntity(m
, (CacheEntity
*)cg
);
4434 AssignDomainName(cg
->name
, rr
->name
);
4436 if (CacheGroupForRecord(m
, slot
, rr
)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr
->name
->c
);
4437 m
->rrcache_hash
[slot
] = cg
;
4438 if (CacheGroupForRecord(m
, slot
, rr
) != cg
) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr
->name
->c
);
4443 mDNSexport
void mDNS_PurgeCacheResourceRecord(mDNS
*const m
, CacheRecord
*rr
)
4445 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4446 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4447 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4448 // a positive answer using an expired record (e.g. from an interface that has gone away).
4449 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4450 // summary deletion without giving the proper callback to any questions that are monitoring it.
4451 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4452 rr
->TimeRcvd
= m
->timenow
- mDNSPlatformOneSecond
* 60;
4453 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4454 rr
->resrec
.rroriginalttl
= 0;
4455 SetNextCacheCheckTime(m
, rr
);
4458 mDNSexport mDNSs32
mDNS_TimeNow(const mDNS
*const m
)
4461 mDNSPlatformLock(m
);
4464 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4465 if (!m
->timenow
) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
4468 if (m
->timenow
) time
= m
->timenow
;
4469 else time
= mDNS_TimeNow_NoLock(m
);
4470 mDNSPlatformUnlock(m
);
4474 // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4475 // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4476 // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4477 #define SetSPSProxyListChanged(X) do { \
4478 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4479 m->SPSProxyListChanged = (X); } while(0)
4481 // Called from mDNS_Execute() to expire stale proxy records
4482 mDNSlocal
void CheckProxyRecords(mDNS
*const m
, AuthRecord
*list
)
4484 m
->CurrentRecord
= list
;
4485 while (m
->CurrentRecord
)
4487 AuthRecord
*rr
= m
->CurrentRecord
;
4488 if (rr
->WakeUp
.HMAC
.l
[0])
4490 if (m
->timenow
- rr
->TimeExpire
< 0) // If proxy record not expired yet, update m->NextScheduledSPS
4492 if (m
->NextScheduledSPS
- rr
->TimeExpire
> 0)
4493 m
->NextScheduledSPS
= rr
->TimeExpire
;
4495 else // else proxy record expired, so remove it
4497 LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4498 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, ARDisplayString(m
, rr
));
4499 SetSPSProxyListChanged(rr
->resrec
.InterfaceID
);
4500 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
4501 // Don't touch rr after this -- memory may have been free'd
4504 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
4505 // because the list may have been changed in that call.
4506 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
4507 m
->CurrentRecord
= rr
->next
;
4511 mDNSexport mDNSs32
mDNS_Execute(mDNS
*const m
)
4513 mDNS_Lock(m
); // Must grab lock before trying to read m->timenow
4515 if (m
->timenow
- m
->NextScheduledEvent
>= 0)
4519 verbosedebugf("mDNS_Execute");
4520 if (m
->CurrentQuestion
)
4521 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4523 // 1. If we're past the probe suppression time, we can clear it
4524 if (m
->SuppressProbes
&& m
->timenow
- m
->SuppressProbes
>= 0) m
->SuppressProbes
= 0;
4526 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4527 if (m
->NumFailedProbes
&& m
->timenow
- m
->ProbeFailTime
>= mDNSPlatformOneSecond
* 10) m
->NumFailedProbes
= 0;
4529 // 3. Purge our cache of stale old records
4530 if (m
->rrcache_size
&& m
->timenow
- m
->NextCacheCheck
>= 0)
4533 m
->NextCacheCheck
= m
->timenow
+ 0x3FFFFFFF;
4534 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4536 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4539 CheckCacheExpiration(m
, *cp
);
4540 if ((*cp
)->members
) cp
=&(*cp
)->next
;
4541 else ReleaseCacheGroup(m
, cp
);
4546 if (m
->timenow
- m
->NextScheduledSPS
>= 0)
4548 m
->NextScheduledSPS
= m
->timenow
+ 0x3FFFFFFF;
4549 CheckProxyRecords(m
, m
->DuplicateRecords
); // Clear m->DuplicateRecords first, then m->ResourceRecords
4550 CheckProxyRecords(m
, m
->ResourceRecords
);
4553 SetSPSProxyListChanged(mDNSNULL
); // Perform any deferred BPF reconfiguration now
4555 if (m
->DelaySleep
&& m
->timenow
- m
->DelaySleep
>= 0)
4558 if (m
->SleepState
== SleepState_Transferring
)
4560 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4561 BeginSleepProcessing(m
);
4565 // 4. See if we can answer any of our new local questions from the cache
4566 for (i
=0; m
->NewQuestions
&& i
<1000; i
++)
4568 if (m
->NewQuestions
->DelayAnswering
&& m
->timenow
- m
->NewQuestions
->DelayAnswering
< 0) break;
4569 AnswerNewQuestion(m
);
4571 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4573 for (i
=0; m
->NewLocalOnlyQuestions
&& i
<1000; i
++) AnswerNewLocalOnlyQuestion(m
);
4574 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4576 for (i
=0; i
<1000 && m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
); i
++)
4578 AuthRecord
*rr
= m
->NewLocalRecords
;
4579 m
->NewLocalRecords
= m
->NewLocalRecords
->next
;
4580 AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNStrue
);
4582 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4584 // 5. See what packets we need to send
4585 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| (m
->SleepState
== SleepState_Sleeping
))
4586 DiscardDeregistrations(m
);
4587 if (m
->mDNSPlatformStatus
== mStatus_NoError
&& (m
->SuppressSending
== 0 || m
->timenow
- m
->SuppressSending
>= 0))
4589 // If the platform code is ready, and we're not suppressing packet generation right now
4590 // then send our responses, probes, and questions.
4591 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4592 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4593 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4594 // Finally, we send responses, including the previously mentioned records that just completed probing.
4595 m
->SuppressSending
= 0;
4597 // 6. Send Query packets. This may cause some probing records to advance to announcing state
4598 if (m
->timenow
- m
->NextScheduledQuery
>= 0 || m
->timenow
- m
->NextScheduledProbe
>= 0) SendQueries(m
);
4599 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
4602 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4603 m
->timenow
, m
->NextScheduledQuery
, m
->timenow
- m
->NextScheduledQuery
);
4604 m
->NextScheduledQuery
= m
->timenow
+ mDNSPlatformOneSecond
;
4605 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
4606 if (ActiveQuestion(q
) && q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
<= 0)
4607 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4609 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
4611 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4612 m
->timenow
, m
->NextScheduledProbe
, m
->timenow
- m
->NextScheduledProbe
);
4613 m
->NextScheduledProbe
= m
->timenow
+ mDNSPlatformOneSecond
;
4616 // 7. Send Response packets, including probing records just advanced to announcing state
4617 if (m
->timenow
- m
->NextScheduledResponse
>= 0) SendResponses(m
);
4618 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
4620 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4621 m
->NextScheduledResponse
= m
->timenow
+ mDNSPlatformOneSecond
;
4625 // Clear RandomDelay values, ready to pick a new different value next time
4626 m
->RandomQueryDelay
= 0;
4627 m
->RandomReconfirmDelay
= 0;
4630 // Note about multi-threaded systems:
4631 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4632 // performing mDNS API operations that change our next scheduled event time.
4634 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4635 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4636 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4637 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4638 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4639 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4640 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4641 // without blocking. This avoids the race condition between the signal from the other thread arriving
4642 // just *before* or just *after* the main thread enters the blocking primitive.
4644 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4645 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4646 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4647 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4648 // by the time it gets to the timer callback function).
4650 #ifndef UNICAST_DISABLED
4653 mDNS_Unlock(m
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4654 return(m
->NextScheduledEvent
);
4657 mDNSlocal
void SuspendLLQs(mDNS
*m
)
4660 for (q
= m
->Questions
; q
; q
= q
->next
)
4661 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->state
== LLQ_Established
)
4662 { q
->ReqLease
= 0; sendLLQRefresh(m
, q
); }
4665 // ActivateUnicastQuery() is called from three places:
4666 // 1. When a new question is created
4667 // 2. On wake from sleep
4668 // 3. When the DNS configuration changes
4669 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4670 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4671 mDNSlocal
void ActivateUnicastQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool ScheduleImmediately
)
4673 // For now this AutoTunnel stuff is specific to Mac OS X.
4674 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4675 #if APPLE_OSX_mDNSResponder
4676 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4677 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4678 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4679 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4680 // returns results for both at the same time.
4681 if (RRTypeIsAddressType(question
->qtype
) && question
->AuthInfo
&& question
->AuthInfo
->AutoTunnel
&& question
->QuestionCallback
!= AutoTunnelCallback
)
4683 question
->NoAnswer
= NoAnswer_Suspended
;
4684 AddNewClientTunnel(m
, question
);
4687 #endif // APPLE_OSX_mDNSResponder
4689 if (!question
->DuplicateOf
)
4691 debugf("ActivateUnicastQuery: %##s %s%s%s",
4692 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->AuthInfo
? " (Private)" : "", ScheduleImmediately
? " ScheduleImmediately" : "");
4693 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
4694 if (question
->LongLived
)
4696 question
->state
= LLQ_InitialRequest
;
4697 question
->id
= zeroOpaque64
;
4698 question
->servPort
= zeroIPPort
;
4699 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
4701 if (ScheduleImmediately
)
4703 question
->ThisQInterval
= InitialQuestionInterval
;
4704 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
4705 SetNextQueryTime(m
, question
);
4710 mDNSexport
void mDNSCoreRestartQueries(mDNS
*const m
)
4714 #ifndef UNICAST_DISABLED
4715 // Retrigger all our uDNS questions
4716 if (m
->CurrentQuestion
)
4717 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4718 m
->CurrentQuestion
= m
->Questions
;
4719 while (m
->CurrentQuestion
)
4721 q
= m
->CurrentQuestion
;
4722 m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
4723 if (!mDNSOpaque16IsZero(q
->TargetQID
)) ActivateUnicastQuery(m
, q
, mDNStrue
);
4727 // Retrigger all our mDNS questions
4728 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
4729 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
))
4731 q
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
4732 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
4733 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4734 q
->RecentAnswerPkts
= 0;
4735 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
);
4736 m
->NextScheduledQuery
= m
->timenow
;
4740 // ***************************************************************************
4741 #if COMPILER_LIKES_PRAGMA_MARK
4743 #pragma mark - Power Management (Sleep/Wake)
4746 mDNSlocal
void SendSPSRegistration(mDNS
*const m
, NetworkInterfaceInfo
*intf
, const mDNSOpaque16 id
)
4748 const int ownerspace
= mDNSSameEthAddress(&m
->PrimaryMAC
, &intf
->MAC
) ? DNSOpt_OwnerData_ID_Space
: DNSOpt_OwnerData_ID_Wake_Space
;
4749 const int optspace
= DNSOpt_Header_Space
+ DNSOpt_LeaseData_Space
+ ownerspace
;
4750 const int sps
= intf
->NextSPSAttempt
/ 3;
4753 if (!intf
->SPSAddr
[sps
].type
)
4755 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
4756 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
4757 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
4758 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf
->ifname
, intf
->NextSPSAttempt
, sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4762 // Mark our mDNS records (not unicast records) for transfer to SPS
4763 if (mDNSOpaque16IsZero(id
))
4764 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4765 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4766 if (rr
->resrec
.InterfaceID
== intf
->InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
4767 rr
->SendRNow
= mDNSInterfaceMark
; // mark it now
4771 mDNSu8
*p
= m
->omsg
.data
;
4772 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4773 // For now we follow that same logic for SPS registrations too.
4774 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4775 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4776 InitializeDNSMessage(&m
->omsg
.h
, mDNSOpaque16IsZero(id
) ? mDNS_NewMessageID(m
) : id
, UpdateReqFlags
);
4778 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4779 if (rr
->SendRNow
|| (!mDNSOpaque16IsZero(id
) && !AuthRecord_uDNS(rr
) && mDNSSameOpaque16(rr
->updateid
, id
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0))
4782 const mDNSu8
*const limit
= m
->omsg
.data
+ (m
->omsg
.h
.mDNS_numUpdates
? NormalMaxDNSMessageData
: AbsoluteMaxDNSMessageData
) - optspace
;
4783 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
4784 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
4785 newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
4786 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
4788 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf
->ifname
, p
- m
->omsg
.data
, limit
- m
->omsg
.data
, ARDisplayString(m
, rr
));
4791 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, rr
));
4792 rr
->SendRNow
= mDNSNULL
;
4793 rr
->ThisAPInterval
= mDNSPlatformOneSecond
;
4794 rr
->LastAPTime
= m
->timenow
;
4795 rr
->updateid
= m
->omsg
.h
.id
;
4796 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4797 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4802 if (!m
->omsg
.h
.mDNS_numUpdates
) break;
4806 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
4807 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
4808 opt
.resrec
.rdlength
= sizeof(rdataOPT
) * 2; // Two options in this OPT record
4809 opt
.resrec
.rdestimate
= sizeof(rdataOPT
) * 2;
4810 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
4811 opt
.resrec
.rdata
->u
.opt
[0].optlen
= DNSOpt_LeaseData_Space
- 4;
4812 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= DEFAULT_UPDATE_LEASE
;
4813 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[1]);
4814 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, &opt
));
4815 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
4817 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m
->omsg
.h
.mDNS_numUpdates
, ARDisplayString(m
, &opt
));
4821 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf
->ifname
, intf
->NextSPSAttempt
, sps
,
4822 mDNSVal16(m
->omsg
.h
.id
), m
->omsg
.h
.mDNS_numUpdates
, p
- m
->omsg
.data
, &intf
->SPSAddr
[sps
], mDNSVal16(intf
->SPSPort
[sps
]));
4823 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
4824 err
= mDNSSendDNSMessage(m
, &m
->omsg
, p
, intf
->InterfaceID
, mDNSNULL
, &intf
->SPSAddr
[sps
], intf
->SPSPort
[sps
], mDNSNULL
, mDNSNULL
);
4825 if (err
) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err
);
4826 if (err
&& intf
->SPSAddr
[sps
].type
== mDNSAddrType_IPv6
&& intf
->NetWakeResolve
[sps
].ThisQInterval
== -1)
4828 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4829 intf
->NetWakeResolve
[sps
].qtype
= kDNSType_A
;
4830 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[sps
]);
4837 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
* 10; // If successful, update NextSPSAttemptTime
4840 if (mDNSOpaque16IsZero(id
) && intf
->NextSPSAttempt
< 8) intf
->NextSPSAttempt
++;
4843 // RetrySPSRegistrations is called from SendResponses, with the lock held
4844 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
)
4847 NetworkInterfaceInfo
*intf
;
4849 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4850 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4851 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10)
4852 intf
->NextSPSAttemptTime
++;
4854 // Retry any record registrations that are due
4855 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4856 if (!AuthRecord_uDNS(rr
) && !mDNSOpaque16IsZero(rr
->updateid
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4857 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4858 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== intf
->InterfaceID
)
4860 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m
, rr
));
4861 SendSPSRegistration(m
, intf
, rr
->updateid
);
4864 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4865 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4866 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10 && intf
->NextSPSAttempt
< 8)
4867 intf
->NextSPSAttempt
++;
4870 mDNSlocal
void NetWakeResolve(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4872 NetworkInterfaceInfo
*intf
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
4873 int sps
= question
- intf
->NetWakeResolve
;
4875 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps
, AddRecord
, RRDisplayString(m
, answer
));
4877 if (!AddRecord
) return; // Don't care about REMOVE events
4878 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
4880 mDNS_StopQuery(m
, question
);
4881 question
->ThisQInterval
= -1;
4883 if (answer
->rrtype
== kDNSType_SRV
)
4885 intf
->SPSPort
[sps
] = answer
->rdata
->u
.srv
.port
;
4886 AssignDomainName(&question
->qname
, &answer
->rdata
->u
.srv
.target
);
4887 question
->qtype
= kDNSType_AAAA
;
4888 mDNS_StartQuery(m
, question
);
4890 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== sizeof(mDNSv6Addr
) && mDNSv6AddressIsLinkLocal(&answer
->rdata
->u
.ipv6
))
4892 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv6
;
4893 intf
->SPSAddr
[sps
].ip
.v6
= answer
->rdata
->u
.ipv6
;
4895 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4898 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== 0) // If negative answer for IPv6, look for IPv4 addresses instead
4900 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps
, question
->qname
.c
);
4901 question
->qtype
= kDNSType_A
;
4902 mDNS_StartQuery(m
, question
);
4904 else if (answer
->rrtype
== kDNSType_A
&& answer
->rdlength
== sizeof(mDNSv4Addr
))
4906 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv4
;
4907 intf
->SPSAddr
[sps
].ip
.v4
= answer
->rdata
->u
.ipv4
;
4909 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4914 mDNSexport mDNSBool
mDNSCoreHaveAdvertisedMulticastServices(mDNS
*const m
)
4917 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4918 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& !AuthRecord_uDNS(rr
) && !mDNSSameIPPort(rr
->resrec
.rdata
->u
.srv
.port
, DiscardPort
))
4923 // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
4924 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
)
4926 const CacheRecord
*sps
[3] = { mDNSNULL
};
4928 m
->NextScheduledSPRetry
= m
->timenow
;
4930 if (!m
->SystemWakeOnLANEnabled
) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
4931 else if (!mDNSCoreHaveAdvertisedMulticastServices(m
)) LogSPS("BeginSleepProcessing: No advertised services");
4932 else // If we have at least one advertised service
4934 NetworkInterfaceInfo
*intf
;
4935 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4937 if (!intf
->NetWake
) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf
->ifname
);
4940 FindSPSInCache(m
, &intf
->NetWakeBrowse
, sps
);
4941 if (!sps
[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf
->ifname
, &intf
->ip
, intf
->NetWakeBrowse
.ThisQInterval
);
4945 intf
->NextSPSAttempt
= 0;
4946 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
4947 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
4951 if (intf
->SPSAddr
[i
].type
)
4952 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf
->ifname
, i
, intf
->SPSAddr
[i
].type
); *(long*)0 = 0; }
4953 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0)
4954 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf
->ifname
, i
, intf
->NetWakeResolve
[i
].ThisQInterval
); *(long*)0 = 0; }
4956 intf
->SPSAddr
[i
].type
= mDNSAddrType_None
;
4957 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery(m
, &intf
->NetWakeResolve
[i
]);
4958 intf
->NetWakeResolve
[i
].ThisQInterval
= -1;
4961 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf
->ifname
, i
, sps
[i
]->resrec
.rroriginalttl
, CRDisplayString(m
, sps
[i
]));
4962 mDNS_SetupQuestion(&intf
->NetWakeResolve
[i
], intf
->InterfaceID
, &sps
[i
]->resrec
.rdata
->u
.name
, kDNSType_SRV
, NetWakeResolve
, intf
);
4963 intf
->NetWakeResolve
[i
].ReturnIntermed
= mDNStrue
;
4964 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[i
]);
4972 if (!sps
[0]) // If we didn't find even one Sleep Proxy
4975 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
4976 m
->SleepState
= SleepState_Sleeping
;
4978 #ifndef UNICAST_DISABLED
4979 SleepServiceRegistrations(m
);
4980 SleepRecordRegistrations(m
); // If we have no SPS, need to deregister our uDNS records
4983 // Mark all the records we need to deregister and send them
4984 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4985 if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->RequireGoodbye
)
4986 rr
->ImmedAnswer
= mDNSInterfaceMark
;
4991 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
4992 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
4993 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
4994 mDNSexport
void mDNSCoreMachineSleep(mDNS
*const m
, mDNSBool sleep
)
5000 LogSPS("%s (old state %d) at %ld", sleep
? "Sleeping" : "Waking", m
->SleepState
, m
->timenow
);
5002 if (sleep
&& !m
->SleepState
) // Going to sleep
5004 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5007 mDNSu8 oldstate
= m
->SPSState
;
5008 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5010 if (oldstate
== 1) mDNS_DeregisterService(m
, &m
->SPSRecords
);
5011 mDNS_ReclaimLockAfterCallback();
5014 m
->SleepState
= SleepState_Transferring
;
5015 if (m
->SystemWakeOnLANEnabled
&& m
->DelaySleep
)
5017 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5018 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m
->DelaySleep
- m
->timenow
);
5019 m
->SleepLimit
= m
->DelaySleep
+ mDNSPlatformOneSecond
* 10;
5024 m
->SleepLimit
= m
->timenow
+ mDNSPlatformOneSecond
* 10;
5025 BeginSleepProcessing(m
);
5028 #ifndef UNICAST_DISABLED
5031 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m
->SleepState
,
5032 m
->SleepState
== SleepState_Transferring
? "Transferring" :
5033 m
->SleepState
== SleepState_Sleeping
? "Sleeping" : "?", m
->SleepSeqNum
);
5035 else if (!sleep
) // Waking up
5040 NetworkInterfaceInfo
*intf
;
5042 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5043 if (m
->SleepState
!= SleepState_Awake
)
5045 m
->SleepState
= SleepState_Awake
;
5047 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5048 // then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5049 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5050 // before we make our determination of whether there's a Sleep Proxy out there we should register with.
5051 m
->DelaySleep
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 16);
5054 if (m
->SPSState
== 3)
5056 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5058 mDNSCoreBeSleepProxyServer(m
, m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
);
5059 mDNS_ReclaimLockAfterCallback();
5062 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5063 // on wake we go through our record list and clear updateid back to zero
5064 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) rr
->updateid
= zeroID
;
5066 // ... and the same for NextSPSAttempt
5067 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
)) intf
->NextSPSAttempt
= -1;
5069 // Restart unicast and multicast queries
5070 mDNSCoreRestartQueries(m
);
5072 // and reactivtate service registrations
5073 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5074 LogInfo("WakeServiceRegistrations %d %d", m
->timenow
, m
->NextSRVUpdate
);
5076 // 2. Re-validate our cache records
5077 m
->NextCacheCheck
= m
->timenow
;
5078 FORALL_CACHERECORDS(slot
, cg
, cr
)
5079 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForWake
);
5081 // 3. Retrigger probing and announcing for all our authoritative records
5082 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5083 if (AuthRecord_uDNS(rr
))
5085 ActivateUnicastRegistration(m
, rr
);
5089 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
5090 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
5091 rr
->AnnounceCount
= InitialAnnounceCount
;
5092 InitializeLastAPTime(m
, rr
);
5095 // 4. Refresh NAT mappings
5096 // We don't want to have to assume that all hardware can necessarily keep accurate
5097 // track of passage of time while asleep, so on wake we refresh our NAT mappings
5098 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
5099 m
->retryGetAddr
= m
->timenow
;
5100 RecreateNATMappings(m
);
5106 mDNSexport mDNSBool
mDNSCoreReadyForSleep(mDNS
*m
)
5110 ServiceRecordSet
*srs
;
5111 NetworkInterfaceInfo
*intf
;
5115 if (m
->NextScheduledSPRetry
- m
->timenow
> 0) goto notready
;
5117 m
->NextScheduledSPRetry
= m
->timenow
+ 0x40000000UL
;
5119 if (m
->DelaySleep
) goto notready
;
5121 // See if we might need to retransmit any lost Sleep Proxy Registrations
5122 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5123 if (intf
->NextSPSAttempt
>= 0)
5125 if (m
->timenow
- intf
->NextSPSAttemptTime
>= 0)
5127 LogSPS("ReadyForSleep retrying SPS %s %d", intf
->ifname
, intf
->NextSPSAttempt
);
5128 SendSPSRegistration(m
, intf
, zeroID
);
5131 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
5132 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
5135 // Scan list of private LLQs, and make sure they've all completed their handshake with the server
5136 for (q
= m
->Questions
; q
; q
= q
->next
)
5137 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->ReqLease
== 0 && q
->tcp
)
5139 LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5143 // Scan list of interfaces
5144 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5145 if (intf
->NetWakeResolve
[0].ThisQInterval
>= 0)
5147 LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf
->ifname
, intf
->NetWakeResolve
[0].qname
.c
, DNSTypeName(intf
->NetWakeResolve
[0].qtype
));
5151 // Scan list of registered records
5152 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5154 if (AuthRecord_uDNS(rr
))
5156 if (rr
->state
== regState_Refresh
&& rr
->tcp
)
5157 { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto notready
; }
5161 if (!mDNSOpaque16IsZero(rr
->updateid
))
5162 { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto notready
; }
5166 // Scan list of registered services
5167 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
5168 if (srs
->state
== regState_NoTarget
&& srs
->tcp
) goto notready
;
5178 mDNSexport mDNSs32
mDNSCoreIntervalToNextWake(mDNS
*const m
, mDNSs32 now
)
5182 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5183 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5184 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5185 // and if that happens we don't want to just give up and go back to sleep and never try again.
5186 mDNSs32 e
= now
+ (120 * 60 * mDNSPlatformOneSecond
); // Sleep for at most 120 minutes
5188 NATTraversalInfo
*nat
;
5189 for (nat
= m
->NATTraversals
; nat
; nat
=nat
->next
)
5190 if (nat
->Protocol
&& nat
->ExpiryTime
&& nat
->ExpiryTime
- now
> mDNSPlatformOneSecond
*4)
5192 mDNSs32 t
= nat
->ExpiryTime
- (nat
->ExpiryTime
- now
) / 10; // Wake up when 90% of the way to the expiry time
5193 if (e
- t
> 0) e
= t
;
5194 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5195 nat
, nat
->Protocol
== NATOp_MapTCP
? "TCP" : "UDP",
5196 mDNSVal16(nat
->IntPort
), mDNSVal16(nat
->ExternalPort
), nat
->Result
,
5197 nat
->retryPortMap
? (nat
->retryPortMap
- now
) / mDNSPlatformOneSecond
: 0,
5198 nat
->retryInterval
/ mDNSPlatformOneSecond
,
5199 nat
->ExpiryTime
? (nat
->ExpiryTime
- now
) / mDNSPlatformOneSecond
: 0,
5200 (t
- now
) / mDNSPlatformOneSecond
);
5203 // This loop checks both the time we need to renew wide-area registrations,
5204 // and the time we need to renew Sleep Proxy registrations
5205 for (ar
= m
->ResourceRecords
; ar
; ar
= ar
->next
)
5206 if (ar
->expire
&& ar
->expire
- now
> mDNSPlatformOneSecond
*4)
5208 mDNSs32 t
= ar
->expire
- (ar
->expire
- now
) / 10; // Wake up when 90% of the way to the expiry time
5209 if (e
- t
> 0) e
= t
;
5210 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5211 ar
, ar
->ThisAPInterval
/ mDNSPlatformOneSecond
,
5212 (ar
->LastAPTime
+ ar
->ThisAPInterval
- now
) / mDNSPlatformOneSecond
,
5213 ar
->expire
? (ar
->expire
- now
) / mDNSPlatformOneSecond
: 0,
5214 (t
- now
) / mDNSPlatformOneSecond
, ARDisplayString(m
, ar
));
5220 // ***************************************************************************
5221 #if COMPILER_LIKES_PRAGMA_MARK
5223 #pragma mark - Packet Reception Functions
5226 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5228 mDNSlocal mDNSu8
*GenerateUnicastResponse(const DNSMessage
*const query
, const mDNSu8
*const end
,
5229 const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, DNSMessage
*const response
, AuthRecord
*ResponseRecords
)
5231 mDNSu8
*responseptr
= response
->data
;
5232 const mDNSu8
*const limit
= response
->data
+ sizeof(response
->data
);
5233 const mDNSu8
*ptr
= query
->data
;
5235 mDNSu32 maxttl
= 0x70000000;
5238 // Initialize the response fields so we can answer the questions
5239 InitializeDNSMessage(&response
->h
, query
->h
.id
, ResponseFlags
);
5242 // *** 1. Write out the list of questions we are actually going to answer with this packet
5247 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5250 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &q
); // get the question...
5251 if (!ptr
) return(mDNSNULL
);
5253 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // and search our list of proposed answers
5255 if (rr
->NR_AnswerTo
== ptr
) // If we're going to generate a record answering this question
5256 { // then put the question in the question section
5257 responseptr
= putQuestion(response
, responseptr
, limit
, &q
.qname
, q
.qtype
, q
.qclass
);
5258 if (!responseptr
) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL
); }
5259 break; // break out of the ResponseRecords loop, and go on to the next question
5264 if (response
->h
.numQuestions
== 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL
); }
5268 // *** 2. Write Answers
5270 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5271 if (rr
->NR_AnswerTo
)
5273 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAnswers
, &rr
->resrec
,
5274 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5275 if (p
) responseptr
= p
;
5276 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response
->h
.flags
.b
[0] |= kDNSFlag0_TC
; }
5280 // *** 3. Write Additionals
5282 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5283 if (rr
->NR_AdditionalTo
&& !rr
->NR_AnswerTo
)
5285 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAdditionals
, &rr
->resrec
,
5286 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5287 if (p
) responseptr
= p
;
5288 else debugf("GenerateUnicastResponse: No more space for additionals");
5291 return(responseptr
);
5294 // AuthRecord *our is our Resource Record
5295 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5296 // Returns 0 if there is no conflict
5297 // Returns +1 if there was a conflict and we won
5298 // Returns -1 if there was a conflict and we lost and have to rename
5299 mDNSlocal
int CompareRData(const AuthRecord
*const our
, const CacheRecord
*const pkt
)
5301 mDNSu8 ourdata
[256], *ourptr
= ourdata
, *ourend
;
5302 mDNSu8 pktdata
[256], *pktptr
= pktdata
, *pktend
;
5303 if (!our
) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5304 if (!pkt
) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5306 ourend
= putRData(mDNSNULL
, ourdata
, ourdata
+ sizeof(ourdata
), &our
->resrec
);
5307 pktend
= putRData(mDNSNULL
, pktdata
, pktdata
+ sizeof(pktdata
), &pkt
->resrec
);
5308 while (ourptr
< ourend
&& pktptr
< pktend
&& *ourptr
== *pktptr
) { ourptr
++; pktptr
++; }
5309 if (ourptr
>= ourend
&& pktptr
>= pktend
) return(0); // If data identical, not a conflict
5311 if (ourptr
>= ourend
) return(-1); // Our data ran out first; We lost
5312 if (pktptr
>= pktend
) return(+1); // Packet data ran out first; We won
5313 if (*pktptr
> *ourptr
) return(-1); // Our data is numerically lower; We lost
5314 if (*pktptr
< *ourptr
) return(+1); // Packet data is numerically lower; We won
5316 LogMsg("CompareRData ERROR: Invalid state");
5320 // See if we have an authoritative record that's identical to this packet record,
5321 // whose canonical DependentOn record is the specified master record.
5322 // The DependentOn pointer is typically used for the TXT record of service registrations
5323 // It indicates that there is no inherent conflict detection for the TXT record
5324 // -- it depends on the SRV record to resolve name conflicts
5325 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
5326 // pointer chain (if any) to make sure we reach the canonical DependentOn record
5327 // If the record has no DependentOn, then just return that record's pointer
5328 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5329 mDNSlocal mDNSBool
MatchDependentOn(const mDNS
*const m
, const CacheRecord
*const pktrr
, const AuthRecord
*const master
)
5331 const AuthRecord
*r1
;
5332 for (r1
= m
->ResourceRecords
; r1
; r1
=r1
->next
)
5334 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5336 const AuthRecord
*r2
= r1
;
5337 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5338 if (r2
== master
) return(mDNStrue
);
5341 for (r1
= m
->DuplicateRecords
; r1
; r1
=r1
->next
)
5343 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5345 const AuthRecord
*r2
= r1
;
5346 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5347 if (r2
== master
) return(mDNStrue
);
5353 // Find the canonical RRSet pointer for this RR received in a packet.
5354 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
5355 // pointers (if any) to make sure we return the canonical member of this name/type/class
5356 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5357 mDNSlocal
const AuthRecord
*FindRRSet(const mDNS
*const m
, const CacheRecord
*const pktrr
)
5359 const AuthRecord
*rr
;
5360 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5362 if (IdenticalResourceRecord(&rr
->resrec
, &pktrr
->resrec
))
5364 while (rr
->RRSet
&& rr
!= rr
->RRSet
) rr
= rr
->RRSet
;
5371 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
5372 // as one of our records (our) but different rdata.
5373 // 1. If our record is not a type that's supposed to be unique, we don't care.
5374 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
5375 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
5376 // points to our record, ignore this conflict (e.g. the packet record matches one of our
5377 // TXT records, and that record is marked as dependent on 'our', its SRV record).
5378 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
5379 // are members of the same RRSet, then this is not a conflict.
5380 mDNSlocal mDNSBool
PacketRRConflict(const mDNS
*const m
, const AuthRecord
*const our
, const CacheRecord
*const pktrr
)
5382 // If not supposed to be unique, not a conflict
5383 if (!(our
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)) return(mDNSfalse
);
5385 // If a dependent record, not a conflict
5386 if (our
->DependentOn
|| MatchDependentOn(m
, pktrr
, our
)) return(mDNSfalse
);
5389 // If the pktrr matches a member of ourset, not a conflict
5390 const AuthRecord
*ourset
= our
->RRSet
? our
->RRSet
: our
;
5391 const AuthRecord
*pktset
= FindRRSet(m
, pktrr
);
5392 if (pktset
== ourset
) return(mDNSfalse
);
5394 // For records we're proxying, where we don't know the full
5395 // relationship between the records, having any matching record
5396 // in our AuthRecords list is sufficient evidence of non-conflict
5397 if (our
->WakeUp
.HMAC
.l
[0] && pktset
) return(mDNSfalse
);
5400 // Okay, this is a conflict
5404 // Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
5405 // the record list and/or question list.
5406 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5407 mDNSlocal
void ResolveSimultaneousProbe(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5408 DNSQuestion
*q
, AuthRecord
*our
)
5411 const mDNSu8
*ptr
= LocateAuthorities(query
, end
);
5412 mDNSBool FoundUpdate
= mDNSfalse
;
5414 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
5416 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
5418 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5420 FoundUpdate
= mDNStrue
;
5421 if (PacketRRConflict(m
, our
, &m
->rec
.r
))
5423 int result
= (int)our
->resrec
.rrclass
- (int)m
->rec
.r
.resrec
.rrclass
;
5424 if (!result
) result
= (int)our
->resrec
.rrtype
- (int)m
->rec
.r
.resrec
.rrtype
;
5425 if (!result
) result
= CompareRData(our
, &m
->rec
.r
);
5428 const char *const msg
= (result
< 0) ? "lost:" : (result
> 0) ? "won: " : "tie: ";
5429 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5430 LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our
->ProbeCount
, msg
, our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5432 // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network.
5433 // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
5434 // If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
5437 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5438 our
->ProbeCount
= DefaultProbeCountForTypeUnique
;
5439 our
->AnnounceCount
= InitialAnnounceCount
;
5440 InitializeLastAPTime(m
, our
);
5447 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5448 LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5452 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5455 LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
5457 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5460 mDNSlocal CacheRecord
*FindIdenticalRecordInCache(const mDNS
*const m
, const ResourceRecord
*const pktrr
)
5462 mDNSu32 slot
= HashSlot(pktrr
->name
);
5463 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, pktrr
);
5465 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5466 if (pktrr
->InterfaceID
== rr
->resrec
.InterfaceID
&& IdenticalSameNameRecord(pktrr
, &rr
->resrec
)) break;
5470 // Called from ProcessQuery when we get an mDNS packet with an owner record in it
5471 mDNSlocal
void ClearProxyRecords(mDNS
*const m
, const OwnerOptData
*const owner
, AuthRecord
*const thelist
)
5473 m
->CurrentRecord
= thelist
;
5474 while (m
->CurrentRecord
)
5476 AuthRecord
*const rr
= m
->CurrentRecord
;
5477 if (m
->rec
.r
.resrec
.InterfaceID
== rr
->resrec
.InterfaceID
&& mDNSSameEthAddress(&owner
->HMAC
, &rr
->WakeUp
.HMAC
))
5478 if (owner
->seq
!= rr
->WakeUp
.seq
|| m
->timenow
- rr
->TimeRcvd
> mDNSPlatformOneSecond
* 60)
5480 LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
5481 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, owner
->seq
, ARDisplayString(m
, rr
));
5482 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
5483 SetSPSProxyListChanged(m
->rec
.r
.resrec
.InterfaceID
);
5485 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
5486 // because the list may have been changed in that call.
5487 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
5488 m
->CurrentRecord
= rr
->next
;
5492 // ProcessQuery examines a received query to see if we have any answers to give
5493 mDNSlocal mDNSu8
*ProcessQuery(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5494 const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, mDNSBool QueryWasMulticast
,
5495 mDNSBool QueryWasLocalUnicast
, DNSMessage
*const response
)
5497 mDNSBool FromLocalSubnet
= srcaddr
&& AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
5498 AuthRecord
*ResponseRecords
= mDNSNULL
;
5499 AuthRecord
**nrp
= &ResponseRecords
;
5500 CacheRecord
*ExpectedAnswers
= mDNSNULL
; // Records in our cache we expect to see updated
5501 CacheRecord
**eap
= &ExpectedAnswers
;
5502 DNSQuestion
*DupQuestions
= mDNSNULL
; // Our questions that are identical to questions in this packet
5503 DNSQuestion
**dqp
= &DupQuestions
;
5504 mDNSs32 delayresponse
= 0;
5505 mDNSBool SendLegacyResponse
= mDNSfalse
;
5507 mDNSu8
*responseptr
= mDNSNULL
;
5512 // *** 1. Look in Additional Section for an OPT record
5514 ptr
= LocateOptRR(query
, end
, DNSOpt_OwnerData_ID_Space
);
5517 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &m
->rec
);
5518 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
5520 const rdataOPT
*opt
;
5521 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
5522 // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
5523 // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
5524 for (opt
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; opt
< e
; opt
++)
5525 if (opt
->opt
== kDNSOpt_Owner
&& opt
->u
.owner
.vers
== 0 && opt
->u
.owner
.HMAC
.l
[0])
5527 ClearProxyRecords(m
, &opt
->u
.owner
, m
->DuplicateRecords
);
5528 ClearProxyRecords(m
, &opt
->u
.owner
, m
->ResourceRecords
);
5531 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5535 // *** 2. Parse Question Section and mark potential answers
5538 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5540 mDNSBool QuestionNeedsMulticastResponse
;
5541 int NumAnswersForThisQuestion
= 0;
5542 AuthRecord
*NSECAnswer
= mDNSNULL
;
5543 DNSQuestion pktq
, *q
;
5544 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &pktq
); // get the question...
5545 if (!ptr
) goto exit
;
5547 // The only queries that *need* a multicast response are:
5548 // * Queries sent via multicast
5550 // * that don't have the kDNSQClass_UnicastResponse bit set
5551 // These queries need multicast responses because other clients will:
5552 // * suppress their own identical questions when they see these questions, and
5553 // * expire their cache records if they don't see the expected responses
5554 // For other queries, we may still choose to send the occasional multicast response anyway,
5555 // to keep our neighbours caches warm, and for ongoing conflict detection.
5556 QuestionNeedsMulticastResponse
= QueryWasMulticast
&& !LegacyQuery
&& !(pktq
.qclass
& kDNSQClass_UnicastResponse
);
5557 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
5558 pktq
.qclass
&= ~kDNSQClass_UnicastResponse
;
5560 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
5561 // can result in user callbacks which may change the record list and/or question list.
5562 // Also note: we just mark potential answer records here, without trying to build the
5563 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
5564 // from that list while we're in the middle of trying to build it.
5565 if (m
->CurrentRecord
)
5566 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
5567 m
->CurrentRecord
= m
->ResourceRecords
;
5568 while (m
->CurrentRecord
)
5570 rr
= m
->CurrentRecord
;
5571 m
->CurrentRecord
= rr
->next
;
5572 if (AnyTypeRecordAnswersQuestion(&rr
->resrec
, &pktq
) && (QueryWasMulticast
|| QueryWasLocalUnicast
|| rr
->AllowRemoteQuery
))
5574 if (RRTypeAnswersQuestionType(&rr
->resrec
, pktq
.qtype
))
5576 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
5577 ResolveSimultaneousProbe(m
, query
, end
, &pktq
, rr
);
5578 else if (ResourceRecordIsValidAnswer(rr
))
5580 NumAnswersForThisQuestion
++;
5581 // Note: We should check here if this is a probe-type query, and if so, generate an immediate
5582 // unicast answer back to the source, because timeliness in answering probes is important.
5585 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
5586 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
5587 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
5588 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
5589 // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
5590 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
5591 if (QuestionNeedsMulticastResponse
|| (!FromLocalSubnet
&& QueryWasMulticast
&& !LegacyQuery
))
5593 // We only mark this question for sending if it is at least one second since the last time we multicast it
5594 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
5595 // This is to guard against the case where someone blasts us with queries as fast as they can.
5596 if (m
->timenow
- (rr
->LastMCTime
+ mDNSPlatformOneSecond
) >= 0 ||
5597 (rr
->LastMCInterface
!= mDNSInterfaceMark
&& rr
->LastMCInterface
!= InterfaceID
))
5598 rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5600 else if (!rr
->NR_AnswerTo
) rr
->NR_AnswerTo
= LegacyQuery
? ptr
: (mDNSu8
*)~1;
5603 else if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
5605 // If we don't have any answers for this question, but we do own another record with the same name,
5606 // then mark it to generate an NSEC record on this interface
5607 if (!NSECAnswer
) NSECAnswer
= rr
;
5612 if (NumAnswersForThisQuestion
== 0 && NSECAnswer
)
5614 NumAnswersForThisQuestion
++;
5615 NSECAnswer
->SendNSECNow
= InterfaceID
;
5616 m
->NextScheduledResponse
= m
->timenow
;
5619 // If we couldn't answer this question, someone else might be able to,
5620 // so use random delay on response to reduce collisions
5621 if (NumAnswersForThisQuestion
== 0) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5623 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5624 if (QuestionNeedsMulticastResponse
)
5626 // We only do the following accelerated cache expiration and duplicate question suppression processing
5627 // for non-truncated multicast queries with multicast responses.
5628 // For any query generating a unicast response we don't do this because we can't assume we will see the response.
5629 // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
5630 // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
5631 if (QuestionNeedsMulticastResponse
&& !(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5634 const mDNSu32 slot
= HashSlot(&pktq
.qname
);
5635 CacheGroup
*cg
= CacheGroupForName(m
, slot
, pktq
.qnamehash
, &pktq
.qname
);
5638 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
5639 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5640 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5641 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5643 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
5644 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &pktq
) && cr
->resrec
.rdlength
<= SmallRecordLimit
)
5645 if (!cr
->NextInKAList
&& eap
!= &cr
->NextInKAList
)
5648 eap
= &cr
->NextInKAList
;
5649 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5650 if (cr
->MPUnansweredQ
== 0 || m
->timenow
- cr
->MPLastUnansweredQT
>= mDNSPlatformOneSecond
)
5652 // Although MPUnansweredQ is only really used for multi-packet query processing,
5653 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
5654 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
5655 cr
->MPUnansweredQ
++;
5656 cr
->MPLastUnansweredQT
= m
->timenow
;
5657 cr
->MPExpectingKA
= mDNStrue
;
5662 // Check if this question is the same as any of mine.
5663 // We only do this for non-truncated queries. Right now it would be too complicated to try
5664 // to keep track of duplicate suppression state between multiple packets, especially when we
5665 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
5666 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5667 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5669 for (q
= m
->Questions
; q
; q
=q
->next
)
5670 if (!q
->Target
.type
&& ActiveQuestion(q
) && m
->timenow
- q
->LastQTxTime
> mDNSPlatformOneSecond
/ 4)
5671 if (!q
->InterfaceID
|| q
->InterfaceID
== InterfaceID
)
5672 if (q
->NextInDQList
== mDNSNULL
&& dqp
!= &q
->NextInDQList
)
5673 if (q
->qtype
== pktq
.qtype
&&
5674 q
->qclass
== pktq
.qclass
&&
5675 q
->qnamehash
== pktq
.qnamehash
&& SameDomainName(&q
->qname
, &pktq
.qname
))
5676 { *dqp
= q
; dqp
= &q
->NextInDQList
; }
5681 // *** 3. Now we can safely build the list of marked answers
5683 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) // Now build our list of potential answers
5684 if (rr
->NR_AnswerTo
) // If we marked the record...
5685 AddRecordToResponseList(&nrp
, rr
, mDNSNULL
); // ... add it to the list
5688 // *** 4. Add additional records
5690 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
5693 // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
5695 for (i
=0; i
<query
->h
.numAnswers
; i
++) // For each record in the query's answer section...
5697 // Get the record...
5698 CacheRecord
*ourcacherr
;
5699 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &m
->rec
);
5700 if (!ptr
) goto exit
;
5702 // See if this Known-Answer suppresses any of our currently planned answers
5703 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5704 if (MustSendRecord(rr
) && ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5705 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5707 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5708 for (rr
=m
->ResourceRecords
; rr
; rr
=rr
->next
)
5710 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5711 if (rr
->ImmedAnswer
== InterfaceID
&& ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5713 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5715 if (mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= zerov4Addr
;
5717 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5719 if (mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= zerov6Addr
;
5721 if (mDNSIPv4AddressIsZero(rr
->v4Requester
) && mDNSIPv6AddressIsZero(rr
->v6Requester
))
5723 rr
->ImmedAnswer
= mDNSNULL
;
5724 rr
->ImmedUnicast
= mDNSfalse
;
5725 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5726 LogMsg("Suppressed after%4d: %s", m
->timenow
- rr
->ImmedAnswerMarkTime
, ARDisplayString(m
, rr
));
5732 ourcacherr
= FindIdenticalRecordInCache(m
, &m
->rec
.r
.resrec
);
5734 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5735 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5736 // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
5737 if (ourcacherr
&& ourcacherr
->MPExpectingKA
&& m
->timenow
- ourcacherr
->MPLastUnansweredQT
< mDNSPlatformOneSecond
)
5739 ourcacherr
->MPUnansweredKA
++;
5740 ourcacherr
->MPExpectingKA
= mDNSfalse
;
5744 // Having built our ExpectedAnswers list from the questions in this packet, we then remove
5745 // any records that are suppressed by the Known Answer list in this packet.
5746 eap
= &ExpectedAnswers
;
5749 CacheRecord
*cr
= *eap
;
5750 if (cr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalResourceRecord(&m
->rec
.r
.resrec
, &cr
->resrec
))
5751 { *eap
= cr
->NextInKAList
; cr
->NextInKAList
= mDNSNULL
; }
5752 else eap
= &cr
->NextInKAList
;
5755 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5758 dqp
= &DupQuestions
;
5761 DNSQuestion
*q
= *dqp
;
5762 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5763 { *dqp
= q
->NextInDQList
; q
->NextInDQList
= mDNSNULL
; }
5764 else dqp
= &q
->NextInDQList
;
5767 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5771 // *** 6. Cancel any additionals that were added because of now-deleted records
5773 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5774 if (rr
->NR_AdditionalTo
&& !MustSendRecord(rr
->NR_AdditionalTo
))
5775 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5778 // *** 7. Mark the send flags on the records we plan to send
5780 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5782 if (rr
->NR_AnswerTo
)
5784 mDNSBool SendMulticastResponse
= mDNSfalse
; // Send modern multicast response
5785 mDNSBool SendUnicastResponse
= mDNSfalse
; // Send modern unicast response (not legacy unicast response)
5787 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5788 if (m
->timenow
- (rr
->LastMCTime
+ TicksTTL(rr
)/4) >= 0)
5790 SendMulticastResponse
= mDNStrue
;
5791 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5792 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5793 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5794 if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5797 // If the client insists on a multicast response, then we'd better send one
5798 if (rr
->NR_AnswerTo
== (mDNSu8
*)~0) SendMulticastResponse
= mDNStrue
;
5799 else if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) SendUnicastResponse
= mDNStrue
;
5800 else if (rr
->NR_AnswerTo
) SendLegacyResponse
= mDNStrue
;
5802 if (SendMulticastResponse
|| SendUnicastResponse
)
5804 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5805 rr
->ImmedAnswerMarkTime
= m
->timenow
;
5807 m
->NextScheduledResponse
= m
->timenow
;
5808 // If we're already planning to send this on another interface, just send it on all interfaces
5809 if (rr
->ImmedAnswer
&& rr
->ImmedAnswer
!= InterfaceID
)
5810 rr
->ImmedAnswer
= mDNSInterfaceMark
;
5813 rr
->ImmedAnswer
= InterfaceID
; // Record interface to send it on
5814 if (SendUnicastResponse
) rr
->ImmedUnicast
= mDNStrue
;
5815 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5817 if (mDNSIPv4AddressIsZero(rr
->v4Requester
)) rr
->v4Requester
= srcaddr
->ip
.v4
;
5818 else if (!mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= onesIPv4Addr
;
5820 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5822 if (mDNSIPv6AddressIsZero(rr
->v6Requester
)) rr
->v6Requester
= srcaddr
->ip
.v6
;
5823 else if (!mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= onesIPv6Addr
;
5827 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5828 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5829 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5830 // else, for a simple unique record reply, we can reply immediately; no need for delay
5831 if (query
->h
.flags
.b
[0] & kDNSFlag0_TC
) delayresponse
= mDNSPlatformOneSecond
* 20; // Divided by 50 = 400ms
5832 else if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5834 else if (rr
->NR_AdditionalTo
&& rr
->NR_AdditionalTo
->NR_AnswerTo
== (mDNSu8
*)~0)
5836 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
5837 // If two clients on different interfaces do queries that invoke the same optional additional answer,
5838 // then the earlier client is out of luck
5839 rr
->ImmedAdditional
= InterfaceID
;
5840 // No need to set m->NextScheduledResponse here
5841 // We'll send these additional records when we send them, or not, as the case may be
5846 // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
5848 if (delayresponse
&& (!m
->SuppressSending
|| (m
->SuppressSending
- m
->timenow
) < (delayresponse
+ 49) / 50))
5850 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5851 mDNSs32 oldss
= m
->SuppressSending
;
5852 if (oldss
&& delayresponse
)
5853 LogMsg("Current SuppressSending delay%5ld; require%5ld", m
->SuppressSending
- m
->timenow
, (delayresponse
+ 49) / 50);
5855 // Pick a random delay:
5856 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
5857 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5858 // This is an integer value, with resolution determined by the platform clock rate.
5859 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
5860 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5861 // The +49 before dividing is to ensure we round up, not down, to ensure that even
5862 // on platforms where the native clock rate is less than fifty ticks per second,
5863 // we still guarantee that the final calculated delay is at least one platform tick.
5864 // We want to make sure we don't ever allow the delay to be zero ticks,
5865 // because if that happens we'll fail the Bonjour Conformance Test.
5866 // Our final computed delay is 20-120ms for normal delayed replies,
5867 // or 400-500ms in the case of multi-packet known-answer lists.
5868 m
->SuppressSending
= m
->timenow
+ (delayresponse
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*5) + 49) / 50;
5869 if (m
->SuppressSending
== 0) m
->SuppressSending
= 1;
5870 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5871 if (oldss
&& delayresponse
)
5872 LogMsg("Set SuppressSending to %5ld", m
->SuppressSending
- m
->timenow
);
5877 // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5879 if (SendLegacyResponse
)
5880 responseptr
= GenerateUnicastResponse(query
, end
, InterfaceID
, LegacyQuery
, response
, ResponseRecords
);
5883 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5886 // *** 10. Finally, clear our link chains ready for use next time
5888 while (ResponseRecords
)
5890 rr
= ResponseRecords
;
5891 ResponseRecords
= rr
->NextResponse
;
5892 rr
->NextResponse
= mDNSNULL
;
5893 rr
->NR_AnswerTo
= mDNSNULL
;
5894 rr
->NR_AdditionalTo
= mDNSNULL
;
5897 while (ExpectedAnswers
)
5899 CacheRecord
*cr
= ExpectedAnswers
;
5900 ExpectedAnswers
= cr
->NextInKAList
;
5901 cr
->NextInKAList
= mDNSNULL
;
5903 // For non-truncated queries, we can definitively say that we should expect
5904 // to be seeing a response for any records still left in the ExpectedAnswers list
5905 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5906 if (cr
->UnansweredQueries
== 0 || m
->timenow
- cr
->LastUnansweredTime
>= mDNSPlatformOneSecond
)
5908 cr
->UnansweredQueries
++;
5909 cr
->LastUnansweredTime
= m
->timenow
;
5910 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5911 if (cr
->UnansweredQueries
> 1)
5912 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5913 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
5915 SetNextCacheCheckTime(m
, cr
);
5918 // If we've seen multiple unanswered queries for this record,
5919 // then mark it to expire in five seconds if we don't get a response by then.
5920 if (cr
->UnansweredQueries
>= MaxUnansweredQueries
)
5922 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5923 // Only show debugging message if this record was not about to expire anyway
5924 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
5925 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5926 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
5928 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
5930 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5931 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
5932 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
5933 // possible packet loss of up to 20% of the additional KA packets.)
5934 else if (cr
->MPUnansweredQ
* 4 > cr
->MPUnansweredKA
* 5 + 8)
5936 // We want to do this conservatively.
5937 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
5938 // then we don't want them to all hit the network simultaneously with their final expiration queries.
5939 // By setting the record to expire in four minutes, we achieve two things:
5940 // (a) the 90-95% final expiration queries will be less bunched together
5941 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
5942 mDNSu32 remain
= (mDNSu32
)(RRExpireTime(cr
) - m
->timenow
) / 4;
5943 if (remain
> 240 * (mDNSu32
)mDNSPlatformOneSecond
)
5944 remain
= 240 * (mDNSu32
)mDNSPlatformOneSecond
;
5946 // Only show debugging message if this record was not about to expire anyway
5947 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
5948 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5949 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
5951 if (remain
<= 60 * (mDNSu32
)mDNSPlatformOneSecond
)
5952 cr
->UnansweredQueries
++; // Treat this as equivalent to one definite unanswered query
5953 cr
->MPUnansweredQ
= 0; // Clear MPQ/MPKA statistics
5954 cr
->MPUnansweredKA
= 0;
5955 cr
->MPExpectingKA
= mDNSfalse
;
5957 if (remain
< kDefaultReconfirmTimeForNoAnswer
)
5958 remain
= kDefaultReconfirmTimeForNoAnswer
;
5959 mDNS_Reconfirm_internal(m
, cr
, remain
);
5964 while (DupQuestions
)
5966 DNSQuestion
*q
= DupQuestions
;
5967 DupQuestions
= q
->NextInDQList
;
5968 q
->NextInDQList
= mDNSNULL
;
5969 i
= RecordDupSuppressInfo(q
->DupSuppress
, m
->timenow
, InterfaceID
, srcaddr
->type
);
5970 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q
->qname
.c
, DNSTypeName(q
->qtype
), InterfaceID
,
5971 srcaddr
->type
== mDNSAddrType_IPv4
? "v4" : "v6", i
);
5974 return(responseptr
);
5977 mDNSlocal
void mDNSCoreReceiveQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
5978 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
5979 const mDNSInterfaceID InterfaceID
)
5981 mDNSu8
*responseend
= mDNSNULL
;
5982 mDNSBool QueryWasLocalUnicast
= srcaddr
&& dstaddr
&&
5983 !mDNSAddrIsDNSMulticast(dstaddr
) && AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
5985 if (!InterfaceID
&& dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
))
5987 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5988 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
5989 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
5990 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
5991 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
5992 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
5993 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
5997 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5998 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5999 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6000 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6001 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6002 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6003 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6005 responseend
= ProcessQuery(m
, msg
, end
, srcaddr
, InterfaceID
,
6006 !mDNSSameIPPort(srcport
, MulticastDNSPort
), mDNSAddrIsDNSMulticast(dstaddr
), QueryWasLocalUnicast
, &m
->omsg
);
6008 if (responseend
) // If responseend is non-null, that means we built a unicast response packet
6010 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
6011 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
6012 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
6013 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s",
6014 srcaddr
, mDNSVal16(srcport
), InterfaceID
, srcaddr
->type
);
6015 mDNSSendDNSMessage(m
, &m
->omsg
, responseend
, InterfaceID
, mDNSNULL
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
6020 mDNSlocal mDNSBool
TrustedSource(const mDNS
*const m
, const mDNSAddr
*const srcaddr
)
6024 (void)srcaddr
; // Unused
6025 for (s
= m
->DNSServers
; s
; s
= s
->next
)
6026 if (mDNSSameAddress(srcaddr
, &s
->addr
)) return(mDNStrue
);
6031 struct UDPSocket_struct
6033 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
6036 mDNSlocal DNSQuestion
*ExpectingUnicastResponseForQuestion(const mDNS
*const m
, const mDNSIPPort port
, const mDNSOpaque16 id
, const DNSQuestion
*const question
)
6039 for (q
= m
->Questions
; q
; q
=q
->next
)
6040 if (q
->LocalSocket
&&
6041 mDNSSameIPPort (q
->LocalSocket
->port
, port
) &&
6042 mDNSSameOpaque16(q
->TargetQID
, id
) &&
6043 q
->qtype
== question
->qtype
&&
6044 q
->qclass
== question
->qclass
&&
6045 q
->qnamehash
== question
->qnamehash
&&
6046 SameDomainName(&q
->qname
, &question
->qname
))
6051 mDNSlocal mDNSBool
ExpectingUnicastResponseForRecord(mDNS
*const m
, const mDNSAddr
*const srcaddr
, const mDNSBool SrcLocal
, const mDNSIPPort port
, const mDNSOpaque16 id
, const CacheRecord
*const rr
)
6056 for (q
= m
->Questions
; q
; q
=q
->next
)
6057 if (!q
->DuplicateOf
&& ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
6059 if (!mDNSOpaque16IsZero(q
->TargetQID
))
6061 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id
), mDNSVal16(q
->TargetQID
), CRDisplayString(m
, rr
));
6062 if (mDNSSameOpaque16(q
->TargetQID
, id
))
6064 if (q
->LocalSocket
&& mDNSSameIPPort(q
->LocalSocket
->port
, port
)) return(mDNStrue
);
6065 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
6066 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
6067 // if (TrustedSource(m, srcaddr)) return(mDNStrue);
6068 LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
6069 q
->qname
.c
, DNSTypeName(q
->qtype
), &q
->Target
, mDNSVal16(q
->LocalSocket
? q
->LocalSocket
->port
: zeroIPPort
), srcaddr
, mDNSVal16(port
), CRDisplayString(m
, rr
));
6075 if (SrcLocal
&& q
->ExpectUnicastResp
&& (mDNSu32
)(m
->timenow
- q
->ExpectUnicastResp
) < (mDNSu32
)(mDNSPlatformOneSecond
*2))
6082 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
6083 // Currently this applies only to rdata types containing more than one domainname,
6084 // or types where the domainname is not the last item in the structure.
6085 // In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
6086 mDNSlocal mDNSu16
GetRDLengthMem(const ResourceRecord
*const rr
)
6090 case kDNSType_SOA
: return sizeof(rdataSOA
);
6091 case kDNSType_RP
: return sizeof(rdataRP
);
6092 case kDNSType_PX
: return sizeof(rdataPX
);
6093 case kDNSType_NSEC
:return sizeof(rdataNSEC
);
6094 default: return rr
->rdlength
;
6098 mDNSexport CacheRecord
*CreateNewCacheEntry(mDNS
*const m
, const mDNSu32 slot
, CacheGroup
*cg
)
6100 CacheRecord
*rr
= mDNSNULL
;
6101 mDNSu16 RDLength
= GetRDLengthMem(&m
->rec
.r
.resrec
);
6103 if (!m
->rec
.r
.resrec
.InterfaceID
) debugf("CreateNewCacheEntry %s", CRDisplayString(m
, &m
->rec
.r
));
6105 //if (RDLength > InlineCacheRDSize)
6106 // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
6108 if (!cg
) cg
= GetCacheGroup(m
, slot
, &m
->rec
.r
.resrec
); // If we don't have a CacheGroup for this name, make one now
6109 if (cg
) rr
= GetCacheRecord(m
, cg
, RDLength
); // Make a cache record, being careful not to recycle cg
6110 if (!rr
) NoCacheAnswer(m
, &m
->rec
.r
);
6113 RData
*saveptr
= rr
->resrec
.rdata
; // Save the rr->resrec.rdata pointer
6114 *rr
= m
->rec
.r
; // Block copy the CacheRecord object
6115 rr
->resrec
.rdata
= saveptr
; // Restore rr->resrec.rdata after the structure assignment
6116 rr
->resrec
.name
= cg
->name
; // And set rr->resrec.name to point into our CacheGroup header
6118 // If this is an oversized record with external storage allocated, copy rdata to external storage
6119 if (rr
->resrec
.rdata
== (RData
*)&rr
->smallrdatastorage
&& RDLength
> InlineCacheRDSize
)
6120 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6121 else if (rr
->resrec
.rdata
!= (RData
*)&rr
->smallrdatastorage
&& RDLength
<= InlineCacheRDSize
)
6122 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6123 if (RDLength
> InlineCacheRDSize
)
6124 mDNSPlatformMemCopy(rr
->resrec
.rdata
, m
->rec
.r
.resrec
.rdata
, sizeofRDataHeader
+ RDLength
);
6126 rr
->next
= mDNSNULL
; // Clear 'next' pointer
6127 *(cg
->rrcache_tail
) = rr
; // Append this record to tail of cache slot list
6128 cg
->rrcache_tail
= &(rr
->next
); // Advance tail pointer
6129 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
6130 rr
->DelayDelivery
= NonZeroTime(m
->timenow
);
6131 else if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
&& // If marked unique,
6132 rr
->resrec
.rdata
->MaxRDLength
!= 0) // and non-negative, assume we may have
6133 rr
->DelayDelivery
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
); // to delay delivery of this 'add' event
6135 rr
->DelayDelivery
= CheckForSoonToExpireRecords(m
, rr
->resrec
.name
, rr
->resrec
.namehash
, slot
);
6137 CacheRecordAdd(m
, rr
); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
6142 mDNSlocal
void RefreshCacheRecord(mDNS
*const m
, CacheRecord
*rr
, mDNSu32 ttl
)
6144 rr
->TimeRcvd
= m
->timenow
;
6145 rr
->resrec
.rroriginalttl
= ttl
;
6146 rr
->UnansweredQueries
= 0;
6147 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6148 rr
->MPUnansweredQ
= 0;
6149 rr
->MPUnansweredKA
= 0;
6150 rr
->MPExpectingKA
= mDNSfalse
;
6152 SetNextCacheCheckTime(m
, rr
);
6155 mDNSexport
void GrantCacheExtensions(mDNS
*const m
, DNSQuestion
*q
, mDNSu32 lease
)
6158 const mDNSu32 slot
= HashSlot(&q
->qname
);
6159 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
6160 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6161 if (rr
->CRActiveQuestion
== q
)
6163 //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
6164 RefreshCacheRecord(m
, rr
, lease
);
6168 mDNSlocal mDNSu32
GetEffectiveTTL(const uDNS_LLQType LLQType
, mDNSu32 ttl
) // TTL in seconds
6170 if (LLQType
== uDNS_LLQ_Entire
) ttl
= kLLQ_DefLease
;
6171 else if (LLQType
== uDNS_LLQ_Events
)
6173 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
6174 if (ttl
== 0xFFFFFFFF) ttl
= 0;
6175 else ttl
= kLLQ_DefLease
;
6177 else // else not LLQ (standard uDNS response)
6179 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
6180 // also do this check here to make sure we can't get integer overflow below
6181 if (ttl
> 0x8000000UL
) ttl
= 0x8000000UL
;
6183 // Adjustment factor to avoid race condition:
6184 // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
6185 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
6186 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
6187 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
6188 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
6189 // the cached copy at our local caching server will already have expired, so the server will be forced
6190 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
6193 // For mDNS, TTL zero means "delete this record"
6194 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
6195 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
6196 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
6197 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
6198 if (ttl
< 15) ttl
= 15;
6204 // Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
6205 // the record list and/or question list.
6206 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6207 // InterfaceID non-NULL tells us the interface this multicast response was received on
6208 // InterfaceID NULL tells us this was a unicast response
6209 // dstaddr NULL tells us we received this over an outgoing TCP connection we made
6210 mDNSlocal
void mDNSCoreReceiveResponse(mDNS
*const m
,
6211 const DNSMessage
*const response
, const mDNSu8
*end
,
6212 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6213 const mDNSInterfaceID InterfaceID
)
6216 mDNSBool ResponseMCast
= dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
);
6217 mDNSBool ResponseSrcLocal
= !srcaddr
|| AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
6218 uDNS_LLQType LLQType
= uDNS_recvLLQResponse(m
, response
, end
, srcaddr
, srcport
);
6220 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
6221 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
6222 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
6223 CacheRecord
*CacheFlushRecords
= (CacheRecord
*)1;
6224 CacheRecord
**cfp
= &CacheFlushRecords
;
6226 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
6227 // to guard against spoof responses, then the only credible protection against that is cryptographic
6228 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
6229 int firstauthority
= response
->h
.numAnswers
;
6230 int firstadditional
= firstauthority
+ response
->h
.numAuthorities
;
6231 int totalrecords
= firstadditional
+ response
->h
.numAdditionals
;
6232 const mDNSu8
*ptr
= response
->data
;
6234 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
6235 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
6236 srcaddr
, dstaddr
, InterfaceID
,
6237 response
->h
.numQuestions
, response
->h
.numQuestions
== 1 ? ", " : "s,",
6238 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6239 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6240 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s", LLQType
);
6242 // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
6243 // When a DNS client receives a reply with TC
6244 // set, it should ignore that response, and query again, using a
6245 // mechanism, such as a TCP connection, that will permit larger replies.
6246 // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
6247 // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
6248 // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
6249 // <rdar://problem/6690034> Can't bind to Active Directory
6250 // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
6251 // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
6252 // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
6253 // and not even do the TCP query.
6254 // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
6255 if (!InterfaceID
&& (response
->h
.flags
.b
[0] & kDNSFlag0_TC
)) return;
6257 if (LLQType
== uDNS_LLQ_Ignore
) return;
6259 // 1. We ignore questions (if any) in mDNS response packets
6260 // 2. If this is an LLQ response, we handle it much the same
6261 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
6262 // answer as being the authoritative complete RRSet, and respond by deleting all other
6263 // matching cache records that don't appear in this packet.
6264 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
6265 if (ResponseMCast
|| LLQType
== uDNS_LLQ_Events
|| (response
->h
.flags
.b
[0] & kDNSFlag0_TC
))
6266 ptr
= LocateAnswers(response
, end
);
6267 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
6268 // in this response packet are immediately deemed to be invalid.
6271 mDNSu8 rcode
= (mDNSu8
)(response
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
6272 mDNSBool failure
= !(rcode
== kDNSFlag1_RC_NoErr
|| rcode
== kDNSFlag1_RC_NXDomain
|| rcode
== kDNSFlag1_RC_NotAuth
);
6273 mDNSBool returnEarly
= mDNSfalse
;
6274 // We could possibly combine this with the similar loop at the end of this function --
6275 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
6276 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
6277 // which it was received (or refreshed), and then at the end if we find any cache records which
6278 // answer questions in this packet's question section, but which aren't tagged with this packet's
6279 // packet number, then we deduce they are old and delete them
6280 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6282 DNSQuestion q
, *qptr
= mDNSNULL
;
6283 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6284 if (ptr
&& (!dstaddr
|| (qptr
= ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
))))
6289 const mDNSu32 slot
= HashSlot(&q
.qname
);
6290 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6291 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6292 if (q
.InterfaceID
== rr
->resrec
.InterfaceID
&& SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6294 debugf("uDNS marking %p %##s (%s) %p %s", q
.InterfaceID
, q
.qname
.c
, DNSTypeName(q
.qtype
),
6295 rr
->resrec
.InterfaceID
, CRDisplayString(m
, rr
));
6296 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
6297 rr
->TimeRcvd
= m
->timenow
- TicksTTL(rr
) - 1;
6298 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6305 LogInfo("Server %p responded with code %d to query %##s (%s)", qptr
->qDNSServer
, rcode
, q
.qname
.c
, DNSTypeName(q
.qtype
));
6306 PushDNSServerToEnd(m
, qptr
);
6308 returnEarly
= mDNStrue
;
6314 LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
6315 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6316 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6317 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s");
6318 // not goto exit because we won't have any CacheFlushRecords and we do not want to
6319 // generate negative cache entries (we want to query the next server)
6324 for (i
= 0; i
< totalrecords
&& ptr
&& ptr
< end
; i
++)
6326 // All responses sent via LL multicast are acceptable for caching
6327 // All responses received over our outbound TCP connections are acceptable for caching
6328 mDNSBool AcceptableResponse
= ResponseMCast
|| !dstaddr
|| LLQType
;
6329 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
6330 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
6332 const mDNSu8 RecordType
=
6333 (i
< firstauthority
) ? (mDNSu8
)kDNSRecordTypePacketAns
:
6334 (i
< firstadditional
) ? (mDNSu8
)kDNSRecordTypePacketAuth
: (mDNSu8
)kDNSRecordTypePacketAdd
;
6335 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, RecordType
, &m
->rec
);
6336 if (!ptr
) goto exit
; // Break out of the loop and clean up our CacheFlushRecords list before exiting
6338 // Don't want to cache OPT or TSIG pseudo-RRs
6339 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
|| m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
6340 { m
->rec
.r
.resrec
.RecordType
= 0; continue; }
6342 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
6343 // In the case of active LLQs, we'll get remove events when the records actually do go away
6344 // In the case of polling LLQs, we assume the record remains valid until the next poll
6345 if (!mDNSOpaque16IsZero(response
->h
.id
))
6346 m
->rec
.r
.resrec
.rroriginalttl
= GetEffectiveTTL(LLQType
, m
->rec
.r
.resrec
.rroriginalttl
);
6348 // If response was not sent via LL multicast,
6349 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
6350 if (!AcceptableResponse
) AcceptableResponse
= ExpectingUnicastResponseForRecord(m
, srcaddr
, ResponseSrcLocal
, dstport
, response
->h
.id
, &m
->rec
.r
);
6352 // 1. Check that this packet resource record does not conflict with any of ours
6353 if (mDNSOpaque16IsZero(response
->h
.id
) && m
->rec
.r
.resrec
.rrtype
!= kDNSType_NSEC
)
6355 if (m
->CurrentRecord
)
6356 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
6357 m
->CurrentRecord
= m
->ResourceRecords
;
6358 while (m
->CurrentRecord
)
6360 AuthRecord
*rr
= m
->CurrentRecord
;
6361 m
->CurrentRecord
= rr
->next
;
6362 // We accept all multicast responses, and unicast responses resulting from queries we issued
6363 // For other unicast responses, this code accepts them only for responses with an
6364 // (apparently) local source address that pertain to a record of our own that's in probing state
6365 if (!AcceptableResponse
&& !(ResponseSrcLocal
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)) continue;
6367 if (PacketRRMatchesSignature(&m
->rec
.r
, rr
)) // If interface, name, type (if shared record) and class match...
6369 // ... check to see if type and rdata are identical
6370 if (IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6372 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
6373 if (m
->rec
.r
.resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/2 || m
->SleepState
)
6375 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
6376 if (rr
->ImmedAnswer
== InterfaceID
) { rr
->ImmedAnswer
= mDNSNULL
; rr
->ImmedUnicast
= mDNSfalse
; }
6380 if (rr
->ImmedAnswer
== mDNSNULL
) { rr
->ImmedAnswer
= InterfaceID
; m
->NextScheduledResponse
= m
->timenow
; }
6381 else if (rr
->ImmedAnswer
!= InterfaceID
) { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6384 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
6385 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0 && PacketRRConflict(m
, rr
, &m
->rec
.r
))
6387 LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
6388 LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6390 // If this record is marked DependentOn another record for conflict detection purposes,
6391 // then *that* record has to be bumped back to probing state to resolve the conflict
6392 if (rr
->DependentOn
)
6394 while (rr
->DependentOn
) rr
= rr
->DependentOn
;
6395 LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6398 // If we've just whacked this record's ProbeCount, don't need to do it again
6399 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
6400 LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m
, rr
));
6401 else if (rr
->ProbeCount
== DefaultProbeCountForTypeUnique
)
6402 LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m
, rr
));
6405 LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr
, mDNSVal16(srcport
), CRDisplayString(m
, &m
->rec
.r
));
6406 // If we'd previously verified this record, put it back to probing state and try again
6407 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
6409 LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m
, rr
));
6410 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
6411 // We set ProbeCount to one more than the usual value so we know we've already touched this record.
6412 // This is because our single probe for "example-name.local" could yield a response with (say) two A records and
6413 // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
6414 // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
6415 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
+ 1;
6416 rr
->AnnounceCount
= InitialAnnounceCount
;
6417 InitializeLastAPTime(m
, rr
);
6418 RecordProbeFailure(m
, rr
); // Repeated late conflicts also cause us to back off to the slower probing rate
6420 // If we're probing for this record, we just failed
6421 else if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
6423 LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr
->ProbeCount
, ARDisplayString(m
, rr
));
6424 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6426 // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
6427 // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
6428 else if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
6430 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m
, rr
));
6431 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6434 LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
6437 // Else, matching signature, different type or rdata, but not a considered a conflict.
6438 // If the packet record has the cache-flush bit set, then we check to see if we
6439 // have any record(s) of the same type that we should re-assert to rescue them
6440 // (see note about "multi-homing and bridged networks" at the end of this function).
6441 else if (m
->rec
.r
.resrec
.rrtype
== rr
->resrec
.rrtype
)
6442 if ((m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && m
->timenow
- rr
->LastMCTime
> mDNSPlatformOneSecond
/2)
6443 { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6448 if (!AcceptableResponse
)
6450 const CacheRecord
*cr
;
6451 for (cr
= CacheFlushRecords
; cr
!= (CacheRecord
*)1; cr
= cr
->NextInCFList
)
6453 domainname
*target
= GetRRDomainNameTarget(&cr
->resrec
);
6454 if (target
&& cr
->resrec
.rdatahash
== m
->rec
.r
.resrec
.namehash
&& SameDomainName(target
, m
->rec
.r
.resrec
.name
))
6455 { AcceptableResponse
= mDNStrue
; break; }
6459 // 2. See if we want to add this packet resource record to our cache
6460 // We only try to cache answers if we have a cache to put them in
6461 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
6462 if (!AcceptableResponse
) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m
, &m
->rec
.r
));
6463 if (m
->rrcache_size
&& AcceptableResponse
)
6465 const mDNSu32 slot
= HashSlot(m
->rec
.r
.resrec
.name
);
6466 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &m
->rec
.r
.resrec
);
6469 // 2a. Check if this packet resource record is already in our cache
6470 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6472 // If we found this exact resource record, refresh its TTL
6473 if (rr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6475 if (m
->rec
.r
.resrec
.rdlength
> InlineCacheRDSize
)
6476 verbosedebugf("Found record size %5d interface %p already in cache: %s",
6477 m
->rec
.r
.resrec
.rdlength
, InterfaceID
, CRDisplayString(m
, &m
->rec
.r
));
6478 rr
->TimeRcvd
= m
->timenow
;
6480 if (m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
)
6482 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
6483 if (rr
->NextInCFList
== mDNSNULL
&& cfp
!= &rr
->NextInCFList
&& LLQType
!= uDNS_LLQ_Events
)
6484 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6486 // If this packet record is marked unique, and our previous cached copy was not, then fix it
6487 if (!(rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))
6490 for (q
= m
->Questions
; q
; q
=q
->next
) if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
)) q
->UniqueAnswers
++;
6491 rr
->resrec
.RecordType
= m
->rec
.r
.resrec
.RecordType
;
6495 if (!mDNSPlatformMemSame(m
->rec
.r
.resrec
.rdata
->u
.data
, rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
))
6497 // If the rdata of the packet record differs in name capitalization from the record in our cache
6498 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
6499 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
6500 rr
->resrec
.rroriginalttl
= 0;
6501 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6502 SetNextCacheCheckTime(m
, rr
);
6503 // DO NOT break out here -- we want to continue as if we never found it
6505 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0)
6507 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
6508 RefreshCacheRecord(m
, rr
, m
->rec
.r
.resrec
.rroriginalttl
);
6513 // If the packet TTL is zero, that means we're deleting this record.
6514 // To give other hosts on the network a chance to protest, we push the deletion
6515 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
6516 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
6517 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
6518 debugf("DE for %s", CRDisplayString(m
, rr
));
6519 rr
->resrec
.rroriginalttl
= 1;
6520 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6521 SetNextCacheCheckTime(m
, rr
);
6527 // If packet resource record not in our cache, add it now
6528 // (unless it is just a deletion of a record we never had, in which case we don't care)
6529 if (!rr
&& m
->rec
.r
.resrec
.rroriginalttl
> 0)
6531 rr
= CreateNewCacheEntry(m
, slot
, cg
);
6532 if (rr
&& (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && LLQType
!= uDNS_LLQ_Events
)
6533 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6536 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6540 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6542 // If we've just received one or more records with their cache flush bits set,
6543 // then scan that cache slot to see if there are any old stale records we need to flush
6544 while (CacheFlushRecords
!= (CacheRecord
*)1)
6546 CacheRecord
*r1
= CacheFlushRecords
, *r2
;
6547 const mDNSu32 slot
= HashSlot(r1
->resrec
.name
);
6548 const CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &r1
->resrec
);
6549 CacheFlushRecords
= CacheFlushRecords
->NextInCFList
;
6550 r1
->NextInCFList
= mDNSNULL
;
6552 // Look for records in the cache with the same signature as this new one with the cache flush
6553 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
6554 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
6555 // We make these TTL adjustments *only* for records that still have *more* than one second
6556 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
6557 // (and now has half a second remaining) could inadvertently get its life extended, by either
6558 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
6559 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
6560 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
6561 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
6562 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
6563 // To avoid this, we need to ensure that the cache flushing operation will only act to
6564 // *decrease* a record's remaining lifetime, never *increase* it.
6565 for (r2
= cg
? cg
->members
: mDNSNULL
; r2
; r2
=r2
->next
)
6566 if (r1
->resrec
.InterfaceID
== r2
->resrec
.InterfaceID
&&
6567 r1
->resrec
.rrtype
== r2
->resrec
.rrtype
&&
6568 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
)
6570 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
6571 // else, if record is old, mark it to be flushed
6572 if (m
->timenow
- r2
->TimeRcvd
< mDNSPlatformOneSecond
&& RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6574 // If we find mismatched TTLs in an RRSet, correct them.
6575 // We only do this for records with a TTL of 2 or higher. It's possible to have a
6576 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
6577 // which we treat as a goodbye followed by an addition) and in that case it would be
6578 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
6579 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
6580 // because certain early Bonjour devices are known to have this specific mismatch, and
6581 // there's no point filling syslog with messages about something we already know about.
6582 // We also don't log this for uDNS responses, since a caching name server is obliged
6583 // to give us an aged TTL to correct for how long it has held the record,
6584 // so our received TTLs are expected to vary in that case
6585 if (r2
->resrec
.rroriginalttl
!= r1
->resrec
.rroriginalttl
&& r1
->resrec
.rroriginalttl
> 1)
6587 if (!(r2
->resrec
.rroriginalttl
== 240 && r1
->resrec
.rroriginalttl
== 60 && r2
->resrec
.rrtype
== kDNSType_TXT
) &&
6588 mDNSOpaque16IsZero(response
->h
.id
))
6589 LogInfo("Correcting TTL from %4d to %4d for %s",
6590 r2
->resrec
.rroriginalttl
, r1
->resrec
.rroriginalttl
, CRDisplayString(m
, r2
));
6591 r2
->resrec
.rroriginalttl
= r1
->resrec
.rroriginalttl
;
6593 r2
->TimeRcvd
= m
->timenow
;
6595 else // else, if record is old, mark it to be flushed
6597 verbosedebugf("Cache flush %p X %p %s", r1
, r2
, CRDisplayString(m
, r2
));
6598 // We set stale records to expire in one second.
6599 // This gives the owner a chance to rescue it if necessary.
6600 // This is important in the case of multi-homing and bridged networks:
6601 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
6602 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
6603 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
6604 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
6605 // By delaying the deletion by one second, we give X a change to notice that this bridging has
6606 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
6608 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
6609 // final expiration queries for this record.
6611 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
6612 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
6613 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
6614 if (r2
->TimeRcvd
== m
->timenow
&& r2
->resrec
.rroriginalttl
<= 1 && r2
->UnansweredQueries
== MaxUnansweredQueries
)
6616 debugf("Cache flush for DE record %s", CRDisplayString(m
, r2
));
6617 r2
->resrec
.rroriginalttl
= 0;
6618 m
->NextCacheCheck
= m
->timenow
;
6619 m
->NextScheduledEvent
= m
->timenow
;
6621 else if (RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6623 // We only set a record to expire in one second if it currently has *more* than a second to live
6624 // If it's already due to expire in a second or less, we just leave it alone
6625 r2
->resrec
.rroriginalttl
= 1;
6626 r2
->UnansweredQueries
= MaxUnansweredQueries
;
6627 r2
->TimeRcvd
= m
->timenow
- 1;
6628 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
6629 // that we marked for deletion via an explicit DE record
6632 SetNextCacheCheckTime(m
, r2
);
6634 if (r1
->DelayDelivery
) // If we were planning to delay delivery of this record, see if we still need to
6636 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
6637 r1
->DelayDelivery
= CheckForSoonToExpireRecords(m
, r1
->resrec
.name
, r1
->resrec
.namehash
, slot
);
6638 if (!r1
->DelayDelivery
) CacheRecordDeferredAdd(m
, r1
);
6642 // See if we need to generate negative cache entries for unanswered unicast questions
6643 ptr
= response
->data
;
6644 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6647 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6648 if (ptr
&& (!dstaddr
|| ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
)))
6650 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
6651 // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
6652 // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
6653 // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
6654 // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
6655 // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
6656 // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
6657 // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
6658 // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
6659 // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
6660 if (!InterfaceID
&& q
.qtype
!= kDNSType_SOA
&& IsLocalDomain(&q
.qname
))
6661 LogInfo("Not generating negative cache entry for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
6664 CacheRecord
*rr
, *neg
= mDNSNULL
;
6665 mDNSu32 slot
= HashSlot(&q
.qname
);
6666 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6667 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6668 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6670 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
6671 if (rr
->TimeRcvd
+ TicksTTL(rr
) - m
->timenow
> 0) break;
6672 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
6673 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
) neg
= rr
;
6678 // We start off assuming a negative caching TTL of 60 seconds
6679 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
6680 mDNSu32 negttl
= 60;
6682 const domainname
*name
= &q
.qname
;
6683 mDNSu32 hash
= q
.qnamehash
;
6685 // Special case for our special Microsoft Active Directory "local SOA" check.
6686 // Some cheap home gateways don't include an SOA record in the authority section when
6687 // they send negative responses, so we don't know how long to cache the negative result.
6688 // Because we don't want to keep hitting the root name servers with our query to find
6689 // if we're on a network using Microsoft Active Directory using "local" as a private
6690 // internal top-level domain, we make sure to cache the negative result for at least one day.
6691 if (q
.qtype
== kDNSType_SOA
&& SameDomainName(&q
.qname
, &localdomain
)) negttl
= 60 * 60 * 24;
6693 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
6694 if (response
->h
.numAuthorities
&& (ptr
= LocateAuthorities(response
, end
)) != mDNSNULL
)
6696 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
6697 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_SOA
)
6699 const rdataSOA
*const soa
= (const rdataSOA
*)m
->rec
.r
.resrec
.rdata
->u
.data
;
6700 mDNSu32 ttl_s
= soa
->min
;
6701 // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
6702 // for the SOA record for ".", where the record is reported as non-cacheable
6703 // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
6704 if (ttl_s
> m
->rec
.r
.resrec
.rroriginalttl
&& m
->rec
.r
.resrec
.name
->c
[0])
6705 ttl_s
= m
->rec
.r
.resrec
.rroriginalttl
;
6706 if (negttl
< ttl_s
) negttl
= ttl_s
;
6708 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
6709 // with an Authority Section SOA record for d.com, then this is a hint that the authority
6710 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
6711 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
6712 if (q
.qtype
== kDNSType_SOA
)
6714 int qcount
= CountLabels(&q
.qname
);
6715 int scount
= CountLabels(m
->rec
.r
.resrec
.name
);
6716 if (qcount
- 1 > scount
)
6717 if (SameDomainName(SkipLeadingLabels(&q
.qname
, qcount
- scount
), m
->rec
.r
.resrec
.name
))
6718 repeat
= qcount
- 1 - scount
;
6721 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6724 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
6725 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
6726 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
6727 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
6728 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
6729 // so that we back off our polling rate and don't keep hitting the server continually.
6732 if (negttl
< neg
->resrec
.rroriginalttl
* 2)
6733 negttl
= neg
->resrec
.rroriginalttl
* 2;
6738 negttl
= GetEffectiveTTL(LLQType
, negttl
); // Add 25% grace period if necessary
6740 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
6743 debugf("Renewing negative TTL from %d to %d %s", neg
->resrec
.rroriginalttl
, negttl
, CRDisplayString(m
, neg
));
6744 RefreshCacheRecord(m
, neg
, negttl
);
6748 debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl
, name
->c
, DNSTypeName(q
.qtype
));
6749 MakeNegativeCacheRecord(m
, &m
->rec
.r
, name
, hash
, q
.qtype
, q
.qclass
, negttl
, mDNSInterface_Any
);
6750 CreateNewCacheEntry(m
, slot
, cg
);
6751 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6754 name
= (const domainname
*)(name
->c
+ 1 + name
->c
[0]);
6755 hash
= DomainNameHashValue(name
);
6756 slot
= HashSlot(name
);
6757 cg
= CacheGroupForName(m
, slot
, hash
, name
);
6765 mDNSlocal
void SPSRecordCallback(mDNS
*const m
, AuthRecord
*const ar
, mStatus result
)
6767 if (result
&& result
!= mStatus_MemFree
)
6768 LogInfo("SPS Callback %d %s", result
, ARDisplayString(m
, ar
));
6770 if (result
== mStatus_NameConflict
)
6772 LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
6773 InterfaceNameForID(m
, ar
->resrec
.InterfaceID
), &ar
->WakeUp
.HMAC
, ARDisplayString(m
, ar
));
6774 SendWakeup(m
, ar
->resrec
.InterfaceID
, &ar
->WakeUp
.IMAC
, &ar
->WakeUp
.password
);
6776 else if (result
== mStatus_MemFree
)
6779 mDNSPlatformMemFree(ar
);
6783 mDNSlocal
void mDNSCoreReceiveUpdate(mDNS
*const m
,
6784 const DNSMessage
*const msg
, const mDNSu8
*end
,
6785 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6786 const mDNSInterfaceID InterfaceID
)
6790 mDNSu8
*p
= m
->omsg
.data
;
6792 mDNSu32 updatelease
= 0;
6795 LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6796 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6797 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6798 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6799 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6800 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6801 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6803 if (!InterfaceID
|| !m
->SPSSocket
|| !mDNSSameIPPort(dstport
, m
->SPSSocket
->port
)) return;
6805 if (mDNS_PacketLoggingEnabled
)
6806 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
6808 ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
+ DNSOpt_OwnerData_ID_Space
);
6811 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
6812 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
6815 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
6816 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
6818 if (o
->opt
== kDNSOpt_Lease
) updatelease
= o
->u
.updatelease
;
6819 else if (o
->opt
== kDNSOpt_Owner
&& o
->u
.owner
.vers
== 0) owner
= o
->u
.owner
;
6822 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6825 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, UpdateRespFlags
);
6827 if (!updatelease
|| !owner
.HMAC
.l
[0])
6829 static int msgs
= 0;
6833 LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr
, mDNSVal16(srcport
),
6834 !updatelease
? " No lease" : "", !owner
.HMAC
.l
[0] ? " No owner" : "");
6836 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_FormErr
;
6838 else if (m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
> MAX_PROXY_RECORDS
)
6840 static int msgs
= 0;
6844 LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr
, mDNSVal16(srcport
),
6845 m
->ProxyRecords
, msg
->h
.mDNS_numUpdates
, m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
, MAX_PROXY_RECORDS
);
6847 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
;
6851 LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner
.HMAC
, &owner
.IMAC
, &owner
.password
, owner
.seq
);
6853 if (updatelease
> 24 * 60 * 60)
6854 updatelease
= 24 * 60 * 60;
6856 if (updatelease
> 0x40000000UL
/ mDNSPlatformOneSecond
)
6857 updatelease
= 0x40000000UL
/ mDNSPlatformOneSecond
;
6859 ptr
= LocateAuthorities(msg
, end
);
6860 for (i
= 0; i
< msg
->h
.mDNS_numUpdates
&& ptr
&& ptr
< end
; i
++)
6862 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
6865 mDNSu16 RDLengthMem
= GetRDLengthMem(&m
->rec
.r
.resrec
);
6866 AuthRecord
*ar
= mDNSPlatformMemAllocate(sizeof(AuthRecord
) - sizeof(RDataBody
) + RDLengthMem
);
6867 if (!ar
) { m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
; break; }
6870 mDNSu8 RecordType
= m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
? kDNSRecordTypeUnique
: kDNSRecordTypeShared
;
6871 m
->rec
.r
.resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
;
6872 mDNS_SetupResourceRecord(ar
, mDNSNULL
, InterfaceID
, m
->rec
.r
.resrec
.rrtype
, m
->rec
.r
.resrec
.rroriginalttl
, RecordType
, SPSRecordCallback
, ar
);
6873 AssignDomainName(&ar
->namestorage
, m
->rec
.r
.resrec
.name
);
6874 ar
->resrec
.rdlength
= GetRDLength(&m
->rec
.r
.resrec
, mDNSfalse
);
6875 ar
->resrec
.rdata
->MaxRDLength
= RDLengthMem
;
6876 mDNSPlatformMemCopy(ar
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, RDLengthMem
);
6878 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_PTR
)
6880 mDNSs32 t
= ReverseMapDomainType(m
->rec
.r
.resrec
.name
);
6881 if (t
== mDNSAddrType_IPv4
) GetIPv4FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
6882 else if (t
== mDNSAddrType_IPv6
) GetIPv6FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
6883 debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t
, ar
->AddressProxy
.type
, &ar
->AddressProxy
, ARDisplayString(m
, ar
));
6884 if (ar
->AddressProxy
.type
) SetSPSProxyListChanged(InterfaceID
);
6886 ar
->TimeRcvd
= m
->timenow
;
6887 ar
->TimeExpire
= m
->timenow
+ updatelease
* mDNSPlatformOneSecond
;
6888 if (m
->NextScheduledSPS
- ar
->TimeExpire
> 0)
6889 m
->NextScheduledSPS
= ar
->TimeExpire
;
6890 mDNS_Register_internal(m
, ar
);
6891 // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
6892 if (ar
->resrec
.rrtype
== kDNSType_AAAA
) ar
->resrec
.rroriginalttl
= 0;
6894 LogSPS("SPS Registered %4d %X %s", m
->ProxyRecords
, RecordType
, ARDisplayString(m
,ar
));
6897 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6900 if (m
->omsg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)
6902 LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr
, mDNSVal16(srcport
));
6903 ClearProxyRecords(m
, &owner
, m
->DuplicateRecords
);
6904 ClearProxyRecords(m
, &owner
, m
->ResourceRecords
);
6908 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
6909 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
6910 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
6911 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
6912 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
6913 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= updatelease
;
6914 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
6918 if (p
) mDNSSendDNSMessage(m
, &m
->omsg
, p
, InterfaceID
, m
->SPSSocket
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
6921 mDNSlocal
void mDNSCoreReceiveUpdateR(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
)
6926 mDNSu32 updatelease
= 60 * 60; // If SPS fails to indicate lease time, assume one hour
6927 const mDNSu8
*ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
);
6930 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
6931 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
6934 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
6935 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
6936 if (o
->opt
== kDNSOpt_Lease
)
6938 updatelease
= o
->u
.updatelease
;
6939 LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease
);
6942 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6945 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6946 if (rr
->resrec
.InterfaceID
== InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
6947 if (mDNSSameOpaque16(rr
->updateid
, msg
->h
.id
))
6949 rr
->updateid
= zeroID
;
6950 rr
->expire
= NonZeroTime(m
->timenow
+ updatelease
* mDNSPlatformOneSecond
);
6951 LogSPS("Sleep Proxy registered record %5d %s", updatelease
, ARDisplayString(m
,rr
));
6955 // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
6956 // may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
6957 if (m
->SleepLimit
) m
->NextScheduledSPRetry
= m
->timenow
;
6960 mDNSexport
void MakeNegativeCacheRecord(mDNS
*const m
, CacheRecord
*const cr
,
6961 const domainname
*const name
, const mDNSu32 namehash
, const mDNSu16 rrtype
, const mDNSu16 rrclass
, mDNSu32 ttl_seconds
, mDNSInterfaceID InterfaceID
)
6963 if (cr
== &m
->rec
.r
&& m
->rec
.r
.resrec
.RecordType
)
6965 LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m
, &m
->rec
.r
));
6971 // Create empty resource record
6972 cr
->resrec
.RecordType
= kDNSRecordTypePacketNegative
;
6973 cr
->resrec
.InterfaceID
= InterfaceID
;
6974 cr
->resrec
.name
= name
; // Will be updated to point to cg->name when we call CreateNewCacheEntry
6975 cr
->resrec
.rrtype
= rrtype
;
6976 cr
->resrec
.rrclass
= rrclass
;
6977 cr
->resrec
.rroriginalttl
= ttl_seconds
;
6978 cr
->resrec
.rdlength
= 0;
6979 cr
->resrec
.rdestimate
= 0;
6980 cr
->resrec
.namehash
= namehash
;
6981 cr
->resrec
.rdatahash
= 0;
6982 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
6983 cr
->resrec
.rdata
->MaxRDLength
= 0;
6985 cr
->NextInKAList
= mDNSNULL
;
6986 cr
->TimeRcvd
= m
->timenow
;
6987 cr
->DelayDelivery
= 0;
6988 cr
->NextRequiredQuery
= m
->timenow
;
6989 cr
->LastUsed
= m
->timenow
;
6990 cr
->CRActiveQuestion
= mDNSNULL
;
6991 cr
->UnansweredQueries
= 0;
6992 cr
->LastUnansweredTime
= 0;
6993 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6994 cr
->MPUnansweredQ
= 0;
6995 cr
->MPLastUnansweredQT
= 0;
6996 cr
->MPUnansweredKA
= 0;
6997 cr
->MPExpectingKA
= mDNSfalse
;
6999 cr
->NextInCFList
= mDNSNULL
;
7002 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, void *const pkt
, const mDNSu8
*const end
,
7003 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
,
7004 const mDNSInterfaceID InterfaceID
)
7006 mDNSInterfaceID ifid
= InterfaceID
;
7007 DNSMessage
*msg
= (DNSMessage
*)pkt
;
7008 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
7009 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
7010 const mDNSu8 UpdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_Update
;
7011 const mDNSu8 UpdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
7013 mDNSu8
*ptr
= mDNSNULL
;
7014 mDNSBool TLS
= (dstaddr
== (mDNSAddr
*)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
7015 if (TLS
) dstaddr
= mDNSNULL
;
7017 #ifndef UNICAST_DISABLED
7018 if (mDNSSameAddress(srcaddr
, &m
->Router
))
7020 #ifdef _LEGACY_NAT_TRAVERSAL_
7021 if (mDNSSameIPPort(srcport
, SSDPPort
) || (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)))
7024 LNT_ConfigureRouterInfo(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7029 if (mDNSSameIPPort(srcport
, NATPMPPort
))
7032 uDNS_ReceiveNATPMPPacket(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7037 #ifdef _LEGACY_NAT_TRAVERSAL_
7038 else if (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr
, mDNSVal16(srcport
)); return; }
7042 if ((unsigned)(end
- (mDNSu8
*)pkt
) < sizeof(DNSMessageHeader
)) { LogMsg("DNS Message too short"); return; }
7043 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
7044 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
7045 ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
7046 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
7047 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
7048 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
7049 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
7051 if (!m
) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
7053 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
7054 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
7055 if (srcaddr
&& !mDNSAddressIsValid(srcaddr
)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr
); return; }
7059 #ifndef UNICAST_DISABLED
7060 if (!dstaddr
|| (!mDNSAddressIsAllDNSLinkGroup(dstaddr
) && (QR_OP
== StdR
|| QR_OP
== UpdR
)))
7061 if (!mDNSOpaque16IsZero(msg
->h
.id
)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
7063 ifid
= mDNSInterface_Any
;
7064 if (mDNS_PacketLoggingEnabled
)
7065 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, TLS
? "TLS" : !dstaddr
? "TCP" : "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
7066 uDNS_ReceiveMsg(m
, msg
, end
, srcaddr
, srcport
);
7067 // Note: mDNSCore also needs to get access to received unicast responses
7070 if (QR_OP
== StdQ
) mDNSCoreReceiveQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7071 else if (QR_OP
== StdR
) mDNSCoreReceiveResponse(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7072 else if (QR_OP
== UpdQ
) mDNSCoreReceiveUpdate (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
);
7073 else if (QR_OP
== UpdR
) mDNSCoreReceiveUpdateR (m
, msg
, end
, InterfaceID
);
7076 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
7077 msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1], srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
-(mDNSu8
*)pkt
, InterfaceID
);
7078 if (mDNS_LoggingEnabled
)
7081 while (i
<end
-(mDNSu8
*)pkt
)
7084 char *p
= buffer
+ mDNS_snprintf(buffer
, sizeof(buffer
), "%04X", i
);
7085 do if (i
<end
-(mDNSu8
*)pkt
) p
+= mDNS_snprintf(p
, sizeof(buffer
), " %02X", ((mDNSu8
*)pkt
)[i
]); while (++i
& 15);
7086 LogInfo("%s", buffer
);
7090 // Packet reception often causes a change to the task list:
7091 // 1. Inbound queries can cause us to need to send responses
7092 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
7093 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
7094 // 4. Response packets that answer questions may cause our client to issue new questions
7098 // ***************************************************************************
7099 #if COMPILER_LIKES_PRAGMA_MARK
7101 #pragma mark - Searcher Functions
7104 // Targets are considered the same if both queries are untargeted, or
7105 // if both are targeted to the same address+port
7106 // (If Target address is zero, TargetPort is undefined)
7107 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
7108 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
7110 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
7111 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
7112 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
7113 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
7114 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
7116 // If IsLLQ(Q) is true, it means the question is both:
7117 // (a) long-lived and
7118 // (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
7119 // for multicast questions, we don't want to treat LongLived as anything special
7120 #define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
7122 mDNSlocal DNSQuestion
*FindDuplicateQuestion(const mDNS
*const m
, const DNSQuestion
*const question
)
7125 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
7126 // This prevents circular references, where two questions are each marked as a duplicate of the other.
7127 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
7128 // further in the list.
7129 for (q
= m
->Questions
; q
&& q
!= question
; q
=q
->next
) // Scan our list for another question
7130 if (q
->InterfaceID
== question
->InterfaceID
&& // with the same InterfaceID,
7131 SameQTarget(q
, question
) && // and same unicast/multicast target settings
7132 q
->qtype
== question
->qtype
&& // type,
7133 q
->qclass
== question
->qclass
&& // class,
7134 IsLLQ(q
) == IsLLQ(question
) && // and long-lived status matches
7135 (!q
->AuthInfo
|| question
->AuthInfo
) && // to avoid deadlock, don't make public query dup of a private one
7136 q
->qnamehash
== question
->qnamehash
&&
7137 SameDomainName(&q
->qname
, &question
->qname
)) // and name
7142 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
7143 mDNSlocal
void UpdateQuestionDuplicates(mDNS
*const m
, DNSQuestion
*const question
)
7146 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7147 if (q
->DuplicateOf
== question
) // To see if any questions were referencing this as their duplicate
7148 if ((q
->DuplicateOf
= FindDuplicateQuestion(m
, q
)) == mDNSNULL
)
7150 // If q used to be a duplicate, but now is not,
7151 // then inherit the state from the question that's going away
7152 q
->LastQTime
= question
->LastQTime
;
7153 q
->ThisQInterval
= question
->ThisQInterval
;
7154 q
->ExpectUnicastResp
= question
->ExpectUnicastResp
;
7155 q
->LastAnswerPktNum
= question
->LastAnswerPktNum
;
7156 q
->RecentAnswerPkts
= question
->RecentAnswerPkts
;
7157 q
->RequestUnicast
= question
->RequestUnicast
;
7158 q
->LastQTxTime
= question
->LastQTxTime
;
7159 q
->CNAMEReferrals
= question
->CNAMEReferrals
;
7160 q
->nta
= question
->nta
;
7161 q
->servAddr
= question
->servAddr
;
7162 q
->servPort
= question
->servPort
;
7163 q
->qDNSServer
= question
->qDNSServer
;
7164 q
->unansweredQueries
= question
->unansweredQueries
;
7166 q
->TargetQID
= question
->TargetQID
;
7167 q
->LocalSocket
= question
->LocalSocket
;
7169 q
->state
= question
->state
;
7170 // q->tcp = question->tcp;
7171 q
->ReqLease
= question
->ReqLease
;
7172 q
->expire
= question
->expire
;
7173 q
->ntries
= question
->ntries
;
7174 q
->id
= question
->id
;
7176 question
->LocalSocket
= mDNSNULL
;
7177 question
->nta
= mDNSNULL
; // If we've got a GetZoneData in progress, transfer it to the newly active question
7178 // question->tcp = mDNSNULL;
7181 debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7185 LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7186 q
->nta
->ZoneDataContext
= q
;
7189 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
7190 if (question
->tcp
) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
7192 if (question
->state
== LLQ_Established
)
7194 LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7195 question
->state
= 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
7198 SetNextQueryTime(m
,q
);
7202 // Look up a DNS Server, matching by name in split-dns configurations.
7203 mDNSexport DNSServer
*GetServerForName(mDNS
*m
, const domainname
*name
)
7205 DNSServer
*curmatch
= mDNSNULL
, *p
;
7206 int curmatchlen
= -1, ncount
= name
? CountLabels(name
) : 0;
7208 for (p
= m
->DNSServers
; p
; p
= p
->next
)
7210 int scount
= CountLabels(&p
->domain
);
7211 if (!(p
->flags
& DNSServer_FlagDelete
) && ncount
>= scount
&& scount
> curmatchlen
)
7212 if (SameDomainName(SkipLeadingLabels(name
, ncount
- scount
), &p
->domain
))
7213 { curmatch
= p
; curmatchlen
= scount
; }
7218 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
7219 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
7221 // Called in normal client context (lock not held)
7222 mDNSlocal
void LLQNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
7227 LogInfo("LLQNATCallback external address:port %.4a:%u", &n
->ExternalAddress
, mDNSVal16(n
->ExternalPort
));
7228 for (q
= m
->Questions
; q
; q
=q
->next
)
7229 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
)
7230 startLLQHandshake(m
, q
); // If ExternalPort is zero, will do StartLLQPolling instead
7231 #if APPLE_OSX_mDNSResponder
7232 UpdateAutoTunnelDomainStatuses(m
);
7237 mDNSexport mStatus
mDNS_StartQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7239 if (question
->Target
.type
&& !ValidQuestionTarget(question
))
7241 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
7242 question
->Target
.type
, mDNSVal16(question
->TargetPort
));
7243 question
->Target
.type
= mDNSAddrType_None
;
7246 if (!question
->Target
.type
) question
->TargetPort
= zeroIPPort
; // If question->Target specified clear TargetPort
7248 question
->TargetQID
=
7249 #ifndef UNICAST_DISABLED
7250 (question
->Target
.type
|| (question
->InterfaceID
== mDNSInterface_Unicast
) ||
7251 (question
->InterfaceID
!= mDNSInterface_LocalOnly
&& !question
->ForceMCast
&& !IsLocalDomain(&question
->qname
)))
7252 ? mDNS_NewMessageID(m
) :
7253 #endif // UNICAST_DISABLED
7256 debugf("mDNS_StartQuery: %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7258 if (m
->rrcache_size
== 0) // Can't do queries if we have no cache space allocated
7259 return(mStatus_NoCache
);
7265 if (!ValidateDomainName(&question
->qname
))
7267 LogMsg("Attempt to start query with invalid qname %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7268 return(mStatus_Invalid
);
7271 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
7273 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) q
= &m
->LocalOnlyQuestions
;
7274 while (*q
&& *q
!= question
) q
=&(*q
)->next
;
7278 LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
7279 question
->qname
.c
, DNSTypeName(question
->qtype
), question
);
7280 return(mStatus_AlreadyRegistered
);
7285 // If this question is referencing a specific interface, verify it exists
7286 if (question
->InterfaceID
&& question
->InterfaceID
!= mDNSInterface_LocalOnly
&& question
->InterfaceID
!= mDNSInterface_Unicast
)
7288 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, question
->InterfaceID
);
7290 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
7291 question
->InterfaceID
, question
->qname
.c
, DNSTypeName(question
->qtype
));
7294 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
7295 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
7296 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
7297 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
7298 // that to go out immediately.
7299 question
->next
= mDNSNULL
;
7300 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // MUST do this before FindDuplicateQuestion()
7301 question
->DelayAnswering
= CheckForSoonToExpireRecords(m
, &question
->qname
, question
->qnamehash
, HashSlot(&question
->qname
));
7302 question
->LastQTime
= m
->timenow
;
7303 question
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
7304 question
->ExpectUnicastResp
= 0;
7305 question
->LastAnswerPktNum
= m
->PktNum
;
7306 question
->RecentAnswerPkts
= 0;
7307 question
->CurrentAnswers
= 0;
7308 question
->LargeAnswers
= 0;
7309 question
->UniqueAnswers
= 0;
7310 question
->FlappingInterface1
= mDNSNULL
;
7311 question
->FlappingInterface2
= mDNSNULL
;
7312 question
->AuthInfo
= GetAuthInfoForQuestion(m
, question
); // Must do this before calling FindDuplicateQuestion()
7313 question
->DuplicateOf
= FindDuplicateQuestion(m
, question
);
7314 question
->NextInDQList
= mDNSNULL
;
7315 question
->SendQNow
= mDNSNULL
;
7316 question
->SendOnAll
= mDNSfalse
;
7317 question
->RequestUnicast
= 0;
7318 question
->LastQTxTime
= m
->timenow
;
7319 question
->CNAMEReferrals
= 0;
7321 // We'll create our question->LocalSocket on demand, if needed.
7322 // We won't need one for duplicate questions, or from questions answered immediately out of the cache.
7323 // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
7324 // NAT mapping for receiving inbound add/remove events.
7325 question
->LocalSocket
= mDNSNULL
;
7326 question
->qDNSServer
= mDNSNULL
;
7327 question
->unansweredQueries
= 0;
7328 question
->nta
= mDNSNULL
;
7329 question
->servAddr
= zeroAddr
;
7330 question
->servPort
= zeroIPPort
;
7331 question
->tcp
= mDNSNULL
;
7332 question
->NoAnswer
= NoAnswer_Normal
;
7334 question
->state
= LLQ_InitialRequest
;
7335 question
->ReqLease
= 0;
7336 question
->expire
= 0;
7337 question
->ntries
= 0;
7338 question
->id
= zeroOpaque64
;
7340 if (question
->DuplicateOf
) question
->AuthInfo
= question
->DuplicateOf
->AuthInfo
;
7342 for (i
=0; i
<DupSuppressInfoSize
; i
++)
7343 question
->DupSuppress
[i
].InterfaceID
= mDNSNULL
;
7345 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
7346 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->InterfaceID
, m
->timenow
,
7347 question
->LastQTime
+ question
->ThisQInterval
- m
->timenow
,
7348 question
->DelayAnswering
? question
->DelayAnswering
- m
->timenow
: 0,
7349 question
, question
->DuplicateOf
? "duplicate of" : "not duplicate", question
->DuplicateOf
);
7351 if (question
->InterfaceID
== mDNSInterface_LocalOnly
)
7353 if (!m
->NewLocalOnlyQuestions
) m
->NewLocalOnlyQuestions
= question
;
7357 if (!m
->NewQuestions
) m
->NewQuestions
= question
;
7359 // If the question's id is non-zero, then it's Wide Area
7360 // MUST NOT do this Wide Area setup until near the end of
7361 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
7362 // NS, etc.) and if we haven't finished setting up our own question and setting
7363 // m->NewQuestions if necessary then we could end up recursively re-entering
7364 // this routine with the question list data structures in an inconsistent state.
7365 if (!mDNSOpaque16IsZero(question
->TargetQID
))
7367 question
->qDNSServer
= GetServerForName(m
, &question
->qname
);
7368 ActivateUnicastQuery(m
, question
, mDNSfalse
);
7370 // If long-lived query, and we don't have our NAT mapping active, start it now
7371 if (question
->LongLived
&& !m
->LLQNAT
.clientContext
)
7373 m
->LLQNAT
.Protocol
= NATOp_MapUDP
;
7374 m
->LLQNAT
.IntPort
= m
->UnicastPort4
;
7375 m
->LLQNAT
.RequestedPort
= m
->UnicastPort4
;
7376 m
->LLQNAT
.clientCallback
= LLQNATCallback
;
7377 m
->LLQNAT
.clientContext
= (void*)1; // Means LLQ NAT Traversal is active
7378 mDNS_StartNATOperation_internal(m
, &m
->LLQNAT
);
7381 #if APPLE_OSX_mDNSResponder
7382 if (question
->LongLived
)
7383 UpdateAutoTunnelDomainStatuses(m
);
7387 SetNextQueryTime(m
,question
);
7390 return(mStatus_NoError
);
7394 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
7395 mDNSexport
void CancelGetZoneData(mDNS
*const m
, ZoneData
*nta
)
7397 debugf("CancelGetZoneData %##s (%s)", nta
->question
.qname
.c
, DNSTypeName(nta
->question
.qtype
));
7398 mDNS_StopQuery_internal(m
, &nta
->question
);
7399 mDNSPlatformMemFree(nta
);
7402 mDNSexport mStatus
mDNS_StopQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7404 const mDNSu32 slot
= HashSlot(&question
->qname
);
7405 CacheGroup
*cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7407 DNSQuestion
**qp
= &m
->Questions
;
7409 //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7411 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) qp
= &m
->LocalOnlyQuestions
;
7412 while (*qp
&& *qp
!= question
) qp
=&(*qp
)->next
;
7413 if (*qp
) *qp
= (*qp
)->next
;
7417 if (question
->ThisQInterval
>= 0) // Only log error message if the query was supposed to be active
7419 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
7420 question
->qname
.c
, DNSTypeName(question
->qtype
));
7424 return(mStatus_BadReferenceErr
);
7427 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
7428 UpdateQuestionDuplicates(m
, question
);
7429 // But don't trash ThisQInterval until afterwards.
7430 question
->ThisQInterval
= -1;
7432 // If there are any cache records referencing this as their active question, then see if there is any
7433 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
7434 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7436 if (rr
->CRActiveQuestion
== question
)
7439 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7440 if (ActiveQuestion(q
) && ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
7442 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
7443 rr
->CRActiveQuestion
= q
; // Question used to be active; new value may or may not be null
7444 if (!q
) m
->rrcache_active
--; // If no longer active, decrement rrcache_active count
7448 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
7449 // bump its pointer forward one question.
7450 if (m
->CurrentQuestion
== question
)
7452 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
7453 question
->qname
.c
, DNSTypeName(question
->qtype
));
7454 m
->CurrentQuestion
= question
->next
;
7457 if (m
->NewQuestions
== question
)
7459 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
7460 question
->qname
.c
, DNSTypeName(question
->qtype
));
7461 m
->NewQuestions
= question
->next
;
7464 if (m
->NewLocalOnlyQuestions
== question
) m
->NewLocalOnlyQuestions
= question
->next
;
7466 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
7467 question
->next
= mDNSNULL
;
7469 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
7471 // And finally, cancel any associated GetZoneData operation that's still running.
7472 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
7473 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
7474 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
7475 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
7476 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
7477 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
7478 if (question
->LocalSocket
) { mDNSPlatformUDPClose(question
->LocalSocket
); question
->LocalSocket
= mDNSNULL
; }
7479 if (!mDNSOpaque16IsZero(question
->TargetQID
) && question
->LongLived
)
7481 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
7483 for (q
= m
->Questions
; q
; q
=q
->next
)
7484 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
) break;
7487 if (!m
->LLQNAT
.clientContext
) // Should never happen, but just in case...
7488 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
7491 LogInfo("Stopping LLQNAT");
7492 mDNS_StopNATOperation_internal(m
, &m
->LLQNAT
);
7493 m
->LLQNAT
.clientContext
= mDNSNULL
; // Means LLQ NAT Traversal not running
7497 // If necessary, tell server it can delete this LLQ state
7498 if (question
->state
== LLQ_Established
)
7500 question
->ReqLease
= 0;
7501 sendLLQRefresh(m
, question
);
7502 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
7503 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
7504 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
7505 // we let that run out its natural course and complete asynchronously.
7508 question
->tcp
->question
= mDNSNULL
;
7509 question
->tcp
= mDNSNULL
;
7512 #if APPLE_OSX_mDNSResponder
7513 UpdateAutoTunnelDomainStatuses(m
);
7517 return(mStatus_NoError
);
7520 mDNSexport mStatus
mDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
7524 status
= mDNS_StartQuery_internal(m
, question
);
7529 mDNSexport mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
7533 status
= mDNS_StopQuery_internal(m
, question
);
7538 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
7539 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
7540 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
7541 // specifically to catch and report if the client callback does try to make API calls
7542 mDNSexport mStatus
mDNS_StopQueryWithRemoves(mDNS
*const m
, DNSQuestion
*const question
)
7548 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
7549 for (qq
= m
->NewQuestions
; qq
; qq
=qq
->next
) if (qq
== question
) break;
7551 status
= mDNS_StopQuery_internal(m
, question
);
7552 if (status
== mStatus_NoError
&& !qq
)
7554 const CacheRecord
*rr
;
7555 const mDNSu32 slot
= HashSlot(&question
->qname
);
7556 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7557 LogInfo("Generating terminal removes for %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7558 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7559 if (rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& SameNameRecordAnswersQuestion(&rr
->resrec
, question
))
7561 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
7562 if (question
->QuestionCallback
)
7563 question
->QuestionCallback(m
, question
, &rr
->resrec
, mDNSfalse
);
7570 mDNSexport mStatus
mDNS_Reconfirm(mDNS
*const m
, CacheRecord
*const cr
)
7574 status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7575 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7580 mDNSexport mStatus
mDNS_ReconfirmByValue(mDNS
*const m
, ResourceRecord
*const rr
)
7582 mStatus status
= mStatus_BadReferenceErr
;
7585 cr
= FindIdenticalRecordInCache(m
, rr
);
7586 debugf("mDNS_ReconfirmByValue: %p %s", cr
, RRDisplayString(m
, rr
));
7587 if (cr
) status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7588 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7593 mDNSlocal mStatus
mDNS_StartBrowse_internal(mDNS
*const m
, DNSQuestion
*const question
,
7594 const domainname
*const srv
, const domainname
*const domain
,
7595 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7597 question
->InterfaceID
= InterfaceID
;
7598 question
->Target
= zeroAddr
;
7599 question
->qtype
= kDNSType_PTR
;
7600 question
->qclass
= kDNSClass_IN
;
7601 question
->LongLived
= mDNSfalse
;
7602 question
->ExpectUnique
= mDNSfalse
;
7603 question
->ForceMCast
= ForceMCast
;
7604 question
->ReturnIntermed
= mDNSfalse
;
7605 question
->QuestionCallback
= Callback
;
7606 question
->QuestionContext
= Context
;
7607 if (!ConstructServiceName(&question
->qname
, mDNSNULL
, srv
, domain
)) return(mStatus_BadParamErr
);
7609 #ifndef UNICAST_DISABLED
7610 if (Question_uDNS(question
))
7612 question
->LongLived
= mDNStrue
;
7613 question
->ThisQInterval
= InitialQuestionInterval
;
7614 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
7616 #endif // UNICAST_DISABLED
7617 return(mDNS_StartQuery_internal(m
, question
));
7620 mDNSexport mStatus
mDNS_StartBrowse(mDNS
*const m
, DNSQuestion
*const question
,
7621 const domainname
*const srv
, const domainname
*const domain
,
7622 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7626 status
= mDNS_StartBrowse_internal(m
, question
, srv
, domain
, InterfaceID
, ForceMCast
, Callback
, Context
);
7631 mDNSlocal mDNSBool
MachineHasActiveIPv6(mDNS
*const m
)
7633 NetworkInterfaceInfo
*intf
;
7634 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
7635 if (intf
->ip
.type
== mDNSAddrType_IPv6
) return(mDNStrue
);
7639 mDNSlocal
void FoundServiceInfoSRV(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7641 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7642 mDNSBool PortChanged
= !mDNSSameIPPort(query
->info
->port
, answer
->rdata
->u
.srv
.port
);
7643 if (!AddRecord
) return;
7644 if (answer
->rrtype
!= kDNSType_SRV
) return;
7646 query
->info
->port
= answer
->rdata
->u
.srv
.port
;
7648 // If this is our first answer, then set the GotSRV flag and start the address query
7651 query
->GotSRV
= mDNStrue
;
7652 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
7653 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
7654 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
7655 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
7656 mDNS_StartQuery(m
, &query
->qAv4
);
7657 // Only do the AAAA query if this machine actually has IPv6 active
7658 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
7660 // If this is not our first answer, only re-issue the address query if the target host name has changed
7661 else if ((query
->qAv4
.InterfaceID
!= query
->qSRV
.InterfaceID
&& query
->qAv4
.InterfaceID
!= answer
->InterfaceID
) ||
7662 !SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
))
7664 mDNS_StopQuery(m
, &query
->qAv4
);
7665 if (query
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &query
->qAv6
);
7666 if (SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
) && !PortChanged
)
7668 // If we get here, it means:
7669 // 1. This is not our first SRV answer
7670 // 2. The interface ID is different, but the target host and port are the same
7671 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
7672 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
7673 query
->qAv4
.InterfaceID
= query
->qSRV
.InterfaceID
; // Will be mDNSInterface_Any, or a specific interface
7674 query
->qAv6
.InterfaceID
= query
->qSRV
.InterfaceID
;
7678 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
7679 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
7680 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
7681 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
7683 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query
->qAv4
.qname
.c
, DNSTypeName(query
->qAv4
.qtype
));
7684 mDNS_StartQuery(m
, &query
->qAv4
);
7685 // Only do the AAAA query if this machine actually has IPv6 active
7686 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
7688 else if (query
->ServiceInfoQueryCallback
&& query
->GotADD
&& query
->GotTXT
&& PortChanged
)
7690 if (++query
->Answers
>= 100)
7691 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
7692 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.srv
.target
.c
,
7693 mDNSVal16(answer
->rdata
->u
.srv
.port
));
7694 query
->ServiceInfoQueryCallback(m
, query
);
7696 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7697 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7700 mDNSlocal
void FoundServiceInfoTXT(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7702 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7703 if (!AddRecord
) return;
7704 if (answer
->rrtype
!= kDNSType_TXT
) return;
7705 if (answer
->rdlength
> sizeof(query
->info
->TXTinfo
)) return;
7707 query
->GotTXT
= mDNStrue
;
7708 query
->info
->TXTlen
= answer
->rdlength
;
7709 query
->info
->TXTinfo
[0] = 0; // In case answer->rdlength is zero
7710 mDNSPlatformMemCopy(query
->info
->TXTinfo
, answer
->rdata
->u
.txt
.c
, answer
->rdlength
);
7712 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query
->info
->name
.c
, query
->GotADD
);
7714 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7715 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7716 if (query
->ServiceInfoQueryCallback
&& query
->GotADD
)
7718 if (++query
->Answers
>= 100)
7719 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
7720 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.txt
.c
);
7721 query
->ServiceInfoQueryCallback(m
, query
);
7725 mDNSlocal
void FoundServiceInfo(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7727 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7728 //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
7729 if (!AddRecord
) return;
7731 if (answer
->rrtype
== kDNSType_A
)
7733 query
->info
->ip
.type
= mDNSAddrType_IPv4
;
7734 query
->info
->ip
.ip
.v4
= answer
->rdata
->u
.ipv4
;
7736 else if (answer
->rrtype
== kDNSType_AAAA
)
7738 query
->info
->ip
.type
= mDNSAddrType_IPv6
;
7739 query
->info
->ip
.ip
.v6
= answer
->rdata
->u
.ipv6
;
7743 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer
->name
->c
, answer
->rrtype
, DNSTypeName(answer
->rrtype
));
7747 query
->GotADD
= mDNStrue
;
7748 query
->info
->InterfaceID
= answer
->InterfaceID
;
7750 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query
->info
->ip
.type
, query
->info
->name
.c
, query
->GotTXT
);
7752 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7753 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7754 if (query
->ServiceInfoQueryCallback
&& query
->GotTXT
)
7756 if (++query
->Answers
>= 100)
7757 debugf(answer
->rrtype
== kDNSType_A
?
7758 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
7759 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
7760 query
->Answers
, query
->qSRV
.qname
.c
, &answer
->rdata
->u
.data
);
7761 query
->ServiceInfoQueryCallback(m
, query
);
7765 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
7766 // If the query is not interface-specific, then InterfaceID may be zero
7767 // Each time the Callback is invoked, the remainder of the fields will have been filled in
7768 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
7769 mDNSexport mStatus
mDNS_StartResolveService(mDNS
*const m
,
7770 ServiceInfoQuery
*query
, ServiceInfo
*info
, mDNSServiceInfoQueryCallback
*Callback
, void *Context
)
7775 query
->qSRV
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7776 query
->qSRV
.InterfaceID
= info
->InterfaceID
;
7777 query
->qSRV
.Target
= zeroAddr
;
7778 AssignDomainName(&query
->qSRV
.qname
, &info
->name
);
7779 query
->qSRV
.qtype
= kDNSType_SRV
;
7780 query
->qSRV
.qclass
= kDNSClass_IN
;
7781 query
->qSRV
.LongLived
= mDNSfalse
;
7782 query
->qSRV
.ExpectUnique
= mDNStrue
;
7783 query
->qSRV
.ForceMCast
= mDNSfalse
;
7784 query
->qSRV
.ReturnIntermed
= mDNSfalse
;
7785 query
->qSRV
.QuestionCallback
= FoundServiceInfoSRV
;
7786 query
->qSRV
.QuestionContext
= query
;
7788 query
->qTXT
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7789 query
->qTXT
.InterfaceID
= info
->InterfaceID
;
7790 query
->qTXT
.Target
= zeroAddr
;
7791 AssignDomainName(&query
->qTXT
.qname
, &info
->name
);
7792 query
->qTXT
.qtype
= kDNSType_TXT
;
7793 query
->qTXT
.qclass
= kDNSClass_IN
;
7794 query
->qTXT
.LongLived
= mDNSfalse
;
7795 query
->qTXT
.ExpectUnique
= mDNStrue
;
7796 query
->qTXT
.ForceMCast
= mDNSfalse
;
7797 query
->qTXT
.ReturnIntermed
= mDNSfalse
;
7798 query
->qTXT
.QuestionCallback
= FoundServiceInfoTXT
;
7799 query
->qTXT
.QuestionContext
= query
;
7801 query
->qAv4
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7802 query
->qAv4
.InterfaceID
= info
->InterfaceID
;
7803 query
->qAv4
.Target
= zeroAddr
;
7804 query
->qAv4
.qname
.c
[0] = 0;
7805 query
->qAv4
.qtype
= kDNSType_A
;
7806 query
->qAv4
.qclass
= kDNSClass_IN
;
7807 query
->qAv4
.LongLived
= mDNSfalse
;
7808 query
->qAv4
.ExpectUnique
= mDNStrue
;
7809 query
->qAv4
.ForceMCast
= mDNSfalse
;
7810 query
->qAv4
.ReturnIntermed
= mDNSfalse
;
7811 query
->qAv4
.QuestionCallback
= FoundServiceInfo
;
7812 query
->qAv4
.QuestionContext
= query
;
7814 query
->qAv6
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7815 query
->qAv6
.InterfaceID
= info
->InterfaceID
;
7816 query
->qAv6
.Target
= zeroAddr
;
7817 query
->qAv6
.qname
.c
[0] = 0;
7818 query
->qAv6
.qtype
= kDNSType_AAAA
;
7819 query
->qAv6
.qclass
= kDNSClass_IN
;
7820 query
->qAv6
.LongLived
= mDNSfalse
;
7821 query
->qAv6
.ExpectUnique
= mDNStrue
;
7822 query
->qAv6
.ForceMCast
= mDNSfalse
;
7823 query
->qAv6
.ReturnIntermed
= mDNSfalse
;
7824 query
->qAv6
.QuestionCallback
= FoundServiceInfo
;
7825 query
->qAv6
.QuestionContext
= query
;
7827 query
->GotSRV
= mDNSfalse
;
7828 query
->GotTXT
= mDNSfalse
;
7829 query
->GotADD
= mDNSfalse
;
7833 query
->ServiceInfoQueryCallback
= Callback
;
7834 query
->ServiceInfoQueryContext
= Context
;
7836 // info->name = Must already be set up by client
7837 // info->interface = Must already be set up by client
7838 info
->ip
= zeroAddr
;
7839 info
->port
= zeroIPPort
;
7842 // We use mDNS_StartQuery_internal here because we're already holding the lock
7843 status
= mDNS_StartQuery_internal(m
, &query
->qSRV
);
7844 if (status
== mStatus_NoError
) status
= mDNS_StartQuery_internal(m
, &query
->qTXT
);
7845 if (status
!= mStatus_NoError
) mDNS_StopResolveService(m
, query
);
7851 mDNSexport
void mDNS_StopResolveService (mDNS
*const m
, ServiceInfoQuery
*q
)
7854 // We use mDNS_StopQuery_internal here because we're already holding the lock
7855 if (q
->qSRV
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qSRV
);
7856 if (q
->qTXT
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qTXT
);
7857 if (q
->qAv4
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv4
);
7858 if (q
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv6
);
7862 mDNSexport mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
7863 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
7865 question
->InterfaceID
= InterfaceID
;
7866 question
->Target
= zeroAddr
;
7867 question
->qtype
= kDNSType_PTR
;
7868 question
->qclass
= kDNSClass_IN
;
7869 question
->LongLived
= mDNSfalse
;
7870 question
->ExpectUnique
= mDNSfalse
;
7871 question
->ForceMCast
= mDNSfalse
;
7872 question
->ReturnIntermed
= mDNSfalse
;
7873 question
->QuestionCallback
= Callback
;
7874 question
->QuestionContext
= Context
;
7875 if (DomainType
> mDNS_DomainTypeMax
) return(mStatus_BadParamErr
);
7876 if (!MakeDomainNameFromDNSNameString(&question
->qname
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
7877 if (!dom
) dom
= &localdomain
;
7878 if (!AppendDomainName(&question
->qname
, dom
)) return(mStatus_BadParamErr
);
7879 return(mDNS_StartQuery(m
, question
));
7882 // ***************************************************************************
7883 #if COMPILER_LIKES_PRAGMA_MARK
7885 #pragma mark - Responder Functions
7888 mDNSexport mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
)
7892 status
= mDNS_Register_internal(m
, rr
);
7897 mDNSexport mStatus
mDNS_Update(mDNS
*const m
, AuthRecord
*const rr
, mDNSu32 newttl
,
7898 const mDNSu16 newrdlength
, RData
*const newrdata
, mDNSRecordUpdateCallback
*Callback
)
7900 #ifndef UNICAST_DISABLED
7901 mDNSBool unicast
= !(rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(rr
->resrec
.name
));
7903 mDNSBool unicast
= mDNSfalse
;
7906 if (!ValidateRData(rr
->resrec
.rrtype
, newrdlength
, newrdata
))
7908 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr
->resrec
, &newrdata
->u
, m
->MsgBuffer
));
7909 return(mStatus_Invalid
);
7914 // If TTL is unspecified, leave TTL unchanged
7915 if (newttl
== 0) newttl
= rr
->resrec
.rroriginalttl
;
7917 // If we already have an update queued up which has not gone through yet,
7918 // give the client a chance to free that memory
7919 if (!unicast
&& rr
->NewRData
)
7921 RData
*n
= rr
->NewRData
;
7922 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
7923 if (rr
->UpdateCallback
)
7924 rr
->UpdateCallback(m
, rr
, n
); // ...and let the client free this memory, if necessary
7927 rr
->NewRData
= newrdata
;
7928 rr
->newrdlength
= newrdlength
;
7929 rr
->UpdateCallback
= Callback
;
7931 if (unicast
) { mStatus status
= uDNS_UpdateRecord(m
, rr
); mDNS_Unlock(m
); return(status
); }
7933 if (rr
->resrec
.rroriginalttl
== newttl
&&
7934 rr
->resrec
.rdlength
== newrdlength
&& mDNSPlatformMemSame(rr
->resrec
.rdata
->u
.data
, newrdata
->u
.data
, newrdlength
))
7935 CompleteRDataUpdate(m
, rr
);
7939 domainname type
, domain
;
7940 DeconstructServiceName(rr
->resrec
.name
, &name
, &type
, &domain
);
7941 rr
->AnnounceCount
= InitialAnnounceCount
;
7942 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
7943 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
7944 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
7945 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
7946 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
7947 if (SameDomainLabel(type
.c
, (mDNSu8
*)"\x6_ichat")) rr
->AnnounceCount
= 1;
7948 InitializeLastAPTime(m
, rr
);
7949 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
7950 if (!rr
->UpdateBlocked
&& rr
->UpdateCredits
) rr
->UpdateCredits
--;
7951 if (!rr
->NextUpdateCredit
) rr
->NextUpdateCredit
= NonZeroTime(m
->timenow
+ kUpdateCreditRefreshInterval
);
7952 if (rr
->AnnounceCount
> rr
->UpdateCredits
+ 1) rr
->AnnounceCount
= (mDNSu8
)(rr
->UpdateCredits
+ 1);
7953 if (rr
->UpdateCredits
<= 5)
7955 mDNSu32 delay
= 6 - rr
->UpdateCredits
; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
7956 if (!rr
->UpdateBlocked
) rr
->UpdateBlocked
= NonZeroTime(m
->timenow
+ (mDNSs32
)delay
* mDNSPlatformOneSecond
);
7957 rr
->ThisAPInterval
*= 4;
7958 rr
->LastAPTime
= rr
->UpdateBlocked
- rr
->ThisAPInterval
;
7959 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
7960 rr
->resrec
.name
->c
, delay
, delay
> 1 ? "s" : "");
7962 rr
->resrec
.rroriginalttl
= newttl
;
7966 return(mStatus_NoError
);
7969 // Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
7970 // the record list and/or question list.
7971 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
7972 mDNSexport mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
)
7976 status
= mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
7981 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
7982 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
7984 mDNSlocal NetworkInterfaceInfo
*FindFirstAdvertisedInterface(mDNS
*const m
)
7986 NetworkInterfaceInfo
*intf
;
7987 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
7988 if (intf
->Advertise
) break;
7992 mDNSlocal
void AdvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
7994 char buffer
[MAX_REVERSE_MAPPING_NAME
];
7995 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
7996 if (!primary
) primary
= set
; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
7998 // Send dynamic update for non-linklocal IPv4 Addresses
7999 mDNS_SetupResourceRecord(&set
->RR_A
, mDNSNULL
, set
->InterfaceID
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNS_HostNameCallback
, set
);
8000 mDNS_SetupResourceRecord(&set
->RR_PTR
, mDNSNULL
, set
->InterfaceID
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
8001 mDNS_SetupResourceRecord(&set
->RR_HINFO
, mDNSNULL
, set
->InterfaceID
, kDNSType_HINFO
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
8003 #if ANSWER_REMOTE_HOSTNAME_QUERIES
8004 set
->RR_A
.AllowRemoteQuery
= mDNStrue
;
8005 set
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
8006 set
->RR_HINFO
.AllowRemoteQuery
= mDNStrue
;
8008 // 1. Set up Address record to map from host name ("foo.local.") to IP address
8009 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
8010 AssignDomainName(&set
->RR_A
.namestorage
, &m
->MulticastHostname
);
8011 if (set
->ip
.type
== mDNSAddrType_IPv4
)
8013 set
->RR_A
.resrec
.rrtype
= kDNSType_A
;
8014 set
->RR_A
.resrec
.rdata
->u
.ipv4
= set
->ip
.ip
.v4
;
8015 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8016 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.",
8017 set
->ip
.ip
.v4
.b
[3], set
->ip
.ip
.v4
.b
[2], set
->ip
.ip
.v4
.b
[1], set
->ip
.ip
.v4
.b
[0]);
8019 else if (set
->ip
.type
== mDNSAddrType_IPv6
)
8022 set
->RR_A
.resrec
.rrtype
= kDNSType_AAAA
;
8023 set
->RR_A
.resrec
.rdata
->u
.ipv6
= set
->ip
.ip
.v6
;
8024 for (i
= 0; i
< 16; i
++)
8026 static const char hexValues
[] = "0123456789ABCDEF";
8027 buffer
[i
* 4 ] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] & 0x0F];
8028 buffer
[i
* 4 + 1] = '.';
8029 buffer
[i
* 4 + 2] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] >> 4];
8030 buffer
[i
* 4 + 3] = '.';
8032 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
8035 MakeDomainNameFromDNSNameString(&set
->RR_PTR
.namestorage
, buffer
);
8036 set
->RR_PTR
.AutoTarget
= Target_AutoHost
; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
8037 set
->RR_PTR
.ForceMCast
= mDNStrue
; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
8039 set
->RR_A
.RRSet
= &primary
->RR_A
; // May refer to self
8041 mDNS_Register_internal(m
, &set
->RR_A
);
8042 mDNS_Register_internal(m
, &set
->RR_PTR
);
8044 if (!NO_HINFO
&& m
->HIHardware
.c
[0] > 0 && m
->HISoftware
.c
[0] > 0 && m
->HIHardware
.c
[0] + m
->HISoftware
.c
[0] <= 254)
8046 mDNSu8
*p
= set
->RR_HINFO
.resrec
.rdata
->u
.data
;
8047 AssignDomainName(&set
->RR_HINFO
.namestorage
, &m
->MulticastHostname
);
8048 set
->RR_HINFO
.DependentOn
= &set
->RR_A
;
8049 mDNSPlatformMemCopy(p
, &m
->HIHardware
, 1 + (mDNSu32
)m
->HIHardware
.c
[0]);
8051 mDNSPlatformMemCopy(p
, &m
->HISoftware
, 1 + (mDNSu32
)m
->HISoftware
.c
[0]);
8052 mDNS_Register_internal(m
, &set
->RR_HINFO
);
8056 debugf("Not creating HINFO record: platform support layer provided no information");
8057 set
->RR_HINFO
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
8061 mDNSlocal
void DeadvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8063 NetworkInterfaceInfo
*intf
;
8065 // If we still have address records referring to this one, update them
8066 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
8067 AuthRecord
*A
= primary
? &primary
->RR_A
: mDNSNULL
;
8068 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8069 if (intf
->RR_A
.RRSet
== &set
->RR_A
)
8070 intf
->RR_A
.RRSet
= A
;
8072 // Unregister these records.
8073 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
8074 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
8075 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
8076 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
8077 if (set
->RR_A
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_A
, mDNS_Dereg_normal
);
8078 if (set
->RR_PTR
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_PTR
, mDNS_Dereg_normal
);
8079 if (set
->RR_HINFO
.resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_HINFO
, mDNS_Dereg_normal
);
8082 mDNSexport
void mDNS_SetFQDN(mDNS
*const m
)
8084 domainname newmname
;
8085 NetworkInterfaceInfo
*intf
;
8089 if (!AppendDomainLabel(&newmname
, &m
->hostlabel
)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8090 if (!AppendLiteralLabelString(&newmname
, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8094 if (SameDomainNameCS(&m
->MulticastHostname
, &newmname
)) debugf("mDNS_SetFQDN - hostname unchanged");
8097 AssignDomainName(&m
->MulticastHostname
, &newmname
);
8099 // 1. Stop advertising our address records on all interfaces
8100 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8101 if (intf
->Advertise
) DeadvertiseInterface(m
, intf
);
8103 // 2. Start advertising our address records using the new name
8104 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8105 if (intf
->Advertise
) AdvertiseInterface(m
, intf
);
8108 // 3. Make sure that any AutoTarget SRV records (and the like) get updated
8109 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8110 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8115 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8117 (void)rr
; // Unused parameter
8121 char *msg
= "Unknown result";
8122 if (result
== mStatus_NoError
) msg
= "Name registered";
8123 else if (result
== mStatus_NameConflict
) msg
= "Name conflict";
8124 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8128 if (result
== mStatus_NoError
)
8130 // Notify the client that the host name is successfully registered
8131 if (m
->MainCallback
)
8132 m
->MainCallback(m
, mStatus_NoError
);
8134 else if (result
== mStatus_NameConflict
)
8136 domainlabel oldlabel
= m
->hostlabel
;
8138 // 1. First give the client callback a chance to pick a new name
8139 if (m
->MainCallback
)
8140 m
->MainCallback(m
, mStatus_NameConflict
);
8142 // 2. If the client callback didn't do it, add (or increment) an index ourselves
8143 // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
8144 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
8145 if (SameDomainLabel(m
->hostlabel
.c
, oldlabel
.c
))
8146 IncrementLabelSuffix(&m
->hostlabel
, mDNSfalse
);
8148 // 3. Generate the FQDNs from the hostlabel,
8149 // and make sure all SRV records, etc., are updated to reference our new hostname
8151 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel
.c
, m
->hostlabel
.c
);
8153 else if (result
== mStatus_MemFree
)
8155 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
8156 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
8157 debugf("mDNS_HostNameCallback: MemFree (ignored)");
8160 LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result
, rr
->resrec
.name
->c
);
8163 mDNSlocal
void UpdateInterfaceProtocols(mDNS
*const m
, NetworkInterfaceInfo
*active
)
8165 NetworkInterfaceInfo
*intf
;
8166 active
->IPv4Available
= mDNSfalse
;
8167 active
->IPv6Available
= mDNSfalse
;
8168 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8169 if (intf
->InterfaceID
== active
->InterfaceID
)
8171 if (intf
->ip
.type
== mDNSAddrType_IPv4
&& intf
->McastTxRx
) active
->IPv4Available
= mDNStrue
;
8172 if (intf
->ip
.type
== mDNSAddrType_IPv6
&& intf
->McastTxRx
) active
->IPv6Available
= mDNStrue
;
8176 mDNSlocal
void RestartRecordGetZoneData(mDNS
* const m
)
8179 ServiceRecordSet
*s
;
8181 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8182 if (AuthRecord_uDNS(rr
))
8184 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr
->resrec
.name
->c
);
8185 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
8186 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
8189 for (s
= m
->ServiceRegistrations
; s
; s
= s
->uDNS_next
)
8191 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s
->RR_SRV
.resrec
.name
->c
);
8192 if (s
->srs_nta
) CancelGetZoneData(m
, s
->srs_nta
);
8193 s
->srs_nta
= StartGetZoneData(m
, s
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, s
);
8197 mDNSlocal
void InitializeNetWakeState(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8200 set
->NetWakeBrowse
.ThisQInterval
= -1;
8203 set
->NetWakeResolve
[i
].ThisQInterval
= -1;
8204 set
->SPSAddr
[i
].type
= mDNSAddrType_None
;
8206 set
->NextSPSAttempt
= -1;
8207 set
->NextSPSAttemptTime
= m
->timenow
;
8210 mDNSexport
void mDNS_ActivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8212 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8213 while (p
&& p
!= set
) p
=p
->next
;
8214 if (!p
) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8216 if (set
->InterfaceActive
)
8218 LogSPS("ActivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8219 mDNS_StartBrowse_internal(m
, &set
->NetWakeBrowse
, &SleepProxyServiceType
, &localdomain
, set
->InterfaceID
, mDNSfalse
, m
->SPSBrowseCallback
, set
);
8223 mDNSexport
void mDNS_DeactivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8225 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8226 while (p
&& p
!= set
) p
=p
->next
;
8227 if (!p
) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8229 if (set
->NetWakeBrowse
.ThisQInterval
>= 0)
8232 LogSPS("DeactivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8234 // Stop our browse and resolve operations
8235 mDNS_StopQuery_internal(m
, &set
->NetWakeBrowse
);
8236 for (i
=0; i
<3; i
++) if (set
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &set
->NetWakeResolve
[i
]);
8238 // Make special call to the browse callback to let it know it can to remove all records for this interface
8239 if (m
->SPSBrowseCallback
) m
->SPSBrowseCallback(m
, &set
->NetWakeBrowse
, mDNSNULL
, mDNSfalse
);
8241 // Reset our variables back to initial state, so we're ready for when NetWake is turned back on
8242 // (includes resetting NetWakeBrowse.ThisQInterval back to -1)
8243 InitializeNetWakeState(m
, set
);
8247 mDNSexport mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8250 mDNSBool FirstOfType
= mDNStrue
;
8251 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8253 if (!set
->InterfaceID
)
8254 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set
->ip
); return(mStatus_Invalid
); }
8256 if (!mDNSAddressIsValidNonZero(&set
->mask
))
8257 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set
->ip
, &set
->mask
); return(mStatus_Invalid
); }
8261 // Assume this interface will be active now, unless we find a duplicate already in the list
8262 set
->InterfaceActive
= mDNStrue
;
8263 set
->IPv4Available
= (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
);
8264 set
->IPv6Available
= (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
);
8266 InitializeNetWakeState(m
, set
);
8268 // Scan list to see if this InterfaceID is already represented
8273 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
8275 return(mStatus_AlreadyRegistered
);
8278 if ((*p
)->InterfaceID
== set
->InterfaceID
)
8280 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
8281 set
->InterfaceActive
= mDNSfalse
;
8282 if (set
->ip
.type
== (*p
)->ip
.type
) FirstOfType
= mDNSfalse
;
8283 if (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
) (*p
)->IPv4Available
= mDNStrue
;
8284 if (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
) (*p
)->IPv6Available
= mDNStrue
;
8290 set
->next
= mDNSNULL
;
8294 AdvertiseInterface(m
, set
);
8296 LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set
->InterfaceID
, set
->ifname
, &set
->ip
,
8297 set
->InterfaceActive
?
8298 "not represented in list; marking active and retriggering queries" :
8299 "already represented in list; marking inactive for now");
8301 if (set
->NetWake
) mDNS_ActivateNetWake_internal(m
, set
);
8303 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8304 // giving the false impression that there's an active representative of this interface when there really isn't.
8305 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
8306 // even if we believe that we previously had an active representative of this interface.
8307 if (set
->McastTxRx
&& ((m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) || FirstOfType
|| set
->InterfaceActive
))
8310 // If flapping, delay between first and second queries is eight seconds instead of one
8311 mDNSs32 delay
= flapping
? mDNSPlatformOneSecond
* 5 : 0;
8312 mDNSu8 announce
= flapping
? (mDNSu8
)1 : InitialAnnounceCount
;
8315 // Use a small amount of randomness:
8316 // In the case of a network administrator turning on an Ethernet hub so that all the
8317 // connected machines establish link at exactly the same time, we don't want them all
8318 // to go and hit the network with identical queries at exactly the same moment.
8319 newSS
= m
->timenow
+ (mDNSs32
)mDNSRandom((mDNSu32
)InitialQuestionInterval
);
8320 #if APPLE_OSX_mDNSResponder
8321 // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
8322 // of network change notifications in a row, and we don't know when we're done getting notified.
8323 // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
8324 newSS
+= mDNSPlatformOneSecond
* 2;
8326 if (!m
->SuppressSending
|| newSS
- m
->SuppressSending
< 0) m
->SuppressSending
= newSS
;
8330 LogMsg("Note: RegisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
8331 set
->ifname
, &set
->ip
);
8332 if (!m
->SuppressProbes
||
8333 m
->SuppressProbes
- (m
->timenow
+ delay
) < 0)
8334 m
->SuppressProbes
= (m
->timenow
+ delay
);
8337 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
8338 if (mDNSOpaque16IsZero(q
->TargetQID
))
8339 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
) // If non-specific Q, or Q on this specific interface,
8340 { // then reactivate this question
8341 mDNSBool dodelay
= flapping
&& (q
->FlappingInterface1
== set
->InterfaceID
|| q
->FlappingInterface2
== set
->InterfaceID
);
8342 mDNSs32 initial
= dodelay
? InitialQuestionInterval
* QuestionIntervalStep2
: InitialQuestionInterval
;
8343 mDNSs32 qdelay
= dodelay
? mDNSPlatformOneSecond
* 5 : 0;
8344 if (dodelay
) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q
->qname
.c
, DNSTypeName(q
->qtype
));
8346 if (!q
->ThisQInterval
|| q
->ThisQInterval
> initial
)
8348 q
->ThisQInterval
= initial
;
8349 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
8351 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ qdelay
;
8352 q
->RecentAnswerPkts
= 0;
8353 SetNextQueryTime(m
,q
);
8356 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
8357 // we now need them to re-probe if necessary, and then re-announce.
8358 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8359 if (!AuthRecord_uDNS(rr
))
8360 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8362 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
8363 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
8364 if (rr
->AnnounceCount
< announce
) rr
->AnnounceCount
= announce
;
8365 InitializeLastAPTime(m
, rr
);
8369 RestartRecordGetZoneData(m
);
8372 return(mStatus_NoError
);
8375 // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
8376 // the record list and/or question list.
8377 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8378 mDNSexport
void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8380 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8382 mDNSBool revalidate
= mDNSfalse
;
8383 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
8384 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
8385 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
8386 if (m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) revalidate
= mDNStrue
;
8390 // Find this record in our list
8391 while (*p
&& *p
!= set
) p
=&(*p
)->next
;
8392 if (!*p
) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m
); return; }
8394 mDNS_DeactivateNetWake_internal(m
, set
);
8396 // Unlink this record from our list
8398 set
->next
= mDNSNULL
;
8400 if (!set
->InterfaceActive
)
8402 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
8403 NetworkInterfaceInfo
*intf
;
8404 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8405 if (intf
->InterfaceActive
&& intf
->InterfaceID
== set
->InterfaceID
)
8406 UpdateInterfaceProtocols(m
, intf
);
8410 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, set
->InterfaceID
);
8413 LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
8414 " making it active", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8415 if (intf
->InterfaceActive
)
8416 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set
->ifname
, &set
->ip
);
8417 intf
->InterfaceActive
= mDNStrue
;
8418 UpdateInterfaceProtocols(m
, intf
);
8420 if (intf
->NetWake
) mDNS_ActivateNetWake_internal(m
, intf
);
8422 // See if another representative *of the same type* exists. If not, we mave have gone from
8423 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
8424 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8425 if (intf
->InterfaceID
== set
->InterfaceID
&& intf
->ip
.type
== set
->ip
.type
)
8427 if (!intf
) revalidate
= mDNStrue
;
8437 LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
8438 " marking questions etc. dormant", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8441 LogMsg("Note: DeregisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
8442 set
->ifname
, &set
->ip
);
8444 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
8445 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
8446 for (q
= m
->Questions
; q
; q
=q
->next
)
8448 if (q
->InterfaceID
== set
->InterfaceID
) q
->ThisQInterval
= 0;
8449 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
)
8451 q
->FlappingInterface2
= q
->FlappingInterface1
;
8452 q
->FlappingInterface1
= set
->InterfaceID
; // Keep history of the last two interfaces to go away
8456 // 2. Flush any cache records received on this interface
8457 revalidate
= mDNSfalse
; // Don't revalidate if we're flushing the records
8458 FORALL_CACHERECORDS(slot
, cg
, rr
)
8459 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8461 // If this interface is deemed flapping,
8462 // postpone deleting the cache records in case the interface comes back again
8463 if (!flapping
) mDNS_PurgeCacheResourceRecord(m
, rr
);
8466 // We want these record to go away in 30 seconds
8467 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
8468 // if the interface does come back, any relevant questions will be reactivated anyway
8469 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8470 rr
->UnansweredQueries
= MaxUnansweredQueries
;
8474 // 3. Any DNS servers specific to this interface are now unusable
8475 for (s
= m
->DNSServers
; s
; s
= s
->next
)
8476 if (s
->interface
== set
->InterfaceID
)
8478 s
->interface
= mDNSInterface_Any
;
8479 s
->teststate
= DNSServer_Disabled
;
8484 // If we were advertising on this interface, deregister those address and reverse-lookup records now
8485 if (set
->Advertise
) DeadvertiseInterface(m
, set
);
8487 // If we have any cache records received on this interface that went away, then re-verify them.
8488 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8489 // giving the false impression that there's an active representative of this interface when there really isn't.
8490 // Don't need to do this when shutting down, because *all* interfaces are about to go away
8491 if (revalidate
&& !m
->ShutdownTime
)
8496 m
->NextCacheCheck
= m
->timenow
;
8497 FORALL_CACHERECORDS(slot
, cg
, rr
)
8498 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8499 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8505 mDNSlocal
void ServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8507 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8508 (void)m
; // Unused parameter
8512 char *msg
= "Unknown result";
8513 if (result
== mStatus_NoError
) msg
= "Name Registered";
8514 else if (result
== mStatus_NameConflict
) msg
= "Name Conflict";
8515 else if (result
== mStatus_MemFree
) msg
= "Memory Free";
8516 debugf("ServiceCallback: %##s (%s) %s (%d)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8520 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
8521 if (result
== mStatus_NoError
&& rr
!= &sr
->RR_SRV
) return;
8523 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
8524 if (result
== mStatus_NameConflict
)
8526 sr
->Conflict
= mDNStrue
; // Record that this service set had a conflict
8527 mDNS_DeregisterService(m
, sr
); // Unlink the records from our list
8531 if (result
== mStatus_MemFree
)
8533 // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
8534 // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
8535 // every record is finished cleaning up.
8537 if (sr
->RR_SRV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8538 if (sr
->RR_TXT
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8539 if (sr
->RR_PTR
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8540 if (sr
->RR_ADV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8541 for (i
=0; i
<sr
->NumSubTypes
; i
++) if (sr
->SubTypes
[i
].resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8543 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
8544 // then we can now report the NameConflict to the client
8545 if (sr
->Conflict
) result
= mStatus_NameConflict
;
8549 LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m
, &sr
->RR_SRV
));
8550 CancelGetZoneData(m
, sr
->srs_nta
);
8551 sr
->srs_nta
= mDNSNULL
;
8555 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
8556 // function is allowed to do anything, including deregistering this service and freeing its memory.
8557 if (sr
->ServiceCallback
)
8558 sr
->ServiceCallback(m
, sr
, result
);
8561 mDNSlocal
void NSSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8563 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8564 if (sr
->ServiceCallback
)
8565 sr
->ServiceCallback(m
, sr
, result
);
8568 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8569 mDNSlocal mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
8572 ServiceRecordSet
**p
= &m
->ServiceRegistrations
;
8573 while (*p
&& *p
!= srs
) p
=&(*p
)->uDNS_next
;
8574 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
->c
); return(mStatus_AlreadyRegistered
); }
8576 srs
->uDNS_next
= mDNSNULL
;
8579 srs
->RR_SRV
.resrec
.rroriginalttl
= kHostNameTTL
;
8580 srs
->RR_TXT
.resrec
.rroriginalttl
= kStandardTTL
;
8581 srs
->RR_PTR
.resrec
.rroriginalttl
= kStandardTTL
;
8582 for (i
= 0; i
< srs
->NumSubTypes
;i
++) srs
->SubTypes
[i
].resrec
.rroriginalttl
= kStandardTTL
;
8584 srs
->srs_uselease
= mDNStrue
;
8586 if (srs
->RR_SRV
.AutoTarget
)
8588 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
8589 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
8590 // with the port number in our advertised SRV record automatically tracking the external mapped port.
8591 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
8592 if (!AuthInfo
|| !AuthInfo
->AutoTunnel
) srs
->RR_SRV
.AutoTarget
= Target_AutoHostAndNATMAP
;
8595 if (!GetServiceTarget(m
, &srs
->RR_SRV
))
8597 // defer registration until we've got a target
8598 LogInfo("uDNS_RegisterService - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
8599 srs
->state
= regState_NoTarget
;
8600 return mStatus_NoError
;
8603 ActivateUnicastRegistration(m
, &srs
->RR_SRV
);
8604 srs
->state
= regState_FetchingZoneData
;
8605 return mStatus_NoError
;
8610 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
8611 // Type is service type (e.g. "_ipp._tcp.")
8612 // Domain is fully qualified domain name (i.e. ending with a null label)
8613 // We always register a TXT, even if it is empty (so that clients are not
8614 // left waiting forever looking for a nonexistent record.)
8615 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
8616 // then the default host name (m->MulticastHostname) is automatically used
8617 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
8618 mDNSexport mStatus
mDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*sr
,
8619 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
8620 const domainname
*const host
, mDNSIPPort port
, const mDNSu8 txtinfo
[], mDNSu16 txtlen
,
8621 AuthRecord
*SubTypes
, mDNSu32 NumSubTypes
,
8622 const mDNSInterfaceID InterfaceID
, mDNSServiceCallback Callback
, void *Context
)
8627 sr
->state
= regState_Zero
;
8628 sr
->srs_uselease
= 0;
8629 sr
->TestForSelfConflict
= 0;
8633 sr
->SRSUpdateServer
= zeroAddr
;
8634 sr
->SRSUpdatePort
= zeroIPPort
;
8635 mDNSPlatformMemZero(&sr
->NATinfo
, sizeof(sr
->NATinfo
));
8636 sr
->NATinfo
.IntPort
= port
; // Record originally-requested port
8637 sr
->ClientCallbackDeferred
= 0;
8638 sr
->DeferredStatus
= 0;
8639 sr
->SRVUpdateDeferred
= 0;
8643 sr
->ServiceCallback
= Callback
;
8644 sr
->ServiceContext
= Context
;
8645 sr
->Conflict
= mDNSfalse
;
8647 sr
->Extras
= mDNSNULL
;
8648 sr
->NumSubTypes
= NumSubTypes
;
8649 sr
->SubTypes
= SubTypes
;
8651 // Initialize the AuthRecord objects to sane values
8652 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
8653 mDNS_SetupResourceRecord(&sr
->RR_ADV
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeAdvisory
, ServiceCallback
, sr
);
8654 mDNS_SetupResourceRecord(&sr
->RR_PTR
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
8655 mDNS_SetupResourceRecord(&sr
->RR_SRV
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8656 mDNS_SetupResourceRecord(&sr
->RR_TXT
, mDNSNULL
, InterfaceID
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8658 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
8659 if (mDNSIPPortIsZero(port
))
8660 return(mDNS_RegisterNoSuchService(m
, &sr
->RR_SRV
, name
, type
, domain
, mDNSNULL
, mDNSInterface_Any
, NSSCallback
, sr
));
8662 // If the client is registering an oversized TXT record,
8663 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
8664 if (sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
< txtlen
)
8665 sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
= txtlen
;
8667 // Set up the record names
8668 // For now we only create an advisory record for the main type, not for subtypes
8669 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
8670 if (ConstructServiceName(&sr
->RR_ADV
.namestorage
, (const domainlabel
*)"\x09_services", (const domainname
*)"\x07_dns-sd\x04_udp", domain
) == mDNSNULL
)
8671 return(mStatus_BadParamErr
);
8672 if (ConstructServiceName(&sr
->RR_PTR
.namestorage
, mDNSNULL
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8673 if (ConstructServiceName(&sr
->RR_SRV
.namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8674 AssignDomainName(&sr
->RR_TXT
.namestorage
, sr
->RR_SRV
.resrec
.name
);
8676 // 1. Set up the ADV record rdata to advertise our service type
8677 AssignDomainName(&sr
->RR_ADV
.resrec
.rdata
->u
.name
, sr
->RR_PTR
.resrec
.name
);
8679 // 2. Set up the PTR record rdata to point to our service name
8680 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
8681 AssignDomainName(&sr
->RR_PTR
.resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
8682 sr
->RR_PTR
.Additional1
= &sr
->RR_SRV
;
8683 sr
->RR_PTR
.Additional2
= &sr
->RR_TXT
;
8685 // 2a. Set up any subtype PTRs to point to our service name
8686 // If the client is using subtypes, it is the client's responsibility to have
8687 // already set the first label of the record name to the subtype being registered
8688 for (i
=0; i
<NumSubTypes
; i
++)
8691 AssignDomainName(&st
, sr
->SubTypes
[i
].resrec
.name
);
8692 st
.c
[1+st
.c
[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
8693 AppendDomainName(&st
, type
);
8694 mDNS_SetupResourceRecord(&sr
->SubTypes
[i
], mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
8695 if (ConstructServiceName(&sr
->SubTypes
[i
].namestorage
, mDNSNULL
, &st
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8696 AssignDomainName(&sr
->SubTypes
[i
].resrec
.rdata
->u
.name
, &sr
->RR_SRV
.namestorage
);
8697 sr
->SubTypes
[i
].Additional1
= &sr
->RR_SRV
;
8698 sr
->SubTypes
[i
].Additional2
= &sr
->RR_TXT
;
8701 // 3. Set up the SRV record rdata.
8702 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.priority
= 0;
8703 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.weight
= 0;
8704 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= port
;
8706 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
8707 if (host
&& host
->c
[0]) AssignDomainName(&sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, host
);
8708 else { sr
->RR_SRV
.AutoTarget
= Target_AutoHost
; sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0'; }
8710 // 4. Set up the TXT record rdata,
8711 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
8712 if (txtinfo
== mDNSNULL
) sr
->RR_TXT
.resrec
.rdlength
= 0;
8713 else if (txtinfo
!= sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
)
8715 sr
->RR_TXT
.resrec
.rdlength
= txtlen
;
8716 if (sr
->RR_TXT
.resrec
.rdlength
> sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
) return(mStatus_BadParamErr
);
8717 mDNSPlatformMemCopy(sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, txtinfo
, txtlen
);
8719 sr
->RR_TXT
.DependentOn
= &sr
->RR_SRV
;
8721 sr
->srs_nta
= mDNSNULL
;
8723 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8724 // If the client has specified an explicit InterfaceID,
8725 // then we do a multicast registration on that interface, even for unicast domains.
8726 if (!(InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&sr
->RR_SRV
.namestorage
)))
8730 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
8731 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
8732 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
8733 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
8734 if (!sr
->RR_TXT
.resrec
.rdlength
) { sr
->RR_TXT
.resrec
.rdlength
= 1; sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
[0] = 0; }
8736 status
= uDNS_RegisterService(m
, sr
);
8743 err
= mDNS_Register_internal(m
, &sr
->RR_SRV
);
8744 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_TXT
);
8745 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
8746 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
8747 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
8748 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
8749 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
8750 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_ADV
);
8751 for (i
=0; i
<NumSubTypes
; i
++) if (!err
) err
= mDNS_Register_internal(m
, &sr
->SubTypes
[i
]);
8752 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_PTR
);
8756 if (err
) mDNS_DeregisterService(m
, sr
);
8760 mDNSlocal
void DummyCallback(mDNS
*const m
, AuthRecord
*rr
, mStatus result
)
8764 (void)result
; // Unused
8765 LogInfo("DummyCallback %d %s", result
, ARDisplayString(m
, rr
));
8768 mDNSexport mStatus
mDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
,
8769 ExtraResourceRecord
*extra
, RData
*rdata
, mDNSu32 ttl
)
8771 ExtraResourceRecord
**e
;
8774 extra
->next
= mDNSNULL
;
8775 mDNS_SetupResourceRecord(&extra
->r
, rdata
, sr
->RR_PTR
.resrec
.InterfaceID
,
8776 extra
->r
.resrec
.rrtype
, ttl
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8777 AssignDomainName(&extra
->r
.namestorage
, sr
->RR_SRV
.resrec
.name
);
8781 while (*e
) e
= &(*e
)->next
;
8783 if (ttl
== 0) ttl
= kStandardTTL
;
8785 extra
->r
.DependentOn
= &sr
->RR_SRV
;
8787 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
8788 extra
->r
.resrec
.name
->c
, DNSTypeName(extra
->r
.resrec
.rrtype
), extra
->r
.resrec
.rdlength
);
8790 status
= mDNS_Register_internal(m
, &extra
->r
);
8791 if (status
== mStatus_NoError
)
8794 #ifndef UNICAST_DISABLED
8795 if (AuthRecord_uDNS(&sr
->RR_SRV
))
8797 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name (???)
8798 extra
->r
.RecordCallback
= DummyCallback
; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
8799 if (sr
->state
!= regState_Registered
&& sr
->state
!= regState_Refresh
) extra
->r
.state
= regState_ExtraQueued
;
8808 mDNSexport mStatus
mDNS_RemoveRecordFromService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
,
8809 mDNSRecordCallback MemFreeCallback
, void *Context
)
8811 ExtraResourceRecord
**e
;
8816 while (*e
&& *e
!= extra
) e
= &(*e
)->next
;
8819 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra
->r
.resrec
.name
->c
);
8820 status
= mStatus_BadReferenceErr
;
8824 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra
->r
.resrec
.name
->c
);
8825 extra
->r
.RecordCallback
= MemFreeCallback
;
8826 extra
->r
.RecordContext
= Context
;
8828 status
= mDNS_Deregister_internal(m
, &extra
->r
, mDNS_Dereg_normal
);
8834 mDNSexport mStatus
mDNS_RenameAndReregisterService(mDNS
*const m
, ServiceRecordSet
*const sr
, const domainlabel
*newname
)
8836 // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
8837 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
8838 domainlabel name1
, name2
;
8839 domainname type
, domain
;
8840 const domainname
*host
= sr
->RR_SRV
.AutoTarget
? mDNSNULL
: &sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
8841 ExtraResourceRecord
*extras
= sr
->Extras
;
8844 DeconstructServiceName(sr
->RR_SRV
.resrec
.name
, &name1
, &type
, &domain
);
8848 IncrementLabelSuffix(&name2
, mDNStrue
);
8852 if (SameDomainName(&domain
, &localdomain
))
8853 debugf("%##s service renamed from \"%#s\" to \"%#s\"", type
.c
, name1
.c
, newname
->c
);
8854 else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type
.c
, domain
.c
, name1
.c
, newname
->c
);
8856 err
= mDNS_RegisterService(m
, sr
, newname
, &type
, &domain
,
8857 host
, sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
, sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, sr
->RR_TXT
.resrec
.rdlength
,
8858 sr
->SubTypes
, sr
->NumSubTypes
,
8859 sr
->RR_PTR
.resrec
.InterfaceID
, sr
->ServiceCallback
, sr
->ServiceContext
);
8861 // mDNS_RegisterService() just reset sr->Extras to NULL.
8862 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
8863 // through the old list of extra records, and re-add them to our freshly created service registration
8864 while (!err
&& extras
)
8866 ExtraResourceRecord
*e
= extras
;
8867 extras
= extras
->next
;
8868 err
= mDNS_AddRecordToService(m
, sr
, e
, e
->r
.resrec
.rdata
, e
->r
.resrec
.rroriginalttl
);
8874 // Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
8875 // which may change the record list and/or question list.
8876 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8877 mDNSexport mStatus
mDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*sr
)
8879 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
8880 if (mDNSIPPortIsZero(sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
)) return(mDNS_DeregisterNoSuchService(m
, &sr
->RR_SRV
));
8882 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8883 if (!(sr
->RR_SRV
.resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(sr
->RR_SRV
.resrec
.name
)))
8887 status
= uDNS_DeregisterService(m
, sr
);
8892 if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
8894 debugf("Service set for %##s already deregistered", sr
->RR_SRV
.resrec
.name
->c
);
8895 return(mStatus_BadReferenceErr
);
8897 else if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeDeregistering
)
8899 debugf("Service set for %##s already in the process of deregistering", sr
->RR_SRV
.resrec
.name
->c
);
8900 // Avoid race condition:
8901 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
8902 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
8903 // If the client happens to deregister the service in the middle of that process, then
8904 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
8905 // instead of incorrectly promoting it to mStatus_NameConflict.
8906 // This race condition is exposed particularly when the conformance test generates
8907 // a whole batch of simultaneous conflicts across a range of services all advertised
8908 // using the same system default name, and if we don't take this precaution then
8909 // we end up incrementing m->nicelabel multiple times instead of just once.
8910 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
8911 sr
->Conflict
= mDNSfalse
;
8912 return(mStatus_NoError
);
8918 ExtraResourceRecord
*e
;
8922 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
8923 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
8924 mDNS_Deregister_internal(m
, &sr
->RR_SRV
, mDNS_Dereg_repeat
);
8925 mDNS_Deregister_internal(m
, &sr
->RR_TXT
, mDNS_Dereg_repeat
);
8927 mDNS_Deregister_internal(m
, &sr
->RR_ADV
, mDNS_Dereg_normal
);
8929 // We deregister all of the extra records, but we leave the sr->Extras list intact
8930 // in case the client wants to do a RenameAndReregister and reinstate the registration
8933 mDNS_Deregister_internal(m
, &e
->r
, mDNS_Dereg_repeat
);
8937 for (i
=0; i
<sr
->NumSubTypes
; i
++)
8938 mDNS_Deregister_internal(m
, &sr
->SubTypes
[i
], mDNS_Dereg_normal
);
8940 // Be sure to deregister the PTR last!
8941 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
8942 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
8943 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
8944 // we've deregistered all our records and done any other necessary cleanup before that happens.
8945 status
= mDNS_Deregister_internal(m
, &sr
->RR_PTR
, mDNS_Dereg_normal
);
8951 // Create a registration that asserts that no such service exists with this name.
8952 // This can be useful where there is a given function is available through several protocols.
8953 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
8954 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
8955 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
8956 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
8957 mDNSexport mStatus
mDNS_RegisterNoSuchService(mDNS
*const m
, AuthRecord
*const rr
,
8958 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
8959 const domainname
*const host
,
8960 const mDNSInterfaceID InterfaceID
, mDNSRecordCallback Callback
, void *Context
)
8962 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, Callback
, Context
);
8963 if (ConstructServiceName(&rr
->namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
8964 rr
->resrec
.rdata
->u
.srv
.priority
= 0;
8965 rr
->resrec
.rdata
->u
.srv
.weight
= 0;
8966 rr
->resrec
.rdata
->u
.srv
.port
= zeroIPPort
;
8967 if (host
&& host
->c
[0]) AssignDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, host
);
8968 else rr
->AutoTarget
= Target_AutoHost
;
8969 return(mDNS_Register(m
, rr
));
8972 mDNSexport mStatus
mDNS_AdvertiseDomains(mDNS
*const m
, AuthRecord
*rr
,
8973 mDNS_DomainType DomainType
, const mDNSInterfaceID InterfaceID
, char *domname
)
8975 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
8976 if (!MakeDomainNameFromDNSNameString(&rr
->namestorage
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
8977 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.rdata
->u
.name
, domname
)) return(mStatus_BadParamErr
);
8978 return(mDNS_Register(m
, rr
));
8981 mDNSexport mDNSOpaque16
mDNS_NewMessageID(mDNS
* const m
)
8985 for (i
=0; i
<10; i
++)
8989 id
= mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
8990 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (mDNSSameOpaque16(id
, r
->updateid
)) continue;
8991 for (q
= m
->Questions
; q
; q
=q
->next
) if (mDNSSameOpaque16(id
, q
->TargetQID
)) continue;
8994 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id
));
8998 // ***************************************************************************
8999 #if COMPILER_LIKES_PRAGMA_MARK
9001 #pragma mark - Sleep Proxy Server
9004 mDNSlocal
void RestartProbing(mDNS
*const m
, AuthRecord
*const rr
)
9006 // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
9007 // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
9008 // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
9009 // then we'll transition out of probing state and start answering ARPs again.
9010 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
9011 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
9012 rr
->AnnounceCount
= InitialAnnounceCount
;
9013 InitializeLastAPTime(m
, rr
);
9016 mDNSexport
void mDNSCoreReceiveRawPacket(mDNS
*const m
, const mDNSu8
*const p
, const mDNSu8
*const end
, const mDNSInterfaceID InterfaceID
)
9018 static const mDNSOpaque16 Ethertype_IP
= { { 0x08, 0x00 } };
9019 static const mDNSOpaque32 ARP_EthIP_h0
= { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
9020 static const mDNSOpaque32 ARP_EthIP_h1
= { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen
9021 static const mDNSOpaque16 ARP_op_request
= { { 0, 1 } };
9022 const EthernetHeader
*const eth
= (const EthernetHeader
*)p
;
9023 const ARP_EthIP
*const arp
= (const ARP_EthIP
*)(eth
+1);
9024 const IPv4Header
*const v4
= (const IPv4Header
*)(eth
+1);
9025 const IPv6Header
*const v6
= (const IPv6Header
*)(eth
+1);
9026 if (end
>= p
+42 && *(mDNSu32
*)(p
+12) == ARP_EthIP_h0
.NotAnInteger
&& *(mDNSu32
*)(p
+16) == ARP_EthIP_h1
.NotAnInteger
)
9029 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
9032 debugf("Got ARP from %.4a/%.6a for %.4a", &arp
->spa
, &arp
->sha
, &arp
->tpa
);
9037 // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
9038 // We also process and answer ARPs from our own kernel (no special treatment for localhost).
9039 // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
9040 // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below.
9041 if (mDNSSameOpaque16(arp
->op
, ARP_op_request
) && !mDNSSameIPv4Address(arp
->spa
, arp
->tpa
))
9042 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9043 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->tpa
))
9045 static const char msg1
[] = "ARP Req from owner -- re-probing";
9046 static const char msg2
[] = "Ignoring ARP Request from ";
9047 static const char msg3
[] = "Creating Local ARP Cache entry ";
9048 static const char msg4
[] = "Answering ARP Request from ";
9049 const char *const msg
= mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
) ? msg1
:
9050 (rr
->AnnounceCount
== InitialAnnounceCount
) ? msg2
:
9051 mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
) ? msg3
: msg4
;
9052 LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
9053 InterfaceNameForID(m
, InterfaceID
), msg
, &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9054 if (msg
== msg1
) RestartProbing(m
, rr
);
9055 else if (msg
== msg3
) mDNSPlatformSetLocalARP(&arp
->tpa
, &rr
->WakeUp
.IMAC
, InterfaceID
);
9056 else if (msg
== msg4
) SendARP(m
, 2, rr
, arp
->tpa
.b
, arp
->sha
.b
, arp
->spa
.b
, arp
->sha
.b
);
9060 // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
9061 // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
9062 // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
9063 // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
9064 // If we see an apparently conflicting ARP, we check the sender hardware address:
9065 // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
9066 // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
9067 if (mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
))
9068 debugf("ARP from self for %.4a", &arp
->tpa
);
9071 if (!mDNSSameIPv4Address(arp
->spa
, zerov4Addr
))
9072 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9073 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->spa
))
9075 RestartProbing(m
, rr
);
9076 if (mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
))
9077 LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
9078 InterfaceNameForID(m
, InterfaceID
),
9079 mDNSSameIPv4Address(arp
->spa
, arp
->tpa
) ? "Announcement" : mDNSSameOpaque16(arp
->op
, ARP_op_request
) ? "Request " : "Response ",
9080 &arp
->sha
, &arp
->spa
, &arp
->tpa
, ARDisplayString(m
, rr
));
9083 LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
9084 InterfaceNameForID(m
, InterfaceID
), &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9085 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9092 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9094 const mDNSu8
*const trans
= p
+ 14 + (v4
->vlen
& 0xF) * 4;
9095 const mDNSu8
*const required
= trans
+ (v4
->protocol
== 1 ? 4 : v4
->protocol
== 6 ? 20 : v4
->protocol
== 17 ? 8 : 0);
9096 debugf("Got IPv4 from %.4a to %.4a", &v4
->src
, &v4
->dst
);
9097 if (end
>= required
)
9099 #define SSH_AsNumber 22
9100 #define ARD_AsNumber 3283
9101 #define IPSEC_AsNumber 4500
9102 static const mDNSIPPort SSH
= { { SSH_AsNumber
>> 8, SSH_AsNumber
& 0xFF } };
9103 static const mDNSIPPort ARD
= { { ARD_AsNumber
>> 8, ARD_AsNumber
& 0xFF } };
9104 static const mDNSIPPort IPSEC
= { { IPSEC_AsNumber
>> 8, IPSEC_AsNumber
& 0xFF } };
9106 mDNSBool wake
= mDNSfalse
;
9107 mDNSIPPort port
= zeroIPPort
;
9109 switch (v4
->protocol
)
9111 #define XX wake ? "Received" : "Ignoring", end-p
9112 case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX
, &v4
->src
, &v4
->dst
);
9116 const TCPHeader
*const tcp
= (const TCPHeader
*)trans
;
9120 // (a) RST is not set, AND
9121 // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
9122 wake
= (!(tcp
->flags
& 4) && (tcp
->flags
& 3) != 1);
9124 // For now, to reduce spurious wakeups, we wake only for TCP SYN,
9125 // except for ssh connections, where we'll wake for plain data packets too
9126 if (!mDNSSameIPPort(port
, SSH
) && !(tcp
->flags
& 2)) wake
= mDNSfalse
;
9128 LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX
,
9129 &v4
->src
, mDNSVal16(tcp
->src
), &v4
->dst
, mDNSVal16(port
),
9130 (tcp
->flags
& 2) ? " SYN" : "",
9131 (tcp
->flags
& 1) ? " FIN" : "",
9132 (tcp
->flags
& 4) ? " RST" : "");
9137 const UDPHeader
*const udp
= (const UDPHeader
*)trans
;
9138 mDNSu16 len
= (mDNSu16
)((mDNSu16
)trans
[4] << 8 | trans
[5]);
9142 // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
9143 if (mDNSSameIPPort(port
, IPSEC
)) wake
= (len
!= 9 || end
< trans
+ 9 || trans
[8] != 0xFF);
9145 // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
9146 // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
9147 // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
9148 // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
9149 if (mDNSSameIPPort(port
, ARD
)) wake
= (len
>= 118 && end
>= trans
+10 && trans
[8] == 0x13 && trans
[9] == 0x88);
9151 LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX
, &v4
->src
, mDNSVal16(udp
->src
), &v4
->dst
, mDNSVal16(port
));
9155 default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX
, v4
->protocol
, &v4
->src
, &v4
->dst
);
9161 AuthRecord
*rr
, *r2
;
9164 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9165 if (rr
->resrec
.InterfaceID
== InterfaceID
&&
9166 rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, v4
->dst
))
9168 const mDNSu8
*const tp
= (v4
->protocol
== 6) ? (mDNSu8
*)"\x4_tcp" : (mDNSu8
*)"\x4_udp";
9169 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
9170 if (r2
->resrec
.InterfaceID
== InterfaceID
&& mDNSSameEthAddress(&r2
->WakeUp
.HMAC
, &rr
->WakeUp
.HMAC
) &&
9171 r2
->resrec
.rrtype
== kDNSType_SRV
&& mDNSSameIPPort(r2
->resrec
.rdata
->u
.srv
.port
, port
) &&
9172 SameDomainLabel(SkipLeadingLabels(r2
->resrec
.name
, 2)->c
, tp
))
9174 if (!r2
&& mDNSSameIPPort(port
, IPSEC
)) r2
= rr
; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
9177 rr
->AnnounceCount
= 0;
9178 LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
9179 InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), &v4
->dst
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, r2
));
9180 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9183 LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
9184 InterfaceNameForID(m
, rr
->resrec
.InterfaceID
), &v4
->dst
, &rr
->WakeUp
.HMAC
, tp
, mDNSVal16(port
));
9190 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9192 debugf("Got IPv6 from %.16a to %.16a", &v4
->src
, &v6
->dst
);
9197 mDNSlocal
void ConstructSleepProxyServerName(mDNS
*const m
, domainlabel
*name
)
9199 name
->c
[0] = mDNS_snprintf((char*)name
->c
+1, 62, "%d-%d-%d-%d %#s",
9200 m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
, &m
->nicelabel
);
9203 mDNSlocal
void SleepProxyServerCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
9205 if (result
== mStatus_NameConflict
)
9206 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
9207 else if (result
== mStatus_MemFree
)
9213 m
->SPSState
= (m
->SPSSocket
!= mDNSNULL
);
9217 ConstructSleepProxyServerName(m
, &name
);
9218 mDNS_RegisterService(m
, srs
,
9219 &name
, &SleepProxyServiceType
, &localdomain
,
9220 mDNSNULL
, m
->SPSSocket
->port
, // Host, port
9221 (mDNSu8
*)"", 1, // TXT data, length
9222 mDNSNULL
, 0, // Subtypes (none)
9223 mDNSInterface_Any
, // Interface ID
9224 SleepProxyServerCallback
, mDNSNULL
); // Callback and context
9226 LogSPS("Sleep Proxy Server %#s %s", srs
->RR_SRV
.resrec
.name
->c
, m
->SPSState
? "started" : "stopped");
9231 mDNSexport
void mDNSCoreBeSleepProxyServer(mDNS
*const m
, mDNSu8 sps
, mDNSu8 port
, mDNSu8 marginalpower
, mDNSu8 totpower
)
9233 // If turning off SPS, close our socket
9234 // (Do this first, BEFORE calling mDNS_DeregisterService below)
9235 if (!sps
&& m
->SPSSocket
) { mDNSPlatformUDPClose(m
->SPSSocket
); m
->SPSSocket
= mDNSNULL
; }
9237 // If turning off, or changing type, deregister old name
9238 if (m
->SPSState
== 1 && sps
!= m
->SPSType
)
9239 { m
->SPSState
= 2; mDNS_DeregisterService(m
, &m
->SPSRecords
); }
9241 // Record our new SPS parameters
9243 m
->SPSPortability
= port
;
9244 m
->SPSMarginalPower
= marginalpower
;
9245 m
->SPSTotalPower
= totpower
;
9247 // If turning on, open socket and advertise service
9252 m
->SPSSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
9253 if (!m
->SPSSocket
) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
9255 if (m
->SPSState
== 0) SleepProxyServerCallback(m
, &m
->SPSRecords
, mStatus_MemFree
);
9259 // ***************************************************************************
9260 #if COMPILER_LIKES_PRAGMA_MARK
9262 #pragma mark - Startup and Shutdown
9265 mDNSlocal
void mDNS_GrowCache_internal(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9267 if (storage
&& numrecords
)
9270 debugf("Adding cache storage for %d more records (%d bytes)", numrecords
, numrecords
*sizeof(CacheEntity
));
9271 for (i
=0; i
<numrecords
; i
++) storage
[i
].next
= &storage
[i
+1];
9272 storage
[numrecords
-1].next
= m
->rrcache_free
;
9273 m
->rrcache_free
= storage
;
9274 m
->rrcache_size
+= numrecords
;
9278 mDNSexport
void mDNS_GrowCache(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9281 mDNS_GrowCache_internal(m
, storage
, numrecords
);
9285 mDNSexport mStatus
mDNS_Init(mDNS
*const m
, mDNS_PlatformSupport
*const p
,
9286 CacheEntity
*rrcachestorage
, mDNSu32 rrcachesize
,
9287 mDNSBool AdvertiseLocalAddresses
, mDNSCallback
*Callback
, void *Context
)
9293 if (!rrcachestorage
) rrcachesize
= 0;
9297 m
->CanReceiveUnicastOn5353
= mDNSfalse
; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
9298 m
->AdvertiseLocalAddresses
= AdvertiseLocalAddresses
;
9299 m
->DivertMulticastAdvertisements
= mDNSfalse
;
9300 m
->mDNSPlatformStatus
= mStatus_Waiting
;
9301 m
->UnicastPort4
= zeroIPPort
;
9302 m
->UnicastPort6
= zeroIPPort
;
9303 m
->PrimaryMAC
= zeroEthAddr
;
9304 m
->MainCallback
= Callback
;
9305 m
->MainContext
= Context
;
9306 m
->rec
.r
.resrec
.RecordType
= 0;
9308 // For debugging: To catch and report locking failures
9310 m
->mDNS_reentrancy
= 0;
9311 m
->ShutdownTime
= 0;
9312 m
->lock_rrcache
= 0;
9313 m
->lock_Questions
= 0;
9314 m
->lock_Records
= 0;
9316 // Task Scheduling variables
9317 result
= mDNSPlatformTimeInit();
9318 if (result
!= mStatus_NoError
) return(result
);
9319 m
->timenow_adjust
= (mDNSs32
)mDNSRandom(0xFFFFFFFF);
9320 timenow
= mDNS_TimeNow_NoLock(m
);
9322 m
->timenow
= 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
9323 m
->timenow_last
= timenow
;
9324 m
->NextScheduledEvent
= timenow
;
9325 m
->SuppressSending
= timenow
;
9326 m
->NextCacheCheck
= timenow
+ 0x78000000;
9327 m
->NextScheduledQuery
= timenow
+ 0x78000000;
9328 m
->NextScheduledProbe
= timenow
+ 0x78000000;
9329 m
->NextScheduledResponse
= timenow
+ 0x78000000;
9330 m
->NextScheduledNATOp
= timenow
+ 0x78000000;
9331 m
->NextScheduledSPS
= timenow
+ 0x78000000;
9332 m
->RandomQueryDelay
= 0;
9333 m
->RandomReconfirmDelay
= 0;
9335 m
->SleepState
= SleepState_Awake
;
9337 m
->SystemWakeOnLANEnabled
= mDNSfalse
;
9341 // These fields only required for mDNS Searcher...
9342 m
->Questions
= mDNSNULL
;
9343 m
->NewQuestions
= mDNSNULL
;
9344 m
->CurrentQuestion
= mDNSNULL
;
9345 m
->LocalOnlyQuestions
= mDNSNULL
;
9346 m
->NewLocalOnlyQuestions
= mDNSNULL
;
9347 m
->rrcache_size
= 0;
9348 m
->rrcache_totalused
= 0;
9349 m
->rrcache_active
= 0;
9350 m
->rrcache_report
= 10;
9351 m
->rrcache_free
= mDNSNULL
;
9353 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++) m
->rrcache_hash
[slot
] = mDNSNULL
;
9355 mDNS_GrowCache_internal(m
, rrcachestorage
, rrcachesize
);
9357 // Fields below only required for mDNS Responder...
9358 m
->hostlabel
.c
[0] = 0;
9359 m
->nicelabel
.c
[0] = 0;
9360 m
->MulticastHostname
.c
[0] = 0;
9361 m
->HIHardware
.c
[0] = 0;
9362 m
->HISoftware
.c
[0] = 0;
9363 m
->ResourceRecords
= mDNSNULL
;
9364 m
->DuplicateRecords
= mDNSNULL
;
9365 m
->NewLocalRecords
= mDNSNULL
;
9366 m
->CurrentRecord
= mDNSNULL
;
9367 m
->HostInterfaces
= mDNSNULL
;
9368 m
->ProbeFailTime
= 0;
9369 m
->NumFailedProbes
= 0;
9370 m
->SuppressProbes
= 0;
9372 #ifndef UNICAST_DISABLED
9373 m
->NextuDNSEvent
= timenow
+ 0x78000000;
9374 m
->NextSRVUpdate
= timenow
+ 0x78000000;
9375 m
->SuppressStdPort53Queries
= 0;
9377 m
->ServiceRegistrations
= mDNSNULL
;
9378 m
->DNSServers
= mDNSNULL
;
9380 m
->Router
= zeroAddr
;
9381 m
->AdvertisedV4
= zeroAddr
;
9382 m
->AdvertisedV6
= zeroAddr
;
9384 m
->AuthInfoList
= mDNSNULL
;
9386 m
->ReverseMap
.ThisQInterval
= -1;
9387 m
->StaticHostname
.c
[0] = 0;
9389 m
->Hostnames
= mDNSNULL
;
9390 m
->AutoTunnelHostAddr
.b
[0] = 0;
9391 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
9392 m
->AutoTunnelLabel
.c
[0] = 0;
9394 m
->RegisterSearchDomains
= mDNSfalse
;
9396 // NAT traversal fields
9397 m
->NATTraversals
= mDNSNULL
;
9398 m
->CurrentNATTraversal
= mDNSNULL
;
9399 m
->retryIntervalGetAddr
= 0; // delta between time sent and retry
9400 m
->retryGetAddr
= timenow
+ 0x78000000; // absolute time when we retry
9401 m
->ExternalAddress
= zerov4Addr
;
9403 m
->NATMcastRecvskt
= mDNSNULL
;
9404 m
->LastNATupseconds
= 0;
9405 m
->LastNATReplyLocalTime
= timenow
;
9406 m
->LastNATMapResultCode
= NATErr_None
;
9408 m
->UPnPInterfaceID
= 0;
9409 m
->SSDPSocket
= mDNSNULL
;
9410 m
->SSDPWANPPPConnection
= mDNSfalse
;
9411 m
->UPnPRouterPort
= zeroIPPort
;
9412 m
->UPnPSOAPPort
= zeroIPPort
;
9413 m
->UPnPRouterURL
= mDNSNULL
;
9414 m
->UPnPWANPPPConnection
= mDNSfalse
;
9415 m
->UPnPSOAPURL
= mDNSNULL
;
9416 m
->UPnPRouterAddressString
= mDNSNULL
;
9417 m
->UPnPSOAPAddressString
= mDNSNULL
;
9419 m
->SPSPortability
= 0;
9420 m
->SPSMarginalPower
= 0;
9421 m
->SPSTotalPower
= 0;
9423 m
->SPSProxyListChanged
= mDNSNULL
;
9424 m
->SPSSocket
= mDNSNULL
;
9425 m
->SPSBrowseCallback
= mDNSNULL
;
9426 m
->ProxyRecords
= 0;
9430 #if APPLE_OSX_mDNSResponder
9431 m
->TunnelClients
= mDNSNULL
;
9434 result
= mDNSPlatformInit(m
);
9436 #ifndef UNICAST_DISABLED
9437 // It's better to do this *after* the platform layer has set up the
9438 // interface list and security credentials
9439 uDNS_SetupDNSConfig(m
); // Get initial DNS configuration
9445 mDNSexport
void mDNS_ConfigChanged(mDNS
*const m
)
9447 if (m
->SPSState
== 1)
9449 domainlabel name
, newname
;
9450 domainname type
, domain
;
9451 DeconstructServiceName(m
->SPSRecords
.RR_SRV
.resrec
.name
, &name
, &type
, &domain
);
9452 ConstructSleepProxyServerName(m
, &newname
);
9453 if (!SameDomainLabelCS(name
.c
, newname
.c
))
9455 LogSPS("Renaming SPS from “%#s” to “%#s”", name
.c
, newname
.c
);
9456 // When SleepProxyServerCallback gets the mStatus_MemFree message,
9457 // it will reregister the service under the new name
9459 mDNS_DeregisterService(m
, &m
->SPSRecords
);
9463 if (m
->MainCallback
)
9464 m
->MainCallback(m
, mStatus_ConfigChanged
);
9467 mDNSlocal
void DynDNSHostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
9470 debugf("NameStatusCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
9471 mDNSPlatformDynDNSHostNameStatusChanged(rr
->resrec
.name
, result
);
9474 mDNSlocal
void PurgeOrReconfirmCacheRecord(mDNS
*const m
, CacheRecord
*cr
, const DNSServer
* const ptr
, mDNSBool lameduck
)
9476 mDNSBool purge
= cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
||
9477 cr
->resrec
.rrtype
== kDNSType_A
||
9478 cr
->resrec
.rrtype
== kDNSType_AAAA
||
9479 cr
->resrec
.rrtype
== kDNSType_SRV
;
9483 debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge
? "purging" : "reconfirming", lameduck
? "lame duck" : "new", ptr
, &ptr
->addr
, mDNSVal16(ptr
->port
), ptr
->domain
.c
, CRDisplayString(m
, cr
));
9485 if (purge
) mDNS_PurgeCacheResourceRecord(m
, cr
);
9486 else mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
9489 mDNSexport mStatus
uDNS_SetupDNSConfig(mDNS
*const m
)
9497 DNSServer
*ptr
, **p
= &m
->DNSServers
;
9498 const DNSServer
*oldServers
= m
->DNSServers
;
9501 debugf("uDNS_SetupDNSConfig: entry");
9503 if (m
->RegisterSearchDomains
) uDNS_RegisterSearchDomains(m
);
9507 // Let the platform layer get the current DNS information
9508 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
9509 // (no need to hit the network with domain enumeration queries until we actually need that information).
9510 for (ptr
= m
->DNSServers
; ptr
; ptr
= ptr
->next
) ptr
->flags
|= DNSServer_FlagDelete
;
9512 mDNSPlatformSetDNSConfig(m
, mDNStrue
, mDNSfalse
, &fqdn
, mDNSNULL
, mDNSNULL
);
9514 // Update our qDNSServer pointers before we go and free the DNSServer object memory
9515 for (q
= m
->Questions
; q
; q
=q
->next
)
9516 if (!mDNSOpaque16IsZero(q
->TargetQID
))
9518 DNSServer
*s
= GetServerForName(m
, &q
->qname
);
9519 DNSServer
*t
= q
->qDNSServer
;
9522 // If DNS Server for this question has changed, reactivate it
9523 debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
9524 t
, t
? &t
->addr
: mDNSNULL
, mDNSVal16(t
? t
->port
: zeroIPPort
), t
? t
->domain
.c
: (mDNSu8
*)"",
9525 s
, s
? &s
->addr
: mDNSNULL
, mDNSVal16(s
? s
->port
: zeroIPPort
), s
? s
->domain
.c
: (mDNSu8
*)"",
9526 q
->qname
.c
, DNSTypeName(q
->qtype
));
9528 q
->unansweredQueries
= 0;
9529 ActivateUnicastQuery(m
, q
, mDNStrue
);
9533 // Flush all records that match a new resolver
9534 FORALL_CACHERECORDS(slot
, cg
, cr
)
9536 ptr
= GetServerForName(m
, cr
->resrec
.name
);
9537 if (ptr
&& (ptr
->flags
& DNSServer_FlagNew
) && !cr
->resrec
.InterfaceID
)
9538 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNSfalse
);
9543 if (((*p
)->flags
& DNSServer_FlagDelete
) != 0)
9545 // Scan our cache, looking for uDNS records that we would have queried this server for.
9546 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
9547 // different DNS servers can give different answers to the same question.
9549 ptr
->flags
&= ~DNSServer_FlagDelete
; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
9550 FORALL_CACHERECORDS(slot
, cg
, cr
)
9551 if (!cr
->resrec
.InterfaceID
&& GetServerForName(m
, cr
->resrec
.name
) == ptr
)
9552 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNStrue
);
9554 debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr
, &ptr
->addr
, mDNSVal16(ptr
->port
), ptr
->domain
.c
);
9555 mDNSPlatformMemFree(ptr
);
9559 (*p
)->flags
&= ~DNSServer_FlagNew
;
9564 // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
9565 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
9566 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
9567 // Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated.
9568 if ((m
->DNSServers
!= mDNSNULL
) != (oldServers
!= mDNSNULL
))
9571 FORALL_CACHERECORDS(slot
, cg
, cr
) if (!cr
->resrec
.InterfaceID
) { mDNS_PurgeCacheResourceRecord(m
, cr
); count
++; }
9572 LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
9573 m
->DNSServers
? "DNS server became" : "No DNS servers", count
);
9576 // If we no longer have any DNS servers, we need to force anything that needs to get zone data
9577 // to get that information again (which will fail, since we have no more DNS servers)
9578 if ((m
->DNSServers
== mDNSNULL
) && (oldServers
!= mDNSNULL
)) RestartRecordGetZoneData(m
);
9580 // Did our FQDN change?
9581 if (!SameDomainName(&fqdn
, &m
->FQDN
))
9583 if (m
->FQDN
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &m
->FQDN
);
9585 AssignDomainName(&m
->FQDN
, &fqdn
);
9589 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
9590 mDNS_AddDynDNSHostName(m
, &m
->FQDN
, DynDNSHostNameCallback
, mDNSNULL
);
9596 // handle router and primary interface changes
9597 v4
= v6
= r
= zeroAddr
;
9598 v4
.type
= r
.type
= mDNSAddrType_IPv4
;
9600 if (mDNSPlatformGetPrimaryInterface(m
, &v4
, &v6
, &r
) == mStatus_NoError
&& !mDNSv4AddressIsLinkLocal(&v4
.ip
.v4
))
9602 mDNS_SetPrimaryInterfaceInfo(m
,
9603 !mDNSIPv4AddressIsZero(v4
.ip
.v4
) ? &v4
: mDNSNULL
,
9604 !mDNSIPv6AddressIsZero(v6
.ip
.v6
) ? &v6
: mDNSNULL
,
9605 !mDNSIPv4AddressIsZero(r
.ip
.v4
) ? &r
: mDNSNULL
);
9609 mDNS_SetPrimaryInterfaceInfo(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
9610 if (m
->FQDN
.c
[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1); // Set status to 1 to indicate temporary failure
9613 return mStatus_NoError
;
9616 mDNSexport
void mDNSCoreInitComplete(mDNS
*const m
, mStatus result
)
9618 m
->mDNSPlatformStatus
= result
;
9619 if (m
->MainCallback
)
9622 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
9623 m
->MainCallback(m
, mStatus_NoError
);
9624 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
9629 extern ServiceRecordSet
*CurrentServiceRecordSet
;
9631 mDNSlocal
void DeregLoop(mDNS
*const m
, AuthRecord
*const start
)
9633 m
->CurrentRecord
= start
;
9634 while (m
->CurrentRecord
)
9636 AuthRecord
*rr
= m
->CurrentRecord
;
9637 if (rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
9639 LogInfo("DeregLoop: Deregistering %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9640 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
9642 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
9643 // the list may have been changed in that call.
9644 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
9645 m
->CurrentRecord
= rr
->next
;
9649 mDNSexport
void mDNS_StartExit(mDNS
*const m
)
9651 NetworkInterfaceInfo
*intf
;
9656 m
->ShutdownTime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
9658 mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
9659 mDNSCoreBeSleepProxyServer(m
, 0, 0, 0, 0);
9660 mDNS_ReclaimLockAfterCallback();
9662 #ifndef UNICAST_DISABLED
9666 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
9667 // because we deregister all records and services later in this routine
9668 while (m
->Hostnames
) mDNS_RemoveDynDNSHostName(m
, &m
->Hostnames
->fqdn
);
9670 // For each member of our SearchList, deregister any records it may have created, and cut them from the list.
9671 // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
9672 // and we may crash because the list still contains dangling pointers.
9673 for (s
= SearchList
; s
; s
= s
->next
)
9676 ARListElem
*dereg
= s
->AuthRecs
;
9677 s
->AuthRecs
= s
->AuthRecs
->next
;
9678 mDNS_Deregister_internal(m
, &dereg
->ar
, mDNS_Dereg_normal
); // Memory will be freed in the FreeARElemCallback
9683 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
9684 if (intf
->Advertise
)
9685 DeadvertiseInterface(m
, intf
);
9687 // Shut down all our active NAT Traversals
9688 while (m
->NATTraversals
)
9690 NATTraversalInfo
*t
= m
->NATTraversals
;
9691 mDNS_StopNATOperation_internal(m
, t
); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
9693 // After stopping the NAT Traversal, we zero out the fields.
9694 // This has particularly important implications for our AutoTunnel records --
9695 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
9696 // handlers to just turn around and attempt to re-register those same records.
9697 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
9698 t
->ExternalAddress
= zerov4Addr
;
9699 t
->ExternalPort
= zeroIPPort
;
9701 t
->Result
= mStatus_NoError
;
9704 // Make sure there are nothing but deregistering records remaining in the list
9705 if (m
->CurrentRecord
)
9706 LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
9708 // We're in the process of shutting down, so queries, etc. are no longer available.
9709 // Consequently, determining certain information, e.g. the uDNS update server's IP
9710 // address, will not be possible. The records on the main list are more likely to
9711 // already contain such information, so we deregister the duplicate records first.
9712 LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
9713 DeregLoop(m
, m
->DuplicateRecords
);
9714 LogInfo("mDNS_StartExit: Deregistering resource records");
9715 DeregLoop(m
, m
->ResourceRecords
);
9717 // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
9718 // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
9719 if (m
->NextScheduledResponse
- m
->timenow
< mDNSPlatformOneSecond
)
9721 m
->NextScheduledResponse
= m
->timenow
;
9722 m
->SuppressSending
= 0;
9725 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9726 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
9727 while (CurrentServiceRecordSet
)
9729 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
9730 LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs
->RR_SRV
.resrec
.name
->c
);
9731 uDNS_DeregisterService(m
, srs
);
9732 if (CurrentServiceRecordSet
== srs
)
9733 CurrentServiceRecordSet
= srs
->uDNS_next
;
9737 if (m
->ResourceRecords
) LogInfo("mDNS_StartExit: Sending final record deregistrations");
9738 else LogInfo("mDNS_StartExit: No deregistering records remain");
9740 if (m
->ServiceRegistrations
) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
9741 else LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
9743 for (rr
= m
->DuplicateRecords
; rr
; rr
= rr
->next
)
9744 LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9746 // If any deregistering records remain, send their deregistration announcements before we exit
9747 if (m
->mDNSPlatformStatus
!= mStatus_NoError
) DiscardDeregistrations(m
);
9751 LogInfo("mDNS_StartExit: done");
9754 mDNSexport
void mDNS_FinalExit(mDNS
*const m
)
9756 mDNSu32 rrcache_active
= 0;
9757 mDNSu32 rrcache_totalused
= 0;
9760 ServiceRecordSet
*srs
;
9762 LogInfo("mDNS_FinalExit: mDNSPlatformClose");
9763 mDNSPlatformClose(m
);
9765 rrcache_totalused
= m
->rrcache_totalused
;
9766 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
9768 while (m
->rrcache_hash
[slot
])
9770 CacheGroup
*cg
= m
->rrcache_hash
[slot
];
9773 CacheRecord
*cr
= cg
->members
;
9774 cg
->members
= cg
->members
->next
;
9775 if (cr
->CRActiveQuestion
) rrcache_active
++;
9776 ReleaseCacheRecord(m
, cr
);
9778 cg
->rrcache_tail
= &cg
->members
;
9779 ReleaseCacheGroup(m
, &m
->rrcache_hash
[slot
]);
9782 debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused
, rrcache_active
);
9783 if (rrcache_active
!= m
->rrcache_active
)
9784 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active
, m
->rrcache_active
);
9786 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
9787 LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
9789 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
9790 LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs
, srs
->RR_SRV
.resrec
.name
->c
);
9792 LogInfo("mDNS_FinalExit: done");