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.977 2009/07/23 23:30:01 cheshire
42 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
44 Revision 1.976 2009/07/23 09:15:06 cheshire
45 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
46 Fixed silly mistake in checkin 1.974 that broke SendResponses
48 Revision 1.975 2009/07/21 23:46:19 cheshire
49 Improved "DNS Message too short" syslog debugging message
51 Revision 1.974 2009/07/21 23:41:05 cheshire
52 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
53 Fixed silly mistake in checkin 1.974 that broke SendResponses
55 svn merge: Revision 1.974 2009/07/21 23:41:05 cheshire
56 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
57 Another refinement: When building a response packet, if we're going to add an OWNER option at the end,
58 reserve enough bytes to ensure that we'll be able to do that
60 svn merge: Revision 1.973 2009/07/16 00:34:18 cheshire
61 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
62 Additional refinement: If we didn't register with a Sleep Proxy when going to sleep,
63 we don't need to include our OWNER option in our packets when we re-awaken
65 svn merge: Revision 1.972 2009/07/16 00:12:23 cheshire
66 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
67 Additional fixes: Only add and send OWNER option if we were already going to send a non-empty packet anyway
69 svn merge: Revision 1.971 2009/07/15 23:35:40 cheshire
70 <rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
72 Revision 1.970.2.1 2009/07/23 23:36:04 cheshire
73 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
75 Revision 1.970 2009/07/11 01:59:27 cheshire
76 <rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
77 When going to sleep, try calling ActivateLocalProxy before registering with remote sleep proxy
79 Revision 1.969 2009/06/30 21:18:19 cheshire
80 <rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
82 1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
83 2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
85 Revision 1.968 2009/06/29 23:51:09 cheshire
86 <rdar://problem/6690034> Can't bind to Active Directory
88 Revision 1.967 2009/06/27 00:25:27 cheshire
89 <rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
90 Removed overly-complicate and ineffective multi-packet known-answer snooping code
91 (Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
93 Revision 1.966 2009/06/26 01:55:55 cheshire
94 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
95 Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
96 add additional NSEC records only when there's space to do that without having to generate an additional packet
98 Revision 1.965 2009/06/24 22:14:21 cheshire
99 <rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
101 Revision 1.964 2009/06/03 23:07:13 cheshire
102 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
103 Large records were not being added in cases where an NSEC record was also required
105 Revision 1.963 2009/05/28 00:39:19 cheshire
106 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
107 After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
109 Revision 1.962 2009/05/19 23:40:37 cheshire
110 <rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
111 Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
113 Revision 1.961 2009/05/19 23:00:43 cheshire
114 Improved comments and debugging messages
116 Revision 1.960 2009/05/13 17:25:33 mkrochma
117 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
118 Sleep proxy client should only look for services being advertised via Multicast
120 Revision 1.959 2009/05/12 23:10:31 cheshire
121 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
122 Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
124 Revision 1.958 2009/05/12 19:19:20 cheshire
125 <rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
127 Revision 1.957 2009/05/07 23:56:25 cheshire
128 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
129 To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
131 Revision 1.956 2009/05/07 23:46:27 cheshire
132 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
134 Revision 1.955 2009/05/07 23:40:54 cheshire
135 Minor code rearrangement in preparation for upcoming changes
137 Revision 1.954 2009/05/01 21:28:34 cheshire
138 <rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
139 No longer suspend network operations after we've acknowledged that the machine is going to sleep,
140 because other software may not have yet acknowledged the sleep event, and may be still trying
141 to do unicast DNS queries or other Bonjour operations.
143 Revision 1.953 2009/05/01 19:17:35 cheshire
144 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
146 Revision 1.952 2009/05/01 19:16:45 mcguire
147 <rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
149 Revision 1.951 2009/04/28 23:48:19 jessic2
150 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0
152 Revision 1.950 2009/04/25 01:17:10 mcguire
153 Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
155 Revision 1.949 2009/04/25 01:11:02 mcguire
156 Refactor: create separate function: RestartRecordGetZoneData
158 Revision 1.948 2009/04/24 21:25:16 cheshire
159 <rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
161 Revision 1.947 2009/04/24 19:41:12 mcguire
162 <rdar://problem/6791775> 4 second delay in DNS response
164 Revision 1.946 2009/04/24 19:28:39 mcguire
165 <rdar://problem/6791775> 4 second delay in DNS response
167 Revision 1.945 2009/04/24 00:30:30 cheshire
168 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
169 Added code to generate and process NSEC records
171 Revision 1.944 2009/04/23 22:06:29 cheshire
172 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
173 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
175 Revision 1.943 2009/04/22 01:19:56 jessic2
176 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
178 Revision 1.942 2009/04/21 02:13:29 cheshire
179 <rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
180 Made code less susceptible to being tricked by stale packets echoed back from the network.
182 Revision 1.941 2009/04/15 22:22:23 mcguire
183 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
184 Additional fix: protect against deref of NULL
186 Revision 1.940 2009/04/15 20:42:51 mcguire
187 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
189 Revision 1.939 2009/04/11 00:19:32 jessic2
190 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
192 Revision 1.938 2009/04/06 23:44:57 cheshire
193 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
195 Revision 1.937 2009/04/04 00:14:49 mcguire
196 fix logging in BeginSleepProcessing
198 Revision 1.936 2009/04/04 00:10:59 mcguire
199 don't ignore m->SystemWakeOnLANEnabled when going to sleep
201 Revision 1.935 2009/04/01 17:50:11 mcguire
204 Revision 1.934 2009/03/27 17:17:58 cheshire
205 Improved "Ignoring suspect uDNS response" debugging message
207 Revision 1.933 2009/03/21 02:40:21 cheshire
208 <rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
210 Revision 1.932 2009/03/20 23:53:03 jessic2
211 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
213 Revision 1.931 2009/03/18 19:08:15 cheshire
214 Show old/new sleep sequence numbers in logical order
216 Revision 1.930 2009/03/17 23:40:45 cheshire
217 For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
219 Revision 1.929 2009/03/17 21:55:56 cheshire
220 Fixed mistake in logic for decided when we're ready to go to sleep
222 Revision 1.928 2009/03/17 19:48:12 cheshire
223 <rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
225 Revision 1.927 2009/03/17 01:22:56 cheshire
226 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
227 Initial support for resolving up to three Sleep Proxies in parallel
229 Revision 1.926 2009/03/17 01:05:07 mcguire
230 <rdar://problem/6657640> Reachability fixes on DNS config change
232 Revision 1.925 2009/03/13 01:35:36 mcguire
233 <rdar://problem/6657640> Reachability fixes on DNS config change
235 Revision 1.924 2009/03/10 23:45:20 cheshire
236 Added comments explaining usage of SetSPSProxyListChanged()
238 Revision 1.923 2009/03/09 21:53:02 cheshire
239 <rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
241 Revision 1.922 2009/03/09 21:30:17 cheshire
242 Improved some LogSPS messages; made RestartProbing() subroutine
244 Revision 1.921 2009/03/06 22:53:31 cheshire
245 Don't bother registering with Sleep Proxy if we have no advertised services
247 Revision 1.920 2009/03/06 20:08:55 cheshire
248 <rdar://problem/6601429> Sleep Proxy: Return error responses to clients
250 Revision 1.919 2009/03/05 21:54:43 cheshire
251 Improved "Sleep Proxy Server started / stopped" message
253 Revision 1.918 2009/03/04 01:37:14 cheshire
254 <rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
256 Revision 1.917 2009/03/03 23:14:25 cheshire
257 Got rid of code duplication by making subroutine "SetupOwnerOpt"
259 Revision 1.916 2009/03/03 23:04:43 cheshire
260 For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
262 Revision 1.915 2009/03/03 22:51:53 cheshire
263 <rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
265 Revision 1.914 2009/03/03 00:46:09 cheshire
266 Additional debugging information in ResolveSimultaneousProbe
268 Revision 1.913 2009/02/27 03:08:47 cheshire
269 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
271 Revision 1.912 2009/02/27 02:31:28 cheshire
272 Improved "Record not found in list" debugging message
274 Revision 1.911 2009/02/21 01:42:11 cheshire
277 Revision 1.910 2009/02/19 01:50:53 cheshire
278 Converted some LogInfo messages to LogSPS
280 Revision 1.909 2009/02/14 00:04:59 cheshire
281 Left-justify interface names
283 Revision 1.908 2009/02/13 19:40:07 cheshire
284 Improved alignment of LogSPS messages
286 Revision 1.907 2009/02/13 18:16:05 cheshire
287 Fixed some compile warnings
289 Revision 1.906 2009/02/13 06:10:17 cheshire
290 Convert LogOperation messages to LogInfo
292 Revision 1.905 2009/02/12 20:57:24 cheshire
293 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
295 Revision 1.904 2009/02/11 02:37:29 cheshire
296 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
297 Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
298 so that it happens correctly even when we delay re-sleep due to a very short wakeup.
300 Revision 1.903 2009/02/09 23:34:31 cheshire
301 Additional logging for debugging unknown packets
303 Revision 1.902 2009/02/07 05:57:01 cheshire
304 Fixed debugging log message
306 Revision 1.901 2009/02/07 02:57:31 cheshire
307 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
309 Revision 1.900 2009/02/02 21:29:24 cheshire
310 <rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
311 If Negative response for our special Microsoft Active Directory "local SOA" check has no
312 SOA record in the authority section, assume we should cache the negative result for 24 hours
314 Revision 1.899 2009/01/31 00:37:50 cheshire
315 When marking cache records for deletion in response to a uDNS response,
316 make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
318 Revision 1.898 2009/01/30 23:49:20 cheshire
319 Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
321 Revision 1.897 2009/01/30 22:04:49 cheshire
322 Workaround to reduce load on root name servers when caching the SOA record for "."
324 Revision 1.896 2009/01/30 22:00:05 cheshire
325 Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
327 Revision 1.895 2009/01/30 17:46:39 cheshire
328 Improved debugging messages for working out why spurious name conflicts are happening
330 Revision 1.894 2009/01/30 00:22:09 cheshire
331 <rdar://problem/6540743> No announcement after probing & no conflict notice
333 Revision 1.893 2009/01/29 22:27:03 mcguire
334 <rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
336 Revision 1.892 2009/01/24 01:38:23 cheshire
337 Fixed error in logic for targeted queries
339 Revision 1.891 2009/01/22 02:14:25 cheshire
340 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
342 Revision 1.890 2009/01/22 00:45:02 cheshire
343 Improved SPS debugging log messages; we are eligible to start answering ARP requests
344 after we send our first announcement, not after we send our last probe
346 Revision 1.889 2009/01/21 03:43:56 mcguire
347 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
349 Revision 1.888 2009/01/20 00:27:43 mcguire
350 <rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
352 Revision 1.887 2009/01/17 05:14:37 cheshire
353 Convert SendQueries Probe messages to LogSPS messages
355 Revision 1.886 2009/01/17 03:43:09 cheshire
356 Added SPSLogging switch to facilitate Sleep Proxy Server debugging
358 Revision 1.885 2009/01/16 22:44:18 cheshire
359 <rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
361 Revision 1.884 2009/01/16 21:43:52 cheshire
362 Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
364 Revision 1.883 2009/01/16 21:11:18 cheshire
365 When purging expired Sleep Proxy records, need to check DuplicateRecords list too
367 Revision 1.882 2009/01/16 19:54:28 cheshire
368 Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
370 Revision 1.881 2009/01/14 01:38:38 mcguire
371 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
373 Revision 1.880 2009/01/10 01:51:19 cheshire
374 q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
376 Revision 1.879 2009/01/10 01:43:52 cheshire
377 Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
379 Revision 1.878 2009/01/10 01:38:10 cheshire
380 Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
382 Revision 1.877 2009/01/10 01:36:08 cheshire
383 Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
385 Revision 1.876 2009/01/09 22:56:06 cheshire
386 Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
388 Revision 1.875 2009/01/09 22:54:46 cheshire
389 When tranferring record from DuplicateRecords list to ResourceRecords list,
390 need to copy across state of 'Answered Local-Only-Questions' flag
392 Revision 1.874 2009/01/07 23:07:24 cheshire
393 <rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
395 Revision 1.873 2008/12/17 00:18:59 mkrochma
396 Change some LogMsg to LogOperation before submitting
398 Revision 1.872 2008/12/12 01:30:40 cheshire
399 Update platform-layer BPF filters when we add or remove AddressProxy records
401 Revision 1.871 2008/12/10 02:25:31 cheshire
402 Minor fixes to use of LogClientOperations symbol
404 Revision 1.870 2008/12/10 02:11:41 cheshire
405 ARMv5 compiler doesn't like uncommented stuff after #endif
407 Revision 1.869 2008/12/05 02:35:24 mcguire
408 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
410 Revision 1.868 2008/12/04 21:08:51 mcguire
411 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
413 Revision 1.867 2008/11/26 21:19:36 cheshire
414 <rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
416 Revision 1.866 2008/11/26 20:32:46 cheshire
417 <rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
418 Update advertised name when Sleep Proxy "intent" metric changes
420 Revision 1.865 2008/11/26 19:49:25 cheshire
421 Record originally-requested port in sr->NATinfo.IntPort
423 Revision 1.864 2008/11/26 19:02:37 cheshire
424 Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
426 Revision 1.863 2008/11/26 03:59:03 cheshire
427 Wait 30 seconds before starting ARP Announcements
429 Revision 1.862 2008/11/25 23:43:07 cheshire
430 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
431 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
433 Revision 1.861 2008/11/25 22:46:30 cheshire
434 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
436 Revision 1.860 2008/11/25 05:07:15 cheshire
437 <rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
439 Revision 1.859 2008/11/20 02:07:56 cheshire
440 <rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
442 Revision 1.858 2008/11/20 01:38:36 cheshire
443 For consistency with other parts of the code, changed code to only check
444 that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
446 Revision 1.857 2008/11/14 22:55:18 cheshire
449 Revision 1.856 2008/11/14 21:08:28 cheshire
450 Only put owner option in query packet if we have a non-zero MAC address to put
451 Only process owner options in received query packets if the MAC address in the option is non-zero
453 Revision 1.855 2008/11/14 02:29:54 cheshire
454 If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
456 Revision 1.854 2008/11/14 00:00:53 cheshire
457 After client machine wakes up, Sleep Proxy machine need to remove any records
458 it was temporarily holding as proxy for that client
460 Revision 1.853 2008/11/13 19:07:30 cheshire
461 Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
463 Revision 1.852 2008/11/12 23:23:11 cheshire
464 Before waking a host, check to see if it has an SRV record advertising
465 a service on the port in question, and if not, don't bother waking it.
467 Revision 1.851 2008/11/12 01:54:15 cheshire
468 <rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
469 It turns out it is beneficial to have the domain on the end, because it allows better name compression
471 Revision 1.850 2008/11/11 01:56:57 cheshire
472 Improved name conflict log messages
474 Revision 1.849 2008/11/06 23:50:43 cheshire
475 Allow plain (non-SYN) ssh data packets to wake sleeping host
477 Revision 1.848 2008/11/05 02:40:28 mkrochma
478 Change mDNS_SetFQDN syslog mesage to debugf
480 Revision 1.847 2008/11/04 23:06:50 cheshire
481 Split RDataBody union definition into RDataBody and RDataBody2, and removed
482 SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
484 Revision 1.846 2008/11/04 22:21:44 cheshire
485 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
487 Revision 1.845 2008/11/03 23:52:05 cheshire
488 Improved ARP debugging messages to differentiate ARP Announcements from Requests
490 Revision 1.844 2008/10/31 23:43:51 cheshire
491 Fixed compile error in Posix build
493 Revision 1.843 2008/10/31 22:55:04 cheshire
494 Initial support for structured SPS names
496 Revision 1.842 2008/10/30 00:12:07 cheshire
497 Fixed spin when PutSPSRec fails to put a record because it's too big to fit
499 Revision 1.841 2008/10/29 23:23:38 cheshire
500 Refined cache size reporting to go in steps of 1000 when number is above 1000
502 Revision 1.840 2008/10/29 21:34:10 cheshire
503 Removed some old debugging messages
505 Revision 1.839 2008/10/29 21:31:32 cheshire
506 Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
508 Revision 1.838 2008/10/28 18:30:37 cheshire
509 Added debugging message in mDNSCoreReceiveRawPacket
511 Revision 1.837 2008/10/24 23:58:05 cheshire
512 Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
514 Revision 1.836 2008/10/24 23:18:18 cheshire
515 If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
517 Revision 1.835 2008/10/24 23:07:59 cheshire
518 Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
520 Revision 1.834 2008/10/24 23:03:24 cheshire
521 Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
523 Revision 1.833 2008/10/24 23:01:26 cheshire
524 To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
526 Revision 1.832 2008/10/24 22:58:24 cheshire
527 For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
529 Revision 1.831 2008/10/24 22:50:41 cheshire
530 When waking SPS client, include interface name in syslog message
532 Revision 1.830 2008/10/24 20:50:34 cheshire
533 Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
535 Revision 1.829 2008/10/23 23:55:57 cheshire
536 Fixed some missing "const" declarations
538 Revision 1.828 2008/10/23 22:25:56 cheshire
539 Renamed field "id" to more descriptive "updateid"
541 Revision 1.827 2008/10/23 03:06:25 cheshire
542 Fixed "Waking host" log message
544 Revision 1.826 2008/10/22 23:21:30 cheshire
545 Make sure we have enough bytes before reading into the transport-level header
547 Revision 1.825 2008/10/22 22:31:53 cheshire
548 Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
550 Revision 1.824 2008/10/22 20:00:31 cheshire
551 If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
553 Revision 1.823 2008/10/22 19:55:35 cheshire
554 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
556 Revision 1.822 2008/10/22 01:41:39 cheshire
557 Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
559 Revision 1.821 2008/10/22 01:12:53 cheshire
560 Answer ARP Requests for any IP address we're proxying for
562 Revision 1.820 2008/10/21 01:11:11 cheshire
563 Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
565 Revision 1.819 2008/10/20 22:16:27 cheshire
566 Updated comments; increased cache shedding threshold from 3000 to 4000
568 Revision 1.818 2008/10/16 22:01:54 cheshire
569 Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
571 Revision 1.817 2008/10/16 21:40:49 cheshire
572 Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
574 Revision 1.816 2008/10/15 23:12:36 cheshire
575 On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
577 Revision 1.815 2008/10/15 20:46:38 cheshire
578 When transferring records to SPS, include Lease Option
580 Revision 1.814 2008/10/15 19:51:27 cheshire
581 Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
583 Revision 1.813 2008/10/15 00:09:23 cheshire
584 When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
586 Revision 1.812 2008/10/15 00:01:40 cheshire
587 When going to sleep, discover and resolve SPS, and if successful, transfer records to it
589 Revision 1.811 2008/10/14 23:51:57 cheshire
590 Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
592 Revision 1.810 2008/10/14 21:37:55 cheshire
593 Removed unnecessary m->BeSleepProxyServer variable
595 Revision 1.809 2008/10/10 23:45:48 cheshire
596 For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
597 not a wide-area unicast hostname
599 Revision 1.808 2008/10/09 18:59:19 cheshire
600 Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
602 Revision 1.807 2008/10/07 15:56:58 cheshire
603 Fixed "unused variable" warnings in non-debug builds
605 Revision 1.806 2008/10/04 00:53:37 cheshire
606 On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
608 Revision 1.805 2008/10/03 18:17:28 cheshire
609 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
610 Update advertised Sleep Proxy Server name if user changes computer name
612 Revision 1.804 2008/10/03 01:26:06 mcguire
613 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
614 Put back Duplicate Record check
616 Revision 1.803 2008/10/02 23:38:56 mcguire
617 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
619 Revision 1.802 2008/10/02 23:13:48 cheshire
620 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
621 Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
623 Revision 1.801 2008/10/02 22:51:04 cheshire
624 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
625 Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
627 Revision 1.800 2008/10/02 22:13:15 cheshire
628 <rdar://problem/6230680> 100ms delay on shutdown
629 Additional refinement: Also need to clear m->SuppressSending
631 Revision 1.799 2008/09/29 20:12:37 cheshire
632 Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
634 Revision 1.798 2008/09/26 19:53:14 cheshire
635 Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
637 Revision 1.797 2008/09/25 20:40:59 cheshire
638 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
639 In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
641 Revision 1.796 2008/09/25 20:17:10 cheshire
642 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
643 Added defensive code to make sure *all* records of a ServiceRecordSet have
644 completed deregistering before we pass on the mStatus_MemFree message
646 Revision 1.795 2008/09/25 00:30:11 cheshire
647 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
649 Revision 1.794 2008/09/24 23:48:05 cheshire
650 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
651 it only needs to access the embedded SRV member of the set
653 Revision 1.793 2008/09/23 04:11:53 cheshire
654 <rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
656 Revision 1.792 2008/09/23 02:30:07 cheshire
657 Get rid of PutResourceRecordCappedTTL()
659 Revision 1.791 2008/09/20 00:34:21 mcguire
660 <rdar://problem/6129039> BTMM: Add support for WANPPPConnection
662 Revision 1.790 2008/09/18 22:46:34 cheshire
663 <rdar://problem/6230680> 100ms delay on shutdown
665 Revision 1.789 2008/09/18 06:15:06 mkrochma
666 <rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
668 Revision 1.788 2008/09/16 21:11:41 cheshire
669 <rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
671 Revision 1.787 2008/09/05 22:53:24 cheshire
672 Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
674 Revision 1.786 2008/09/05 22:23:28 cheshire
675 Moved initialization of "question->LocalSocket" to more logical place
677 Revision 1.785 2008/08/14 19:20:55 cheshire
678 <rdar://problem/6143846> Negative responses over TCP incorrectly rejected
680 Revision 1.784 2008/08/13 00:47:53 mcguire
681 Handle failures when packet logging
683 Revision 1.783 2008/07/25 07:09:51 mcguire
684 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
686 Revision 1.782 2008/07/24 20:23:03 cheshire
687 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
689 Revision 1.781 2008/07/18 21:37:35 mcguire
690 <rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
692 Revision 1.780 2008/07/18 02:24:36 cheshire
693 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
694 Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
695 we're still on our first or second query after an interface registration or wake from sleep).
697 Revision 1.779 2008/07/18 01:05:23 cheshire
698 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
700 Revision 1.778 2008/06/26 17:24:11 mkrochma
701 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
703 Revision 1.777 2008/06/19 01:20:48 mcguire
704 <rdar://problem/4206534> Use all configured DNS servers
706 Revision 1.776 2008/04/17 20:14:14 cheshire
707 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
709 Revision 1.775 2008/03/26 01:53:34 mcguire
710 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
712 Revision 1.774 2008/03/17 17:46:08 mcguire
713 When activating an LLQ, reset all the important state and destroy any tcp connection,
714 so that everything will be restarted as if the question had just been asked.
715 Also reset servPort, so that the SOA query will be re-issued.
717 Revision 1.773 2008/03/14 22:52:36 mcguire
718 <rdar://problem/5321824> write status to the DS
719 Update status when any unicast LLQ is started
721 Revision 1.772 2008/03/06 02:48:34 mcguire
722 <rdar://problem/5321824> write status to the DS
724 Revision 1.771 2008/02/26 22:04:44 cheshire
725 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
726 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
727 question while it's still in our 'm->NewQuestions' section of the list
729 Revision 1.770 2008/02/22 23:09:02 cheshire
730 <rdar://problem/5338420> BTMM: Not processing additional records
732 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
733 2. Once we decide a record is acceptable, we can break out of the loop
735 Revision 1.769 2008/02/22 00:00:19 cheshire
736 <rdar://problem/5338420> BTMM: Not processing additional records
738 Revision 1.768 2008/02/19 23:26:50 cheshire
739 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
741 Revision 1.767 2007/12/22 02:25:29 cheshire
742 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
744 Revision 1.766 2007/12/15 01:12:27 cheshire
745 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
747 Revision 1.765 2007/12/15 00:18:51 cheshire
748 Renamed question->origLease to question->ReqLease
750 Revision 1.764 2007/12/14 00:49:53 cheshire
751 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
752 the CurrentServiceRecordSet mechanism to guard against services being deleted,
753 just like the record deregistration loop uses m->CurrentRecord.
755 Revision 1.763 2007/12/13 20:20:17 cheshire
756 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
757 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
758 inline a function defined in a different compilation unit) and therefore optimized better.
760 Revision 1.762 2007/12/13 00:13:03 cheshire
761 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
763 Revision 1.761 2007/12/13 00:03:31 cheshire
764 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
766 Revision 1.760 2007/12/08 00:36:19 cheshire
767 <rdar://problem/5636422> Updating TXT records is too slow
768 Remove unnecessary delays on announcing record updates, and on processing them on reception
770 Revision 1.759 2007/12/07 22:41:29 cheshire
771 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
772 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
774 Revision 1.758 2007/12/07 00:45:57 cheshire
775 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
777 Revision 1.757 2007/12/06 00:22:27 mcguire
778 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
780 Revision 1.756 2007/12/05 01:52:30 cheshire
781 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
782 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
784 Revision 1.755 2007/12/03 23:36:45 cheshire
785 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
786 Need to check GetServerForName() result is non-null before dereferencing pointer
788 Revision 1.754 2007/12/01 01:21:27 jgraessley
789 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
791 Revision 1.753 2007/12/01 00:44:15 cheshire
792 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
794 Revision 1.752 2007/11/14 01:10:51 cheshire
795 Fixed LogOperation() message wording
797 Revision 1.751 2007/10/30 23:49:41 cheshire
798 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
799 LLQ state was not being transferred properly between duplicate questions
801 Revision 1.750 2007/10/29 23:58:52 cheshire
802 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
803 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
805 Revision 1.749 2007/10/29 21:28:36 cheshire
806 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
808 Revision 1.748 2007/10/29 20:02:50 cheshire
809 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
811 Revision 1.747 2007/10/26 22:53:50 cheshire
812 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
813 instead of replicating the logic in both places
815 Revision 1.746 2007/10/25 22:48:50 cheshire
816 Added LogOperation message saying when we restart GetZoneData for record and service registrations
818 Revision 1.745 2007/10/25 20:48:47 cheshire
819 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
821 Revision 1.744 2007/10/25 20:06:14 cheshire
822 Don't try to do SOA queries using private DNS (TLS over TCP) queries
824 Revision 1.743 2007/10/25 00:12:46 cheshire
825 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
826 Retrigger service registrations whenever a new network interface is added
828 Revision 1.742 2007/10/24 22:40:06 cheshire
829 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
830 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
832 Revision 1.741 2007/10/24 00:50:29 cheshire
833 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
834 Retrigger record registrations whenever a new network interface is added
836 Revision 1.740 2007/10/23 00:38:03 cheshire
837 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
838 or code will spin sending the same cache expiration query repeatedly
840 Revision 1.739 2007/10/22 23:46:41 cheshire
841 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
842 Need to clear question->nta pointer after calling CancelGetZoneData()
844 Revision 1.738 2007/10/19 22:08:49 cheshire
845 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
846 Additional fixes and refinements
848 Revision 1.737 2007/10/18 23:06:42 cheshire
849 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
850 Additional fixes and refinements
852 Revision 1.736 2007/10/18 20:23:17 cheshire
853 Moved SuspendLLQs into mDNS.c, since it's only called from one place
855 Revision 1.735 2007/10/18 00:12:34 cheshire
856 Fixed "unused variable" compiler warning
858 Revision 1.734 2007/10/17 22:49:54 cheshire
859 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
861 Revision 1.733 2007/10/17 22:37:23 cheshire
862 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
864 Revision 1.732 2007/10/17 21:53:51 cheshire
865 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
867 Revision 1.731 2007/10/17 18:37:50 cheshire
868 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
869 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
871 Revision 1.730 2007/10/16 21:16:07 cheshire
872 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
874 Revision 1.729 2007/10/05 17:56:10 cheshire
875 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
877 Revision 1.728 2007/10/04 23:18:14 cheshire
878 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
880 Revision 1.727 2007/10/04 22:51:57 cheshire
881 Added debugging LogOperation message to show when we're sending cache expiration queries
883 Revision 1.726 2007/10/03 00:14:24 cheshire
884 Removed write to null to generate stack trace for SetNextQueryTime locking failure
886 Revision 1.725 2007/10/02 21:11:08 cheshire
887 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
889 Revision 1.724 2007/10/02 20:10:23 cheshire
890 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
892 Revision 1.723 2007/10/02 19:56:54 cheshire
893 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
895 Revision 1.722 2007/10/01 22:59:46 cheshire
896 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
897 Need to shut down NATTraversals on exit
899 Revision 1.721 2007/10/01 18:42:07 cheshire
900 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
902 Revision 1.720 2007/09/29 20:40:19 cheshire
903 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
905 Revision 1.719 2007/09/27 22:23:56 cheshire
906 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
907 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
909 Revision 1.718 2007/09/27 22:02:33 cheshire
910 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
912 Revision 1.717 2007/09/27 21:21:39 cheshire
913 Export CompleteDeregistration so it's callable from other files
915 Revision 1.716 2007/09/27 02:12:21 cheshire
916 Updated GrantCacheExtensions degugging message to show new record lifetime
918 Revision 1.715 2007/09/27 01:20:06 cheshire
919 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
921 Revision 1.714 2007/09/27 00:37:01 cheshire
922 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
924 Revision 1.713 2007/09/27 00:25:39 cheshire
925 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
926 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
928 Revision 1.712 2007/09/26 23:16:58 cheshire
929 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
931 Revision 1.711 2007/09/26 22:06:02 cheshire
932 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
934 Revision 1.710 2007/09/26 00:49:46 cheshire
935 Improve packet logging to show sent and received packets,
936 transport protocol (UDP/TCP/TLS) and source/destination address:port
938 Revision 1.709 2007/09/21 21:12:36 cheshire
939 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
941 Revision 1.708 2007/09/20 23:13:37 cheshire
942 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
943 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
945 Revision 1.707 2007/09/20 02:29:37 cheshire
946 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
948 Revision 1.706 2007/09/20 01:13:19 cheshire
949 Export CacheGroupForName so it's callable from other files
951 Revision 1.705 2007/09/20 01:12:06 cheshire
952 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
954 Revision 1.704 2007/09/19 22:47:25 cheshire
955 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
957 Revision 1.703 2007/09/14 01:46:59 cheshire
958 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
960 Revision 1.702 2007/09/13 22:06:46 cheshire
961 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
962 Need to accept DNS responses where the query ID field matches, even if the source address does not
964 Revision 1.701 2007/09/12 23:22:32 cheshire
965 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
967 Revision 1.700 2007/09/12 23:03:08 cheshire
968 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
970 Revision 1.699 2007/09/12 22:19:28 cheshire
971 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
973 Revision 1.698 2007/09/12 22:13:27 cheshire
974 Remove DynDNSHostNames cleanly on shutdown
976 Revision 1.697 2007/09/12 01:44:47 cheshire
977 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
979 Revision 1.696 2007/09/12 01:26:08 cheshire
980 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
982 Revision 1.695 2007/09/11 19:19:16 cheshire
983 Correct capitalization of "uPNP" to "UPnP"
985 Revision 1.694 2007/09/10 22:06:51 cheshire
986 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
988 Revision 1.693 2007/09/07 22:24:36 vazquez
989 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
991 Revision 1.692 2007/09/07 00:12:09 cheshire
992 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
994 Revision 1.691 2007/09/05 22:25:01 vazquez
995 <rdar://problem/5400521> update_record mDNSResponder leak
997 Revision 1.690 2007/09/05 21:48:01 cheshire
998 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
999 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
1000 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
1001 otherwise those records will expire and vanish from the cache.
1003 Revision 1.689 2007/09/05 02:29:06 cheshire
1004 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
1005 Additional fixes to code implementing "NoAnswer" logic
1007 Revision 1.688 2007/08/31 22:56:39 cheshire
1008 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
1010 Revision 1.687 2007/08/31 19:53:14 cheshire
1011 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
1012 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
1014 Revision 1.686 2007/08/30 00:01:56 cheshire
1015 Added comment about SetTargetToHostName()
1017 Revision 1.685 2007/08/29 01:19:24 cheshire
1018 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
1019 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
1021 Revision 1.684 2007/08/28 23:58:42 cheshire
1022 Rename HostTarget -> AutoTarget
1024 Revision 1.683 2007/08/28 23:53:21 cheshire
1025 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
1027 Revision 1.682 2007/08/27 20:28:19 cheshire
1028 Improve "suspect uDNS response" log message
1030 Revision 1.681 2007/08/24 23:37:23 cheshire
1031 Added debugging message to show when ExtraResourceRecord callback gets invoked
1033 Revision 1.680 2007/08/24 00:15:19 cheshire
1034 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
1036 Revision 1.679 2007/08/23 21:47:09 vazquez
1037 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
1038 make sure we clean up port mappings on base stations by sending a lease value of 0,
1039 and only send NAT-PMP packets on private networks; also save some memory by
1040 not using packet structs in NATTraversals.
1042 Revision 1.678 2007/08/01 16:09:13 cheshire
1043 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
1045 Revision 1.677 2007/08/01 01:58:24 cheshire
1046 Added RecordType sanity check in mDNS_Register_internal
1048 Revision 1.676 2007/08/01 00:04:13 cheshire
1049 <rdar://problem/5261696> Crash in tcpKQSocketCallback
1050 Half-open TCP connections were not being cancelled properly
1052 Revision 1.675 2007/07/31 02:28:35 vazquez
1053 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
1055 Revision 1.674 2007/07/31 01:57:23 cheshire
1056 Adding code to respect TTL received in uDNS responses turned out to
1057 expose other problems; backing out change for now.
1059 Revision 1.673 2007/07/30 23:31:26 cheshire
1060 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
1062 Revision 1.672 2007/07/28 01:25:56 cheshire
1063 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
1065 Revision 1.671 2007/07/27 22:32:54 cheshire
1066 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
1067 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
1069 Revision 1.670 2007/07/27 20:54:43 cheshire
1070 Fixed code to respect real record TTL received in uDNS responses
1072 Revision 1.669 2007/07/27 20:09:32 cheshire
1073 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
1075 Revision 1.668 2007/07/27 19:58:47 cheshire
1076 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
1078 Revision 1.667 2007/07/27 19:52:10 cheshire
1079 Don't increment m->rrcache_active for no-cache add events
1081 Revision 1.666 2007/07/27 19:30:39 cheshire
1082 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
1083 to properly reflect tri-state nature of the possible responses
1085 Revision 1.665 2007/07/27 18:44:01 cheshire
1086 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
1088 Revision 1.664 2007/07/27 18:38:56 cheshire
1089 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
1091 Revision 1.663 2007/07/25 03:05:02 vazquez
1093 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
1094 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
1095 and a myriad of other security problems
1097 Revision 1.662 2007/07/24 20:22:46 cheshire
1098 Make sure all fields of main mDNS object are initialized correctly
1100 Revision 1.661 2007/07/21 00:54:45 cheshire
1101 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
1103 Revision 1.660 2007/07/20 20:00:45 cheshire
1104 "Legacy Browse" is better called "Automatic Browse"
1106 Revision 1.659 2007/07/20 00:54:18 cheshire
1107 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
1109 Revision 1.658 2007/07/18 02:28:57 cheshire
1110 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
1112 Revision 1.657 2007/07/18 00:57:10 cheshire
1113 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1114 Only need to call AddNewClientTunnel() for IPv6 addresses
1116 Revision 1.656 2007/07/16 23:54:48 cheshire
1117 <rdar://problem/5338850> Crash when removing or changing DNS keys
1119 Revision 1.655 2007/07/16 20:11:37 vazquez
1120 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
1121 Init LNT stuff and handle SSDP packets
1123 Revision 1.654 2007/07/12 23:30:23 cheshire
1124 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
1126 Revision 1.653 2007/07/12 02:51:27 cheshire
1127 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1129 Revision 1.652 2007/07/11 23:43:42 cheshire
1130 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
1132 Revision 1.651 2007/07/11 22:44:40 cheshire
1133 <rdar://problem/5328801> SIGHUP should purge the cache
1135 Revision 1.650 2007/07/11 21:34:09 cheshire
1136 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
1137 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
1139 Revision 1.649 2007/07/11 02:52:52 cheshire
1140 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
1141 In uDNS_RegisterService, set HostTarget for AutoTunnel services
1143 Revision 1.648 2007/07/09 23:48:12 cheshire
1144 Add parentheses around bitwise operation for clarity
1146 Revision 1.647 2007/07/06 21:17:55 cheshire
1147 Initialize m->retryGetAddr to timenow + 0x78000000;
1149 Revision 1.646 2007/07/06 18:55:49 cheshire
1150 Initialize m->NextScheduledNATOp
1152 Revision 1.645 2007/06/29 22:55:54 cheshire
1153 Move declaration of DNSServer *s; Fixed incomplete comment.
1155 Revision 1.644 2007/06/29 00:07:29 vazquez
1156 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
1158 Revision 1.643 2007/06/20 01:10:12 cheshire
1159 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
1161 Revision 1.642 2007/06/15 21:54:50 cheshire
1162 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
1164 Revision 1.641 2007/05/25 00:30:24 cheshire
1165 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
1166 status matches. This is particularly important when doing a private query for an SOA record,
1167 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
1168 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
1170 Revision 1.640 2007/05/25 00:25:44 cheshire
1171 <rdar://problem/5227737> Need to enhance putRData to output all current known types
1173 Revision 1.639 2007/05/23 00:51:33 cheshire
1174 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
1175 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
1176 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
1178 Revision 1.638 2007/05/23 00:43:16 cheshire
1179 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
1181 Revision 1.637 2007/05/14 23:53:00 cheshire
1182 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
1184 Revision 1.636 2007/05/10 23:27:15 cheshire
1185 Update mDNS_Deregister_internal debugging messages
1187 Revision 1.635 2007/05/07 20:43:45 cheshire
1188 <rdar://problem/4241419> Reduce the number of queries and announcements
1190 Revision 1.634 2007/05/04 22:09:08 cheshire
1191 Only do "restarting exponential backoff sequence" for mDNS questions
1192 In mDNS_RegisterInterface, only retrigger mDNS questions
1193 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
1195 Revision 1.633 2007/05/04 21:45:12 cheshire
1196 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
1198 Revision 1.632 2007/05/04 20:20:50 cheshire
1199 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1200 Need to set srs->nta = mDNSNULL; when regState_NoTarget
1202 Revision 1.631 2007/05/04 00:39:42 cheshire
1203 <rdar://problem/4410011> Eliminate looping SOA lookups
1204 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
1205 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
1207 Revision 1.630 2007/05/03 22:40:38 cheshire
1208 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
1210 Revision 1.629 2007/05/03 00:15:51 cheshire
1211 <rdar://problem/4410011> Eliminate looping SOA lookups
1213 Revision 1.628 2007/05/02 22:21:33 cheshire
1214 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1216 Revision 1.627 2007/04/30 19:29:13 cheshire
1217 Fix display of port number in "Updating DNS Server" message
1219 Revision 1.626 2007/04/30 04:21:13 cheshire
1220 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
1222 Revision 1.625 2007/04/28 01:34:21 cheshire
1223 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
1224 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
1226 Revision 1.624 2007/04/27 21:04:30 cheshire
1227 On network configuration change, need to call uDNS_RegisterSearchDomains
1229 Revision 1.623 2007/04/27 19:28:01 cheshire
1230 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
1231 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
1232 -- it would start a query and then quickly cancel it, and then when
1233 StartGetZoneData completed, it had a dangling pointer and crashed.)
1235 Revision 1.622 2007/04/26 16:09:22 cheshire
1236 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
1238 Revision 1.621 2007/04/26 15:43:22 cheshire
1239 Make sure DNSServer *s is non-null before using value in LogOperation
1241 Revision 1.620 2007/04/26 13:11:05 cheshire
1242 Fixed crash when logging out of VPN
1244 Revision 1.619 2007/04/26 00:35:15 cheshire
1245 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
1246 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
1247 inside the firewall may give answers where a public one gives none, and vice versa.)
1249 Revision 1.618 2007/04/25 19:26:01 cheshire
1250 m->NextScheduledQuery was getting set too early in SendQueries()
1251 Improved "SendQueries didn't send all its queries" debugging message
1253 Revision 1.617 2007/04/25 17:48:22 cheshire
1254 Update debugging message
1256 Revision 1.616 2007/04/25 16:38:32 cheshire
1257 If negative cache entry already exists, reactivate it instead of creating a new one
1259 Revision 1.615 2007/04/25 02:14:38 cheshire
1260 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
1261 Additional fixes to make LLQs work properly
1263 Revision 1.614 2007/04/23 21:52:45 cheshire
1264 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
1266 Revision 1.613 2007/04/23 04:58:20 cheshire
1267 <rdar://problem/5072548> Crash when setting extremely large TXT records
1269 Revision 1.612 2007/04/22 20:39:38 cheshire
1270 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
1272 Revision 1.611 2007/04/22 18:16:29 cheshire
1273 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
1275 Revision 1.610 2007/04/22 06:02:02 cheshire
1276 <rdar://problem/4615977> Query should immediately return failure when no server
1278 Revision 1.609 2007/04/20 21:17:24 cheshire
1279 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
1281 Revision 1.608 2007/04/20 19:45:31 cheshire
1282 In LogClientOperations mode, dump out unknown DNS packets in their entirety
1284 Revision 1.607 2007/04/19 23:56:25 cheshire
1285 Don't do cache-flush processing for LLQ answers
1287 Revision 1.606 2007/04/19 22:50:53 cheshire
1288 <rdar://problem/4246187> Identical client queries should reference a single shared core query
1290 Revision 1.605 2007/04/19 20:06:41 cheshire
1291 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
1293 Revision 1.604 2007/04/19 18:03:04 cheshire
1294 Add "const" declaration
1296 Revision 1.603 2007/04/06 21:00:25 cheshire
1297 Fix log message typo
1299 Revision 1.602 2007/04/05 22:55:35 cheshire
1300 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1302 Revision 1.601 2007/04/04 21:48:52 cheshire
1303 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1305 Revision 1.600 2007/04/04 01:31:33 cheshire
1306 Improve debugging message
1308 Revision 1.599 2007/04/04 00:03:26 cheshire
1309 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
1311 Revision 1.598 2007/04/03 19:43:16 cheshire
1312 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1314 Revision 1.597 2007/03/31 00:32:32 cheshire
1315 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
1317 Revision 1.596 2007/03/28 20:59:26 cheshire
1318 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1320 Revision 1.595 2007/03/26 23:48:16 cheshire
1321 <rdar://problem/4848295> Advertise model information via Bonjour
1322 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
1324 Revision 1.594 2007/03/26 23:05:05 cheshire
1325 <rdar://problem/5089257> Don't cache TSIG records
1327 Revision 1.593 2007/03/23 17:40:08 cheshire
1328 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
1330 Revision 1.592 2007/03/22 18:31:48 cheshire
1331 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1333 Revision 1.591 2007/03/22 00:49:19 cheshire
1334 <rdar://problem/4848295> Advertise model information via Bonjour
1336 Revision 1.590 2007/03/21 23:05:59 cheshire
1337 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1339 Revision 1.589 2007/03/20 15:37:19 cheshire
1340 Delete unnecessary log message
1342 Revision 1.588 2007/03/20 00:24:44 cheshire
1343 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
1345 Revision 1.587 2007/03/16 22:10:56 cheshire
1346 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
1348 Revision 1.586 2007/03/10 03:26:44 cheshire
1349 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1351 Revision 1.585 2007/03/10 02:02:58 cheshire
1352 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1353 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1355 Revision 1.584 2007/02/28 01:51:27 cheshire
1356 Added comment about reverse-order IP address
1358 Revision 1.583 2007/01/27 03:19:33 cheshire
1359 Need to initialize question->sock
1361 Revision 1.582 2007/01/25 00:40:16 cheshire
1362 Unified CNAME-following functionality into cache management code (which means CNAME-following
1363 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1365 Revision 1.581 2007/01/23 02:56:11 cheshire
1366 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1368 Revision 1.580 2007/01/19 21:17:33 cheshire
1369 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1371 Revision 1.579 2007/01/19 18:39:10 cheshire
1372 Fix a bunch of parameters that should have been declared "const"
1374 Revision 1.578 2007/01/10 22:51:57 cheshire
1375 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1377 Revision 1.577 2007/01/10 02:05:21 cheshire
1378 Delay uDNS_SetupDNSConfig() until *after* the platform layer
1379 has set up the interface list and security credentials
1381 Revision 1.576 2007/01/09 02:40:57 cheshire
1382 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1383 moved it to mDNS_Init() in mDNS.c (core code)
1385 Revision 1.575 2007/01/09 00:17:25 cheshire
1386 Improve "ERROR m->CurrentRecord already set" debugging messages
1388 Revision 1.574 2007/01/05 08:30:41 cheshire
1389 Trim excessive "$Log" checkin history from before 2006
1390 (checkin history still available via "cvs log ..." of course)
1392 Revision 1.573 2007/01/05 06:34:03 cheshire
1393 Improve "ERROR m->CurrentQuestion already set" debugging messages
1395 Revision 1.572 2007/01/04 23:11:11 cheshire
1396 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1397 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1399 Revision 1.571 2007/01/04 21:45:20 cheshire
1400 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1401 to do additional lock sanity checking around callback invocations
1403 Revision 1.570 2007/01/04 20:57:47 cheshire
1404 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
1406 Revision 1.569 2007/01/04 20:27:27 cheshire
1407 Change a LogMsg() to debugf()
1409 Revision 1.568 2007/01/04 02:39:53 cheshire
1410 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1412 Revision 1.567 2006/12/21 00:01:37 cheshire
1413 Tidy up code alignment
1415 Revision 1.566 2006/12/20 04:07:34 cheshire
1416 Remove uDNS_info substructure from AuthRecord_struct
1418 Revision 1.565 2006/12/19 22:49:23 cheshire
1419 Remove uDNS_info substructure from ServiceRecordSet_struct
1421 Revision 1.564 2006/12/19 02:38:20 cheshire
1422 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1424 Revision 1.563 2006/12/19 02:18:48 cheshire
1425 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1427 Revision 1.562 2006/12/16 01:58:31 cheshire
1428 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1430 Revision 1.561 2006/12/01 07:38:53 herscher
1431 Only perform cache workaround fix if query is wide-area
1433 Revision 1.560 2006/11/30 23:07:56 herscher
1434 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1436 Revision 1.559 2006/11/27 08:20:57 cheshire
1437 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
1439 Revision 1.558 2006/11/10 07:44:03 herscher
1440 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1442 Revision 1.557 2006/11/10 01:12:51 cheshire
1443 <rdar://problem/4829718> Incorrect TTL corrections
1445 Revision 1.556 2006/11/10 00:54:14 cheshire
1446 <rdar://problem/4816598> Changing case of Computer Name doesn't work
1448 Revision 1.555 2006/10/30 20:03:37 cheshire
1449 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
1451 Revision 1.554 2006/10/20 05:35:04 herscher
1452 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1454 Revision 1.553 2006/10/05 03:42:43 herscher
1455 Remove embedded uDNS_info struct in DNSQuestion_struct
1457 Revision 1.552 2006/09/15 21:20:15 cheshire
1458 Remove uDNS_info substructure from mDNS_struct
1460 Revision 1.551 2006/08/14 23:24:22 cheshire
1461 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1463 Revision 1.550 2006/07/27 17:58:34 cheshire
1464 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
1466 Revision 1.549 2006/07/20 22:07:31 mkrochma
1467 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
1468 More fixes for uninitialized variables
1470 Revision 1.548 2006/07/20 19:30:19 mkrochma
1471 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
1473 Revision 1.547 2006/07/15 02:31:30 cheshire
1474 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
1476 Revision 1.546 2006/07/07 01:09:09 cheshire
1477 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
1478 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
1480 Revision 1.545 2006/07/05 23:10:30 cheshire
1481 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1482 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
1484 Revision 1.544 2006/06/29 07:42:14 cheshire
1485 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
1487 Revision 1.543 2006/06/29 01:38:43 cheshire
1488 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
1490 Revision 1.542 2006/06/27 23:40:29 cheshire
1491 Fix typo in comment: mis-spelled "compile"
1493 Revision 1.541 2006/06/27 19:46:24 cheshire
1494 Updated comments and debugging messages
1496 Revision 1.540 2006/06/15 21:35:16 cheshire
1497 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
1498 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
1500 Revision 1.539 2006/06/08 23:45:46 cheshire
1501 Change SimultaneousProbe messages from debugf() to LogOperation()
1503 Revision 1.538 2006/03/19 17:13:06 cheshire
1504 <rdar://problem/4483117> Need faster purging of stale records
1505 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
1506 and reconfirm whole chain of antecedents ot once
1508 Revision 1.537 2006/03/19 02:00:07 cheshire
1509 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1511 Revision 1.536 2006/03/08 23:29:53 cheshire
1512 <rdar://problem/4468716> Improve "Service Renamed" log message
1514 Revision 1.535 2006/03/02 20:41:17 cheshire
1515 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1516 Minor code tidying and comments to reduce the risk of similar programming errors in future
1518 Revision 1.534 2006/03/02 03:25:46 cheshire
1519 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1520 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
1522 Revision 1.533 2006/02/26 00:54:41 cheshire
1523 Fixes to avoid code generation warning/error on FreeBSD 7
1527 #include "DNSCommon.h" // Defines general DNS untility routines
1528 #include "uDNS.h" // Defines entry points into unicast-specific routines
1530 // Disable certain benign warnings with Microsoft compilers
1531 #if(defined(_MSC_VER))
1532 // Disable "conditional expression is constant" warning for debug macros.
1533 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1534 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1535 #pragma warning(disable:4127)
1537 // Disable "assignment within conditional expression".
1538 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1539 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1540 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1541 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1542 #pragma warning(disable:4706)
1545 // Forward declarations
1546 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
);
1547 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
);
1549 // ***************************************************************************
1550 #if COMPILER_LIKES_PRAGMA_MARK
1551 #pragma mark - Program Constants
1557 // Any records bigger than this are considered 'large' records
1558 #define SmallRecordLimit 1024
1560 #define kMaxUpdateCredits 10
1561 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1563 mDNSexport
const char *const mDNS_DomainTypeNames
[] =
1565 "b._dns-sd._udp.", // Browse
1566 "db._dns-sd._udp.", // Default Browse
1567 "lb._dns-sd._udp.", // Automatic Browse
1568 "r._dns-sd._udp.", // Registration
1569 "dr._dns-sd._udp." // Default Registration
1572 #ifdef UNICAST_DISABLED
1573 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1576 // ***************************************************************************
1577 #if COMPILER_LIKES_PRAGMA_MARK
1579 #pragma mark - General Utility Functions
1582 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
1583 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
1585 mDNSexport
void SetNextQueryTime(mDNS
*const m
, const DNSQuestion
*const q
)
1587 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
1588 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
1591 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1) *(long*)0 = 0;
1594 if (ActiveQuestion(q
))
1596 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
1598 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
1599 if (!mDNSOpaque16IsZero(q
->TargetQID
) && !q
->LongLived
&& m
->SuppressStdPort53Queries
&& (sendtime
- m
->SuppressStdPort53Queries
< 0))
1600 sendtime
= m
->SuppressStdPort53Queries
;
1602 if (m
->NextScheduledQuery
- sendtime
> 0)
1603 m
->NextScheduledQuery
= sendtime
;
1607 mDNSexport CacheGroup
*CacheGroupForName(const mDNS
*const m
, const mDNSu32 slot
, const mDNSu32 namehash
, const domainname
*const name
)
1610 for (cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
1611 if (cg
->namehash
== namehash
&& SameDomainName(cg
->name
, name
))
1616 mDNSlocal CacheGroup
*CacheGroupForRecord(const mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
1618 return(CacheGroupForName(m
, slot
, rr
->namehash
, rr
->name
));
1621 mDNSlocal mDNSBool
AddressIsLocalSubnet(mDNS
*const m
, const mDNSInterfaceID InterfaceID
, const mDNSAddr
*addr
)
1623 NetworkInterfaceInfo
*intf
;
1625 if (addr
->type
== mDNSAddrType_IPv4
)
1627 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
1628 if (mDNSv4AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1629 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1630 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1631 if (((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) & intf
->mask
.ip
.v4
.NotAnInteger
) == 0)
1635 if (addr
->type
== mDNSAddrType_IPv6
)
1637 if (mDNSv6AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
1638 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1639 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
1640 if ((((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) & intf
->mask
.ip
.v6
.l
[0]) == 0) &&
1641 (((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) & intf
->mask
.ip
.v6
.l
[1]) == 0) &&
1642 (((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) & intf
->mask
.ip
.v6
.l
[2]) == 0) &&
1643 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) & intf
->mask
.ip
.v6
.l
[3]) == 0))
1650 mDNSlocal NetworkInterfaceInfo
*FirstInterfaceForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1652 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1653 while (intf
&& intf
->InterfaceID
!= InterfaceID
) intf
= intf
->next
;
1657 mDNSexport
char *InterfaceNameForID(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1659 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
1660 return(intf
? intf
->ifname
: mDNSNULL
);
1663 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1664 // Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
1665 mDNSlocal
void AnswerLocalQuestionWithLocalAuthRecord(mDNS
*const m
, DNSQuestion
*q
, AuthRecord
*rr
, QC_result AddRecord
)
1667 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1668 if (AddRecord
) rr
->AnsweredLocalQ
= mDNStrue
;
1669 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1670 if (q
->QuestionCallback
&& !q
->NoAnswer
)
1672 q
->CurrentAnswers
+= AddRecord
? 1 : -1;
1673 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
1675 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1678 // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
1679 // all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
1680 // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1681 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1682 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1683 mDNSlocal
void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS
*const m
, AuthRecord
*rr
, QC_result AddRecord
)
1685 if (m
->CurrentQuestion
)
1686 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
1688 m
->CurrentQuestion
= m
->LocalOnlyQuestions
;
1689 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewLocalOnlyQuestions
)
1691 DNSQuestion
*q
= m
->CurrentQuestion
;
1692 m
->CurrentQuestion
= q
->next
;
1693 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1694 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1697 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1698 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
1700 m
->CurrentQuestion
= m
->Questions
;
1701 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
1703 DNSQuestion
*q
= m
->CurrentQuestion
;
1704 m
->CurrentQuestion
= q
->next
;
1705 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1706 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1710 m
->CurrentQuestion
= mDNSNULL
;
1713 // ***************************************************************************
1714 #if COMPILER_LIKES_PRAGMA_MARK
1716 #pragma mark - Resource Record Utility Functions
1719 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1721 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1722 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1723 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1724 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1726 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1727 (ResourceRecordIsValidAnswer(RR) && \
1728 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1730 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1731 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1733 #define InitialAnnounceCount ((mDNSu8)8)
1735 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1736 // This means that because the announce interval is doubled after sending the first packet, the first
1737 // observed on-the-wire inter-packet interval between announcements is actually one second.
1738 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1739 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1740 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1741 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1743 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1744 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1745 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1747 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1748 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1749 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1750 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1752 #define MaxUnansweredQueries 4
1754 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1755 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1756 // TTL and rdata may differ.
1757 // This is used for cache flush management:
1758 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1759 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1761 // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
1763 #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
1765 mDNSlocal mDNSBool
SameResourceRecordNameClassInterface(const AuthRecord
*const r1
, const AuthRecord
*const r2
)
1767 if (!r1
) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse
); }
1768 if (!r2
) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse
); }
1769 if (r1
->resrec
.InterfaceID
&&
1770 r2
->resrec
.InterfaceID
&&
1771 r1
->resrec
.InterfaceID
!= r2
->resrec
.InterfaceID
) return(mDNSfalse
);
1773 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
&&
1774 r1
->resrec
.namehash
== r2
->resrec
.namehash
&&
1775 SameDomainName(r1
->resrec
.name
, r2
->resrec
.name
));
1778 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1779 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1780 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1781 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1782 // so a response of any type should match, even if it is not actually the type the client plans to use.
1784 // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
1785 // and require the rrtypes to match for the rdata to be considered potentially conflicting
1786 mDNSlocal mDNSBool
PacketRRMatchesSignature(const CacheRecord
*const pktrr
, const AuthRecord
*const authrr
)
1788 if (!pktrr
) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse
); }
1789 if (!authrr
) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse
); }
1790 if (pktrr
->resrec
.InterfaceID
&&
1791 authrr
->resrec
.InterfaceID
&&
1792 pktrr
->resrec
.InterfaceID
!= authrr
->resrec
.InterfaceID
) return(mDNSfalse
);
1793 if (!(authrr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) || authrr
->WakeUp
.HMAC
.l
[0])
1794 if (pktrr
->resrec
.rrtype
!= authrr
->resrec
.rrtype
) return(mDNSfalse
);
1796 pktrr
->resrec
.rrclass
== authrr
->resrec
.rrclass
&&
1797 pktrr
->resrec
.namehash
== authrr
->resrec
.namehash
&&
1798 SameDomainName(pktrr
->resrec
.name
, authrr
->resrec
.name
));
1801 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1802 // This is the information that the requester believes to be correct.
1803 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1804 // This is the information that we believe to be correct.
1805 // We've already determined that we plan to give this answer on this interface
1806 // (either the record is non-specific, or it is specific to this interface)
1807 // so now we just need to check the name, type, class, rdata and TTL.
1808 mDNSlocal mDNSBool
ShouldSuppressKnownAnswer(const CacheRecord
*const ka
, const AuthRecord
*const rr
)
1810 // If RR signature is different, or data is different, then don't suppress our answer
1811 if (!IdenticalResourceRecord(&ka
->resrec
, &rr
->resrec
)) return(mDNSfalse
);
1813 // If the requester's indicated TTL is less than half the real TTL,
1814 // we need to give our answer before the requester's copy expires.
1815 // If the requester's indicated TTL is at least half the real TTL,
1816 // then we can suppress our answer this time.
1817 // If the requester's indicated TTL is greater than the TTL we believe,
1818 // then that's okay, and we don't need to do anything about it.
1819 // (If two responders on the network are offering the same information,
1820 // that's okay, and if they are offering the information with different TTLs,
1821 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1822 return(mDNSBool
)(ka
->resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/ 2);
1825 mDNSlocal
void SetNextAnnounceProbeTime(mDNS
*const m
, const AuthRecord
*const rr
)
1827 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1829 //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1830 if (m
->NextScheduledProbe
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1831 m
->NextScheduledProbe
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1833 else if (rr
->AnnounceCount
&& ResourceRecordIsValidAnswer(rr
))
1835 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1836 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1840 mDNSlocal
void InitializeLastAPTime(mDNS
*const m
, AuthRecord
*const rr
)
1842 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1843 rr
->ThisAPInterval
= rr
->AddressProxy
.type
? mDNSPlatformOneSecond
: DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
);
1845 // To allow us to aggregate probes when a group of services are registered together,
1846 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1847 // 1/4 second wait; probe
1848 // 1/4 second wait; probe
1849 // 1/4 second wait; probe
1850 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1854 // If we have no probe suppression time set, or it is in the past, set it now
1855 if (m
->SuppressProbes
== 0 || m
->SuppressProbes
- m
->timenow
< 0)
1857 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ DefaultProbeIntervalForTypeUnique
);
1858 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1859 if (m
->SuppressProbes
- m
->NextScheduledProbe
>= 0)
1860 m
->SuppressProbes
= m
->NextScheduledProbe
;
1861 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1862 if (m
->SuppressProbes
- m
->NextScheduledQuery
>= 0)
1863 m
->SuppressProbes
= m
->NextScheduledQuery
;
1867 rr
->LastAPTime
= m
->SuppressProbes
- rr
->ThisAPInterval
;
1868 // Set LastMCTime to now, to inhibit multicast responses
1869 // (no need to send additional multicast responses when we're announcing anyway)
1870 rr
->LastMCTime
= m
->timenow
;
1871 rr
->LastMCInterface
= mDNSInterfaceMark
;
1873 // If this is a record type that's not going to probe, then delay its first announcement so that
1874 // it will go out synchronized with the first announcement for the other records that *are* probing.
1875 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1876 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1877 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1878 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1879 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1880 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
)
1881 rr
->LastAPTime
+= DefaultProbeIntervalForTypeUnique
* DefaultProbeCountForTypeUnique
+ rr
->ThisAPInterval
/ 2;
1883 // The exception is unique records that have already been verified and are just being updated
1884 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1885 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
1886 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1888 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1889 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1890 // After three probes one second apart with no answer, we conclude the client is now sleeping
1891 // and we can begin broadcasting our announcements to take over ownership of that IP address.
1892 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1893 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1894 if (rr
->AddressProxy
.type
) rr
->LastAPTime
= m
->timenow
;
1896 // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
1897 if (rr
->WakeUp
.HMAC
.l
[0] && rr
->resrec
.rrtype
== kDNSType_AAAA
)
1898 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
+ mDNSPlatformOneSecond
* 10;
1900 SetNextAnnounceProbeTime(m
, rr
);
1903 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1904 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1905 mDNSlocal
void SetTargetToHostName(mDNS
*const m
, AuthRecord
*const rr
)
1907 domainname
*const target
= GetRRDomainNameTarget(&rr
->resrec
);
1908 const domainname
*newname
= &m
->MulticastHostname
;
1910 if (!target
) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr
->resrec
.rrtype
);
1912 if (!(rr
->ForceMCast
|| rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&rr
->namestorage
)))
1914 const domainname
*const n
= GetServiceTarget(m
, rr
);
1918 if (target
&& SameDomainName(target
, newname
))
1919 debugf("SetTargetToHostName: Target of %##s is already %##s", rr
->resrec
.name
->c
, target
->c
);
1921 if (target
&& !SameDomainName(target
, newname
))
1923 AssignDomainName(target
, newname
);
1924 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
1926 // If we're in the middle of probing this record, we need to start again,
1927 // because changing its rdata may change the outcome of the tie-breaker.
1928 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1929 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
1931 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1932 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1933 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1934 if (rr
->RequireGoodbye
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
)
1935 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1936 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1938 rr
->AnnounceCount
= InitialAnnounceCount
;
1939 rr
->RequireGoodbye
= mDNSfalse
;
1940 InitializeLastAPTime(m
, rr
);
1944 mDNSlocal
void AcknowledgeRecord(mDNS
*const m
, AuthRecord
*const rr
)
1946 if (rr
->RecordCallback
)
1948 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1949 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1950 rr
->Acknowledged
= mDNStrue
;
1951 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1952 rr
->RecordCallback(m
, rr
, mStatus_NoError
);
1953 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1957 mDNSlocal
void ActivateUnicastRegistration(mDNS
*const m
, AuthRecord
*const rr
)
1960 rr
->AnnounceCount
= 0;
1961 rr
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
1962 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1963 rr
->state
= regState_FetchingZoneData
;
1964 rr
->uselease
= mDNStrue
;
1967 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1968 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1969 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1970 #define RecordIsLocalDuplicate(A,B) \
1971 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1973 // Exported so uDNS.c can call this
1974 mDNSexport mStatus
mDNS_Register_internal(mDNS
*const m
, AuthRecord
*const rr
)
1976 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
1978 AuthRecord
**p
= &m
->ResourceRecords
;
1979 AuthRecord
**d
= &m
->DuplicateRecords
;
1981 if ((mDNSs32
)rr
->resrec
.rroriginalttl
<= 0)
1982 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1984 if (!rr
->resrec
.RecordType
)
1985 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1987 if (m
->ShutdownTime
)
1988 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m
, rr
)); return(mStatus_ServiceNotRunning
); }
1990 if (m
->DivertMulticastAdvertisements
&& !AuthRecord_uDNS(rr
))
1992 mDNSInterfaceID previousID
= rr
->resrec
.InterfaceID
;
1993 if (rr
->resrec
.InterfaceID
== mDNSInterface_Any
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1994 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
1996 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
1997 if (intf
&& !intf
->Advertise
) rr
->resrec
.InterfaceID
= mDNSInterface_LocalOnly
;
1999 if (rr
->resrec
.InterfaceID
!= previousID
)
2000 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m
, rr
));
2003 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2004 while (*d
&& *d
!= rr
) d
=&(*d
)->next
;
2007 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
2008 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2009 return(mStatus_AlreadyRegistered
);
2012 if (rr
->DependentOn
)
2014 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
2015 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
2018 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
2019 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2020 return(mStatus_Invalid
);
2022 if (!(rr
->DependentOn
->resrec
.RecordType
& (kDNSRecordTypeUnique
| kDNSRecordTypeVerified
)))
2024 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
2025 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->DependentOn
->resrec
.RecordType
);
2026 return(mStatus_Invalid
);
2030 // If this resource record is referencing a specific interface, make sure it exists
2031 if (rr
->resrec
.InterfaceID
&& rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
2033 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2036 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr
->resrec
.InterfaceID
);
2037 return(mStatus_BadReferenceErr
);
2041 rr
->next
= mDNSNULL
;
2043 // Field Group 1: The actual information pertaining to this resource record
2044 // Set up by client prior to call
2046 // Field Group 2: Persistent metadata for Authoritative Records
2047 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2048 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2049 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2050 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2051 // rr->Callback = already set in mDNS_SetupResourceRecord
2052 // rr->Context = already set in mDNS_SetupResourceRecord
2053 // rr->RecordType = already set in mDNS_SetupResourceRecord
2054 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2055 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2056 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
2057 if (rr
->AutoTarget
&& target
) target
->c
[0] = 0;
2059 // Field Group 3: Transient state for Authoritative Records
2060 rr
->Acknowledged
= mDNSfalse
;
2061 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
2062 rr
->AnnounceCount
= InitialAnnounceCount
;
2063 rr
->RequireGoodbye
= mDNSfalse
;
2064 rr
->AnsweredLocalQ
= mDNSfalse
;
2065 rr
->IncludeInProbe
= mDNSfalse
;
2066 rr
->ImmedUnicast
= mDNSfalse
;
2067 rr
->SendNSECNow
= mDNSNULL
;
2068 rr
->ImmedAnswer
= mDNSNULL
;
2069 rr
->ImmedAdditional
= mDNSNULL
;
2070 rr
->SendRNow
= mDNSNULL
;
2071 rr
->v4Requester
= zerov4Addr
;
2072 rr
->v6Requester
= zerov6Addr
;
2073 rr
->NextResponse
= mDNSNULL
;
2074 rr
->NR_AnswerTo
= mDNSNULL
;
2075 rr
->NR_AdditionalTo
= mDNSNULL
;
2076 if (!rr
->AutoTarget
) InitializeLastAPTime(m
, rr
);
2077 // rr->LastAPTime = Set for us in InitializeLastAPTime()
2078 // rr->LastMCTime = Set for us in InitializeLastAPTime()
2079 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
2080 rr
->NewRData
= mDNSNULL
;
2081 rr
->newrdlength
= 0;
2082 rr
->UpdateCallback
= mDNSNULL
;
2083 rr
->UpdateCredits
= kMaxUpdateCredits
;
2084 rr
->NextUpdateCredit
= 0;
2085 rr
->UpdateBlocked
= 0;
2087 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
2088 if (rr
->WakeUp
.HMAC
.l
[0] && !rr
->AddressProxy
.type
) rr
->AnnounceCount
= 2;
2090 // Field Group 4: Transient uDNS state for Authoritative Records
2091 rr
->state
= regState_Zero
;
2095 rr
->updateid
= zeroID
;
2096 rr
->zone
= rr
->resrec
.name
;
2097 rr
->UpdateServer
= zeroAddr
;
2098 rr
->UpdatePort
= zeroIPPort
;
2103 rr
->InFlightRData
= 0;
2104 rr
->InFlightRDLen
= 0;
2105 rr
->QueuedRData
= 0;
2106 rr
->QueuedRDLen
= 0;
2108 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
2109 // rr->resrec.name->c = MUST be set by client
2110 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
2111 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
2112 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
2113 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2116 SetTargetToHostName(m
, rr
); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2119 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
2120 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
2123 if (!ValidateDomainName(rr
->resrec
.name
))
2124 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2126 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2127 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2128 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2129 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rr
->resrec
.rdlength
== 0) { rr
->resrec
.rdlength
= 1; rr
->resrec
.rdata
->u
.txt
.c
[0] = 0; }
2131 // Don't do this until *after* we've set rr->resrec.rdlength
2132 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
2133 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
2135 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
2136 rr
->resrec
.rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(&rr
->resrec
);
2138 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
2140 // If this is supposed to be unique, make sure we don't have any name conflicts
2141 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2143 const AuthRecord
*s1
= rr
->RRSet
? rr
->RRSet
: rr
;
2144 for (r
= m
->ResourceRecords
; r
; r
=r
->next
)
2146 const AuthRecord
*s2
= r
->RRSet
? r
->RRSet
: r
;
2147 if (s1
!= s2
&& SameResourceRecordSignature(r
, rr
) && !IdenticalSameNameRecord(&r
->resrec
, &rr
->resrec
))
2150 if (r
) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2152 debugf("Name conflict %p %##s (%s)", rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2153 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2154 rr
->resrec
.rroriginalttl
= 0;
2155 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2156 m
->NextScheduledResponse
= m
->timenow
;
2161 // Now that we've finished building our new record, make sure it's not identical to one we already have
2162 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (RecordIsLocalDuplicate(r
, rr
)) break;
2166 debugf("Adding to duplicate list %p %s", rr
, ARDisplayString(m
,rr
));
2168 // If the previous copy of this record is already verified unique,
2169 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2170 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
2171 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2172 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& r
->resrec
.RecordType
== kDNSRecordTypeVerified
)
2177 debugf("Adding to active record list %p %s", rr
, ARDisplayString(m
,rr
));
2178 if (!m
->NewLocalRecords
) m
->NewLocalRecords
= rr
;
2182 if (!AuthRecord_uDNS(rr
))
2184 // For records that are not going to probe, acknowledge them right away
2185 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
&& rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
2186 AcknowledgeRecord(m
, rr
);
2188 #ifndef UNICAST_DISABLED
2191 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
2192 ActivateUnicastRegistration(m
, rr
);
2196 return(mStatus_NoError
);
2199 mDNSlocal
void RecordProbeFailure(mDNS
*const m
, const AuthRecord
*const rr
)
2201 m
->ProbeFailTime
= m
->timenow
;
2202 m
->NumFailedProbes
++;
2203 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2204 // If a bunch of hosts have all been configured with the same name, then they'll all
2205 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2206 // up to name-10. After that they'll start adding random increments in the range 1-100,
2207 // so they're more likely to branch out in the available namespace and settle on a set of
2208 // unique names quickly. If after five more tries the host is still conflicting, then we
2209 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
2210 if (m
->NumFailedProbes
>= 15)
2212 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
2213 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2214 m
->NumFailedProbes
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2218 mDNSlocal
void CompleteRDataUpdate(mDNS
*const m
, AuthRecord
*const rr
)
2220 RData
*OldRData
= rr
->resrec
.rdata
;
2221 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
); // Update our rdata
2222 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
2223 if (rr
->UpdateCallback
)
2224 rr
->UpdateCallback(m
, rr
, OldRData
); // ... and let the client know
2227 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2228 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2229 // Exported so uDNS.c can call this
2230 mDNSexport mStatus
mDNS_Deregister_internal(mDNS
*const m
, AuthRecord
*const rr
, mDNS_Dereg_type drt
)
2233 mDNSu8 RecordType
= rr
->resrec
.RecordType
;
2234 AuthRecord
**p
= &m
->ResourceRecords
; // Find this record in our list of active records
2236 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2240 // We found our record on the main list. See if there are any duplicates that need special handling.
2241 if (drt
== mDNS_Dereg_conflict
) // If this was a conflict, see that all duplicates get the same treatment
2243 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2244 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2245 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
) if (RecordIsLocalDuplicate(r2
, rr
)) r2
->ProbeCount
= 0xFF;
2249 // Before we delete the record (and potentially send a goodbye packet)
2250 // first see if we have a record on the duplicate list ready to take over from it.
2251 AuthRecord
**d
= &m
->DuplicateRecords
;
2252 while (*d
&& !RecordIsLocalDuplicate(*d
, rr
)) d
=&(*d
)->next
;
2255 AuthRecord
*dup
= *d
;
2256 debugf("Duplicate record %p taking over from %p %##s (%s)",
2257 dup
, rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2258 *d
= dup
->next
; // Cut replacement record from DuplicateRecords list
2259 dup
->next
= rr
->next
; // And then...
2260 rr
->next
= dup
; // ... splice it in right after the record we're about to delete
2261 dup
->resrec
.RecordType
= rr
->resrec
.RecordType
;
2262 dup
->ProbeCount
= rr
->ProbeCount
;
2263 dup
->AnnounceCount
= rr
->AnnounceCount
;
2264 dup
->RequireGoodbye
= rr
->RequireGoodbye
;
2265 dup
->AnsweredLocalQ
= rr
->AnsweredLocalQ
;
2266 dup
->ImmedAnswer
= rr
->ImmedAnswer
;
2267 dup
->ImmedUnicast
= rr
->ImmedUnicast
;
2268 dup
->ImmedAdditional
= rr
->ImmedAdditional
;
2269 dup
->v4Requester
= rr
->v4Requester
;
2270 dup
->v6Requester
= rr
->v6Requester
;
2271 dup
->ThisAPInterval
= rr
->ThisAPInterval
;
2272 dup
->LastAPTime
= rr
->LastAPTime
;
2273 dup
->LastMCTime
= rr
->LastMCTime
;
2274 dup
->LastMCInterface
= rr
->LastMCInterface
;
2275 dup
->UpdateServer
= rr
->UpdateServer
;
2276 dup
->UpdatePort
= rr
->UpdatePort
;
2277 dup
->Private
= rr
->Private
;
2278 dup
->state
= rr
->state
;
2279 rr
->RequireGoodbye
= mDNSfalse
;
2280 rr
->AnsweredLocalQ
= mDNSfalse
;
2286 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2287 p
= &m
->DuplicateRecords
;
2288 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
2289 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2290 if (*p
) rr
->RequireGoodbye
= mDNSfalse
;
2291 if (*p
) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2292 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2297 // No need to log an error message if we already know this is a potentially repeated deregistration
2298 if (drt
!= mDNS_Dereg_repeat
)
2299 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr
, ARDisplayString(m
,rr
));
2300 return(mStatus_BadReferenceErr
);
2303 // If this is a shared record and we've announced it at least once,
2304 // we need to retract that announcement before we delete the record
2306 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2307 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
2308 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2309 // mechanism to cope with the client callback modifying the question list while that's happening.
2310 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2311 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2312 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2313 // records, thereby invoking yet more callbacks, without limit.
2314 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2315 // actual goodbye packets.
2317 #ifndef UNICAST_DISABLED
2318 if (AuthRecord_uDNS(rr
) && rr
->RequireGoodbye
)
2320 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2321 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2322 uDNS_DeregisterRecord(m
, rr
);
2323 // At this point unconditionally we bail out
2324 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2325 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2326 // process and will complete asynchronously. Either way we don't need to do anything more here.
2327 return(mStatus_NoError
);
2329 #endif // UNICAST_DISABLED
2331 if (RecordType
== kDNSRecordTypeShared
&& (rr
->RequireGoodbye
|| rr
->AnsweredLocalQ
))
2333 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m
, rr
));
2334 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
2335 rr
->resrec
.rroriginalttl
= 0;
2336 rr
->ImmedAnswer
= mDNSInterfaceMark
;
2337 if (m
->NextScheduledResponse
- (m
->timenow
+ mDNSPlatformOneSecond
/10) >= 0)
2338 m
->NextScheduledResponse
= (m
->timenow
+ mDNSPlatformOneSecond
/10);
2342 *p
= rr
->next
; // Cut this record from the list
2343 // If someone is about to look at this, bump the pointer forward
2344 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
2345 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
2346 rr
->next
= mDNSNULL
;
2348 if (RecordType
== kDNSRecordTypeUnregistered
)
2349 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m
, rr
));
2350 else if (RecordType
== kDNSRecordTypeDeregistering
)
2351 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m
, rr
));
2354 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m
, rr
));
2355 rr
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2358 if ((drt
== mDNS_Dereg_conflict
|| drt
== mDNS_Dereg_repeat
) && RecordType
== kDNSRecordTypeShared
)
2359 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2360 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2362 // If we have an update queued up which never executed, give the client a chance to free that memory
2363 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
2365 if (rr
->nta
) { CancelGetZoneData(m
, rr
->nta
); rr
->nta
= mDNSNULL
; }
2366 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
2368 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2369 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2370 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2371 // so any attempt to touch rr after this is likely to lead to a crash.
2372 if (drt
!= mDNS_Dereg_conflict
)
2374 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2375 if (rr
->RecordCallback
)
2376 rr
->RecordCallback(m
, rr
, mStatus_MemFree
); // MUST NOT touch rr after this
2377 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2381 RecordProbeFailure(m
, rr
);
2382 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2383 if (rr
->RecordCallback
)
2384 rr
->RecordCallback(m
, rr
, mStatus_NameConflict
); // MUST NOT touch rr after this
2385 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2386 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2387 // Note that with all the client callbacks going on, by the time we get here all the
2388 // records we marked may have been explicitly deregistered by the client anyway.
2389 r2
= m
->DuplicateRecords
;
2392 if (r2
->ProbeCount
!= 0xFF) r2
= r2
->next
;
2393 else { mDNS_Deregister_internal(m
, r2
, mDNS_Dereg_conflict
); r2
= m
->DuplicateRecords
; }
2397 return(mStatus_NoError
);
2400 // ***************************************************************************
2401 #if COMPILER_LIKES_PRAGMA_MARK
2403 #pragma mark - Packet Sending Functions
2406 mDNSlocal
void AddRecordToResponseList(AuthRecord
***nrpp
, AuthRecord
*rr
, AuthRecord
*add
)
2408 if (rr
->NextResponse
== mDNSNULL
&& *nrpp
!= &rr
->NextResponse
)
2411 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2412 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2413 // The referenced record will definitely be acceptable (by recursive application of this rule)
2414 if (add
&& add
->NR_AdditionalTo
) add
= add
->NR_AdditionalTo
;
2415 rr
->NR_AdditionalTo
= add
;
2416 *nrpp
= &rr
->NextResponse
;
2418 debugf("AddRecordToResponseList: %##s (%s) already in list", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2421 mDNSlocal
void AddAdditionalsToResponseList(mDNS
*const m
, AuthRecord
*ResponseRecords
, AuthRecord
***nrpp
, const mDNSInterfaceID InterfaceID
)
2423 AuthRecord
*rr
, *rr2
;
2424 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // For each record we plan to put
2426 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2427 // later in the "for" loop, and we will follow further "additional" links then.)
2428 if (rr
->Additional1
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional1
, InterfaceID
))
2429 AddRecordToResponseList(nrpp
, rr
->Additional1
, rr
);
2431 if (rr
->Additional2
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional2
, InterfaceID
))
2432 AddRecordToResponseList(nrpp
, rr
->Additional2
, rr
);
2434 // For SRV records, automatically add the Address record(s) for the target host
2435 if (rr
->resrec
.rrtype
== kDNSType_SRV
)
2437 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2438 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2439 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2440 rr
->resrec
.rdatahash
== rr2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2441 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, rr2
->resrec
.name
))
2442 AddRecordToResponseList(nrpp
, rr2
, rr
);
2444 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
)) // For A or AAAA, put counterpart as additional
2446 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
2447 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2448 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
2449 rr
->resrec
.namehash
== rr2
->resrec
.namehash
&& // ... and have the same name
2450 SameDomainName(rr
->resrec
.name
, rr2
->resrec
.name
))
2451 AddRecordToResponseList(nrpp
, rr2
, rr
);
2453 else if (rr
->resrec
.rrtype
== kDNSType_PTR
) // For service PTR, see if we want to add DeviceInfo record
2455 if (ResourceRecordIsValidInterfaceAnswer(&m
->DeviceInfo
, InterfaceID
) &&
2456 SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2457 AddRecordToResponseList(nrpp
, &m
->DeviceInfo
, rr
);
2462 mDNSlocal
void SendDelayedUnicastResponse(mDNS
*const m
, const mDNSAddr
*const dest
, const mDNSInterfaceID InterfaceID
)
2465 AuthRecord
*ResponseRecords
= mDNSNULL
;
2466 AuthRecord
**nrp
= &ResponseRecords
;
2468 // Make a list of all our records that need to be unicast to this destination
2469 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2471 // If we find we can no longer unicast this answer, clear ImmedUnicast
2472 if (rr
->ImmedAnswer
== mDNSInterfaceMark
||
2473 mDNSSameIPv4Address(rr
->v4Requester
, onesIPv4Addr
) ||
2474 mDNSSameIPv6Address(rr
->v6Requester
, onesIPv6Addr
) )
2475 rr
->ImmedUnicast
= mDNSfalse
;
2477 if (rr
->ImmedUnicast
&& rr
->ImmedAnswer
== InterfaceID
)
2478 if ((dest
->type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->v4Requester
, dest
->ip
.v4
)) ||
2479 (dest
->type
== mDNSAddrType_IPv6
&& mDNSSameIPv6Address(rr
->v6Requester
, dest
->ip
.v6
)))
2481 rr
->ImmedAnswer
= mDNSNULL
; // Clear the state fields
2482 rr
->ImmedUnicast
= mDNSfalse
;
2483 rr
->v4Requester
= zerov4Addr
;
2484 rr
->v6Requester
= zerov6Addr
;
2485 if (rr
->NextResponse
== mDNSNULL
&& nrp
!= &rr
->NextResponse
) // rr->NR_AnswerTo
2486 { rr
->NR_AnswerTo
= (mDNSu8
*)~0; *nrp
= rr
; nrp
= &rr
->NextResponse
; }
2490 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
2492 while (ResponseRecords
)
2494 mDNSu8
*responseptr
= m
->omsg
.data
;
2496 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2498 // Put answers in the packet
2499 while (ResponseRecords
&& ResponseRecords
->NR_AnswerTo
)
2501 rr
= ResponseRecords
;
2502 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2503 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2504 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2505 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2506 if (!newptr
&& m
->omsg
.h
.numAnswers
) break; // If packet full, send it now
2507 if (newptr
) responseptr
= newptr
;
2508 ResponseRecords
= rr
->NextResponse
;
2509 rr
->NextResponse
= mDNSNULL
;
2510 rr
->NR_AnswerTo
= mDNSNULL
;
2511 rr
->NR_AdditionalTo
= mDNSNULL
;
2512 rr
->RequireGoodbye
= mDNStrue
;
2515 // Add additionals, if there's space
2516 while (ResponseRecords
&& !ResponseRecords
->NR_AnswerTo
)
2518 rr
= ResponseRecords
;
2519 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2520 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2521 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2522 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2524 if (newptr
) responseptr
= newptr
;
2525 if (newptr
&& m
->omsg
.h
.numAnswers
) rr
->RequireGoodbye
= mDNStrue
;
2526 else if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) rr
->ImmedAnswer
= mDNSInterfaceMark
;
2527 ResponseRecords
= rr
->NextResponse
;
2528 rr
->NextResponse
= mDNSNULL
;
2529 rr
->NR_AnswerTo
= mDNSNULL
;
2530 rr
->NR_AdditionalTo
= mDNSNULL
;
2533 if (m
->omsg
.h
.numAnswers
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, mDNSInterface_Any
, mDNSNULL
, dest
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2537 mDNSexport
void CompleteDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2539 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2540 // it should go ahead and immediately dispose of this registration
2541 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
2542 rr
->RequireGoodbye
= mDNSfalse
;
2543 if (rr
->AnsweredLocalQ
) { AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNSfalse
); rr
->AnsweredLocalQ
= mDNSfalse
; }
2544 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
); // Don't touch rr after this
2547 // Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2548 // the record list and/or question list.
2549 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2550 mDNSlocal
void DiscardDeregistrations(mDNS
*const m
)
2552 if (m
->CurrentRecord
)
2553 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
2554 m
->CurrentRecord
= m
->ResourceRecords
;
2556 while (m
->CurrentRecord
)
2558 AuthRecord
*rr
= m
->CurrentRecord
;
2559 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2560 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2562 m
->CurrentRecord
= rr
->next
;
2566 mDNSlocal mStatus
GetLabelDecimalValue(const mDNSu8
*const src
, mDNSu8
*dst
)
2569 if (src
[0] < 1 || src
[0] > 3) return(mStatus_Invalid
);
2570 for (i
=1; i
<=src
[0]; i
++)
2572 if (src
[i
] < '0' || src
[i
] > '9') return(mStatus_Invalid
);
2573 val
= val
* 10 + src
[i
] - '0';
2575 if (val
> 255) return(mStatus_Invalid
);
2577 return(mStatus_NoError
);
2580 mDNSlocal mStatus
GetIPv4FromName(mDNSAddr
*const a
, const domainname
*const name
)
2582 int skip
= CountLabels(name
) - 6;
2583 if (skip
< 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2584 if (GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+3)->c
, &a
->ip
.v4
.b
[0]) ||
2585 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+2)->c
, &a
->ip
.v4
.b
[1]) ||
2586 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+1)->c
, &a
->ip
.v4
.b
[2]) ||
2587 GetLabelDecimalValue(SkipLeadingLabels(name
, skip
+0)->c
, &a
->ip
.v4
.b
[3])) return mStatus_Invalid
;
2588 a
->type
= mDNSAddrType_IPv4
;
2589 return(mStatus_NoError
);
2592 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
2593 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
2594 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2596 mDNSlocal mStatus
GetIPv6FromName(mDNSAddr
*const a
, const domainname
*const name
)
2599 const domainname
*n
;
2601 int skip
= CountLabels(name
) - 34;
2602 if (skip
< 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name
); return mStatus_Invalid
; }
2604 n
= SkipLeadingLabels(name
, skip
);
2605 for (i
=0; i
<16; i
++)
2607 if (n
->c
[0] != 1) return mStatus_Invalid
;
2608 l
= HexVal(n
->c
[1]);
2609 n
= (const domainname
*)(n
->c
+ 2);
2611 if (n
->c
[0] != 1) return mStatus_Invalid
;
2612 h
= HexVal(n
->c
[1]);
2613 n
= (const domainname
*)(n
->c
+ 2);
2615 if (l
<0 || h
<0) return mStatus_Invalid
;
2616 a
->ip
.v6
.b
[15-i
] = (h
<< 4) | l
;
2619 a
->type
= mDNSAddrType_IPv6
;
2620 return(mStatus_NoError
);
2623 mDNSlocal mDNSs32
ReverseMapDomainType(const domainname
*const name
)
2625 int skip
= CountLabels(name
) - 2;
2628 const domainname
*suffix
= SkipLeadingLabels(name
, skip
);
2629 if (SameDomainName(suffix
, (const domainname
*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4
;
2630 if (SameDomainName(suffix
, (const domainname
*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6
;
2632 return(mDNSAddrType_None
);
2635 mDNSlocal
void SendARP(mDNS
*const m
, const mDNSu8 op
, const AuthRecord
*const rr
,
2636 const mDNSu8
*const spa
, const mDNSu8
*const tha
, const mDNSu8
*const tpa
, const mDNSu8
*const dst
)
2639 mDNSu8
*ptr
= m
->omsg
.data
;
2640 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, rr
->resrec
.InterfaceID
);
2641 if (!intf
) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr
->resrec
.InterfaceID
, ARDisplayString(m
,rr
)); return; }
2643 // 0x00 Destination address
2644 for (i
=0; i
<6; i
++) *ptr
++ = dst
[i
];
2646 // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
2647 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
2649 // 0x0C ARP Ethertype (0x0806)
2650 *ptr
++ = 0x08; *ptr
++ = 0x06;
2653 *ptr
++ = 0x00; *ptr
++ = 0x01; // Hardware address space; Ethernet = 1
2654 *ptr
++ = 0x08; *ptr
++ = 0x00; // Protocol address space; IP = 0x0800
2655 *ptr
++ = 6; // Hardware address length
2656 *ptr
++ = 4; // Protocol address length
2657 *ptr
++ = 0x00; *ptr
++ = op
; // opcode; Request = 1, Response = 2
2659 // 0x16 Sender hardware address (our MAC address)
2660 for (i
=0; i
<6; i
++) *ptr
++ = intf
->MAC
.b
[i
];
2662 // 0x1C Sender protocol address
2663 for (i
=0; i
<4; i
++) *ptr
++ = spa
[i
];
2665 // 0x20 Target hardware address
2666 for (i
=0; i
<6; i
++) *ptr
++ = tha
[i
];
2668 // 0x26 Target protocol address
2669 for (i
=0; i
<4; i
++) *ptr
++ = tpa
[i
];
2671 // 0x2A Total ARP Packet length 42 bytes
2672 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, rr
->resrec
.InterfaceID
);
2675 mDNSlocal
void SetupOwnerOpt(const mDNS
*const m
, const NetworkInterfaceInfo
*const intf
, rdataOPT
*const owner
)
2677 owner
->u
.owner
.vers
= 0;
2678 owner
->u
.owner
.seq
= m
->SleepSeqNum
;
2679 owner
->u
.owner
.HMAC
= m
->PrimaryMAC
;
2680 owner
->u
.owner
.IMAC
= intf
->MAC
;
2681 owner
->u
.owner
.password
= zeroEthAddr
;
2683 // Don't try to compute the optlen until *after* we've set up the data fields
2684 // Right now the DNSOpt_Owner_Space macro does not depend on the owner->u.owner being set up correctly, but in the future it might
2685 owner
->opt
= kDNSOpt_Owner
;
2686 owner
->optlen
= DNSOpt_Owner_Space(&m
->PrimaryMAC
, &intf
->MAC
) - 4;
2689 mDNSlocal
void GrantUpdateCredit(AuthRecord
*rr
)
2691 if (++rr
->UpdateCredits
>= kMaxUpdateCredits
) rr
->NextUpdateCredit
= 0;
2692 else rr
->NextUpdateCredit
= NonZeroTime(rr
->NextUpdateCredit
+ kUpdateCreditRefreshInterval
);
2695 // Note about acceleration of announcements to facilitate automatic coalescing of
2696 // multiple independent threads of announcements into a single synchronized thread:
2697 // The announcements in the packet may be at different stages of maturity;
2698 // One-second interval, two-second interval, four-second interval, and so on.
2699 // After we've put in all the announcements that are due, we then consider
2700 // whether there are other nearly-due announcements that are worth accelerating.
2701 // To be eligible for acceleration, a record MUST NOT be older (further along
2702 // its timeline) than the most mature record we've already put in the packet.
2703 // In other words, younger records can have their timelines accelerated to catch up
2704 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
2705 // Older records cannot have their timelines accelerated; this would just widen
2706 // the gap between them and their younger bretheren and get them even more out of sync.
2708 // Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
2709 // the record list and/or question list.
2710 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2711 mDNSlocal
void SendResponses(mDNS
*const m
)
2714 AuthRecord
*rr
, *r2
;
2715 mDNSs32 maxExistingAnnounceInterval
= 0;
2716 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
2718 m
->NextScheduledResponse
= m
->timenow
+ 0x78000000;
2720 if (m
->SleepState
== SleepState_Transferring
) RetrySPSRegistrations(m
);
2722 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2723 if (rr
->ImmedUnicast
)
2725 mDNSAddr v4
= { mDNSAddrType_IPv4
, {{{0}}} };
2726 mDNSAddr v6
= { mDNSAddrType_IPv6
, {{{0}}} };
2727 v4
.ip
.v4
= rr
->v4Requester
;
2728 v6
.ip
.v6
= rr
->v6Requester
;
2729 if (!mDNSIPv4AddressIsZero(rr
->v4Requester
)) SendDelayedUnicastResponse(m
, &v4
, rr
->ImmedAnswer
);
2730 if (!mDNSIPv6AddressIsZero(rr
->v6Requester
)) SendDelayedUnicastResponse(m
, &v6
, rr
->ImmedAnswer
);
2731 if (rr
->ImmedUnicast
)
2733 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m
, rr
));
2734 rr
->ImmedUnicast
= mDNSfalse
;
2739 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
2742 // Run through our list of records, and decide which ones we're going to announce on all interfaces
2743 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2745 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
2746 if (TimeToAnnounceThisRecord(rr
, m
->timenow
) && ResourceRecordIsValidAnswer(rr
))
2748 if (rr
->AddressProxy
.type
)
2750 rr
->AnnounceCount
--;
2751 rr
->ThisAPInterval
*= 2;
2752 rr
->LastAPTime
= m
->timenow
;
2753 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
2755 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
));
2756 SendARP(m
, 1, rr
, rr
->AddressProxy
.ip
.v4
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, onesEthAddr
.b
);
2758 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
2760 //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
2761 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2766 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2767 if (maxExistingAnnounceInterval
< rr
->ThisAPInterval
)
2768 maxExistingAnnounceInterval
= rr
->ThisAPInterval
;
2769 if (rr
->UpdateBlocked
) rr
->UpdateBlocked
= 0;
2774 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
2775 // Eligible records that are more than half-way to their announcement time are accelerated
2776 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2777 if ((rr
->resrec
.InterfaceID
&& rr
->ImmedAnswer
) ||
2778 (rr
->ThisAPInterval
<= maxExistingAnnounceInterval
&&
2779 TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2) &&
2780 !rr
->AddressProxy
.type
&& // Don't include ARP Annoucements when considering which records to accelerate
2781 ResourceRecordIsValidAnswer(rr
)))
2782 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
2784 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
2785 // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
2786 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
2787 // then all that means is that it won't get sent -- which would not be the end of the world.
2788 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2790 if (rr
->ImmedAnswer
&& rr
->resrec
.rrtype
== kDNSType_SRV
)
2791 for (r2
=m
->ResourceRecords
; r2
; r2
=r2
->next
) // Scan list of resource records
2792 if (RRTypeIsAddressType(r2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
2793 ResourceRecordIsValidAnswer(r2
) && // ... which are valid for answer ...
2794 rr
->LastMCTime
- r2
->LastMCTime
>= 0 && // ... which we have not sent recently ...
2795 rr
->resrec
.rdatahash
== r2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
2796 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, r2
->resrec
.name
) &&
2797 (rr
->ImmedAnswer
== mDNSInterfaceMark
|| rr
->ImmedAnswer
== r2
->resrec
.InterfaceID
))
2798 r2
->ImmedAdditional
= r2
->resrec
.InterfaceID
; // ... then mark this address record for sending too
2799 // We also make sure we send the DeviceInfo TXT record too, if necessary
2800 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
2801 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
2802 if (rr
->ImmedAnswer
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->resrec
.rrtype
== kDNSType_PTR
)
2803 if (ResourceRecordIsValidAnswer(&m
->DeviceInfo
) && SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
2805 if (!m
->DeviceInfo
.ImmedAnswer
) m
->DeviceInfo
.ImmedAnswer
= rr
->ImmedAnswer
;
2806 else m
->DeviceInfo
.ImmedAnswer
= mDNSInterfaceMark
;
2810 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
2811 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
2812 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
2813 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
2814 // -- 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
2815 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
2816 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2817 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2819 if (rr
->ImmedAnswer
) // If we're sending this as answer, see that its whole RRSet is similarly marked
2821 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2822 if (ResourceRecordIsValidAnswer(r2
))
2823 if (r2
->ImmedAnswer
!= mDNSInterfaceMark
&&
2824 r2
->ImmedAnswer
!= rr
->ImmedAnswer
&& SameResourceRecordSignature(r2
, rr
))
2825 r2
->ImmedAnswer
= !r2
->ImmedAnswer
? rr
->ImmedAnswer
: mDNSInterfaceMark
;
2827 else if (rr
->ImmedAdditional
) // If we're sending this as additional, see that its whole RRSet is similarly marked
2829 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2830 if (ResourceRecordIsValidAnswer(r2
))
2831 if (r2
->ImmedAdditional
!= rr
->ImmedAdditional
&& SameResourceRecordSignature(r2
, rr
))
2832 r2
->ImmedAdditional
= rr
->ImmedAdditional
;
2836 // Now set SendRNow state appropriately
2837 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2839 if (rr
->ImmedAnswer
== mDNSInterfaceMark
) // Sending this record on all appropriate interfaces
2841 rr
->SendRNow
= !intf
? mDNSNULL
: (rr
->resrec
.InterfaceID
) ? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
2842 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional if sending as answer
2843 rr
->LastMCTime
= m
->timenow
;
2844 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2845 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
2846 if (TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2))
2848 rr
->AnnounceCount
--;
2849 rr
->ThisAPInterval
*= 2;
2850 rr
->LastAPTime
= m
->timenow
;
2851 debugf("Announcing %##s (%s) %d", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->AnnounceCount
);
2854 else if (rr
->ImmedAnswer
) // Else, just respond to a single query on single interface:
2856 rr
->SendRNow
= rr
->ImmedAnswer
; // Just respond on that interface
2857 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional too
2858 rr
->LastMCTime
= m
->timenow
;
2859 rr
->LastMCInterface
= rr
->ImmedAnswer
;
2861 SetNextAnnounceProbeTime(m
, rr
);
2862 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2866 // *** 2. Loop through interface list, sending records as appropriate
2871 const int OwnerRecordSpace
= (m
->AnnounceOwner
&& intf
->MAC
.l
[0]) ? DNSOpt_Header_Space
+ DNSOpt_Owner_Space(&m
->PrimaryMAC
, &intf
->MAC
) : 0;
2873 int numAnnounce
= 0;
2875 mDNSu8
*responseptr
= m
->omsg
.data
;
2877 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2879 // First Pass. Look for:
2880 // 1. Deregistering records that need to send their goodbye packet
2881 // 2. Updated records that need to retract their old data
2882 // 3. Answers and announcements we need to send
2883 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2885 if (rr
->SendRNow
== intf
->InterfaceID
)
2888 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2890 newptr
= PutRR_OS_TTL(responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2891 if (newptr
) { responseptr
= newptr
; numDereg
++; }
2893 else if (rr
->NewRData
&& !m
->SleepState
) // If we have new data for this record
2895 RData
*OldRData
= rr
->resrec
.rdata
;
2896 mDNSu16 oldrdlength
= rr
->resrec
.rdlength
;
2897 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2898 if (ResourceRecordIsValidAnswer(rr
) && rr
->RequireGoodbye
)
2900 newptr
= PutRR_OS_TTL(responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2901 if (newptr
) { responseptr
= newptr
; numDereg
++; rr
->RequireGoodbye
= mDNSfalse
; }
2903 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2904 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
2905 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2906 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2907 newptr
= PutRR_OS(responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2908 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2909 if (newptr
) { responseptr
= newptr
; rr
->RequireGoodbye
= mDNStrue
; }
2910 SetNewRData(&rr
->resrec
, OldRData
, oldrdlength
);
2914 mDNSu8 active
= (m
->SleepState
!= SleepState_Sleeping
|| intf
->SPSAddr
[0].type
|| intf
->SPSAddr
[1].type
|| intf
->SPSAddr
[2].type
);
2915 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2916 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2917 newptr
= PutRR_OS_TTL(responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, active
? rr
->resrec
.rroriginalttl
: 0);
2918 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2921 responseptr
= newptr
;
2922 rr
->RequireGoodbye
= active
;
2923 if (rr
->LastAPTime
== m
->timenow
) numAnnounce
++; else numAnswer
++;
2926 // The first time through (pktcount==0), if this record is verified unique
2927 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2928 if (!pktcount
&& active
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= mDNSInterfaceMark
;
2931 if (newptr
) // If succeeded in sending, advance to next interface
2933 // If sending on all interfaces, go to next interface; else we're finished now
2934 if (rr
->ImmedAnswer
== mDNSInterfaceMark
&& rr
->resrec
.InterfaceID
== mDNSInterface_Any
)
2935 rr
->SendRNow
= GetNextActiveInterfaceID(intf
);
2937 rr
->SendRNow
= mDNSNULL
;
2942 // Second Pass. Add additional records, if there's space.
2943 newptr
= responseptr
;
2944 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2945 if (rr
->ImmedAdditional
== intf
->InterfaceID
)
2946 if (ResourceRecordIsValidAnswer(rr
))
2948 // If we have at least one answer already in the packet, then plan to add additionals too
2949 mDNSBool SendAdditional
= (m
->omsg
.h
.numAnswers
> 0);
2951 // If we're not planning to send any additionals, but this record is a unique one, then
2952 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2953 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2954 if (!SendAdditional
&& (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
))
2956 const AuthRecord
*a
;
2957 for (a
= m
->ResourceRecords
; a
; a
=a
->next
)
2958 if (a
->LastMCTime
== m
->timenow
&&
2959 a
->LastMCInterface
== intf
->InterfaceID
&&
2960 SameResourceRecordSignature(a
, rr
)) { SendAdditional
= mDNStrue
; break; }
2962 if (!SendAdditional
) // If we don't want to send this after all,
2963 rr
->ImmedAdditional
= mDNSNULL
; // then cancel its ImmedAdditional field
2964 else if (newptr
) // Else, try to add it if we can
2966 // The first time through (pktcount==0), if this record is verified unique
2967 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2968 if (!pktcount
&& rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->SendNSECNow
) rr
->SendNSECNow
= mDNSInterfaceMark
;
2970 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2971 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2972 newptr
= PutRR_OS(newptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2973 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2976 responseptr
= newptr
;
2977 rr
->ImmedAdditional
= mDNSNULL
;
2978 rr
->RequireGoodbye
= mDNStrue
;
2979 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2980 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2981 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2982 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2983 rr
->LastMCTime
= m
->timenow
;
2984 rr
->LastMCInterface
= intf
->InterfaceID
;
2989 // Third Pass. Add NSEC records, if there's space.
2990 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2991 if (rr
->SendNSECNow
== mDNSInterfaceMark
|| rr
->SendNSECNow
== intf
->InterfaceID
)
2994 mDNS_SetupResourceRecord(&nsec
, mDNSNULL
, mDNSInterface_Any
, kDNSType_NSEC
, rr
->resrec
.rroriginalttl
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
2995 nsec
.resrec
.rrclass
|= kDNSClass_UniqueRRSet
;
2996 AssignDomainName(&nsec
.namestorage
, rr
->resrec
.name
);
2997 mDNSPlatformMemZero(nsec
.rdatastorage
.u
.nsec
.bitmap
, sizeof(nsec
.rdatastorage
.u
.nsec
.bitmap
));
2998 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
2999 if (ResourceRecordIsValidAnswer(r2
) && SameResourceRecordNameClassInterface(r2
, rr
))
3001 if (r2
->resrec
.rrtype
>= kDNSQType_ANY
) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m
, r2
)); break; }
3002 else nsec
.rdatastorage
.u
.nsec
.bitmap
[r2
->resrec
.rrtype
>> 3] |= 128 >> (r2
->resrec
.rrtype
& 7);
3004 newptr
= responseptr
;
3005 if (!r2
) // If we successfully built our NSEC record, add it to the packet now
3007 newptr
= PutRR_OS(responseptr
, &m
->omsg
.h
.numAdditionals
, &nsec
.resrec
);
3008 if (newptr
) responseptr
= newptr
;
3011 // If we successfully put the NSEC record, clear the SendNSECNow flag
3012 // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
3013 if (newptr
|| rr
->SendNSECNow
== mDNSInterfaceMark
)
3015 rr
->SendNSECNow
= mDNSNULL
;
3016 // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
3017 for (r2
= rr
->next
; r2
; r2
=r2
->next
)
3018 if (SameResourceRecordNameClassInterface(r2
, rr
))
3019 if (r2
->SendNSECNow
== mDNSInterfaceMark
|| r2
->SendNSECNow
== intf
->InterfaceID
)
3020 r2
->SendNSECNow
= mDNSNULL
;
3024 if (m
->omsg
.h
.numAnswers
|| m
->omsg
.h
.numAdditionals
)
3026 // If we have data to send, add OWNER option if necessary, then send packet
3028 if (OwnerRecordSpace
)
3031 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
3032 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
3033 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
3034 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
3035 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[0]);
3036 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
);
3037 if (newptr
) { responseptr
= newptr
; LogSPS("SendResponses put %s", ARDisplayString(m
, &opt
)); }
3038 else LogMsg("SendResponses: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3039 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAdditionals
, ARDisplayString(m
, &opt
));
3042 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
3043 numDereg
, numDereg
== 1 ? "" : "s",
3044 numAnnounce
, numAnnounce
== 1 ? "" : "s",
3045 numAnswer
, numAnswer
== 1 ? "" : "s",
3046 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s", intf
->InterfaceID
);
3047 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3048 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3049 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
3050 if (++pktcount
>= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount
); break; }
3051 // There might be more things to send on this interface, so go around one more time and try again.
3053 else // Nothing more to send on this interface; go to next
3055 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3056 #if MDNS_DEBUGMSGS && 0
3057 const char *const msg
= next
? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3058 debugf(msg
, intf
, next
);
3061 pktcount
= 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
3066 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3069 if (m
->CurrentRecord
)
3070 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3071 m
->CurrentRecord
= m
->ResourceRecords
;
3072 while (m
->CurrentRecord
)
3074 rr
= m
->CurrentRecord
;
3075 m
->CurrentRecord
= rr
->next
;
3079 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3080 LogMsg("SendResponses: No active interface to send: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
3081 rr
->SendRNow
= mDNSNULL
;
3084 if (rr
->ImmedAnswer
)
3086 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
3088 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
3089 CompleteDeregistration(m
, rr
); // Don't touch rr after this
3092 rr
->ImmedAnswer
= mDNSNULL
;
3093 rr
->ImmedUnicast
= mDNSfalse
;
3094 rr
->v4Requester
= zerov4Addr
;
3095 rr
->v6Requester
= zerov6Addr
;
3099 verbosedebugf("SendResponses: Next in %ld ticks", m
->NextScheduledResponse
- m
->timenow
);
3102 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3103 // so we want to be lazy about how frequently we do it.
3104 // 1. If a cache record is currently referenced by *no* active questions,
3105 // then we don't mind expiring it up to a minute late (who will know?)
3106 // 2. Else, if a cache record is due for some of its final expiration queries,
3107 // we'll allow them to be late by up to 2% of the TTL
3108 // 3. Else, if a cache record has completed all its final expiration queries without success,
3109 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3110 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3111 // so allow at most 1/10 second lateness
3112 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
3113 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
3114 #define CacheCheckGracePeriod(RR) ( \
3115 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
3116 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
3117 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
3118 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
3119 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
3121 // Note: MUST call SetNextCacheCheckTime any time we change:
3123 // rr->resrec.rroriginalttl
3124 // rr->UnansweredQueries
3125 // rr->CRActiveQuestion
3126 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3127 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3128 mDNSlocal
void SetNextCacheCheckTime(mDNS
*const m
, CacheRecord
*const rr
)
3130 rr
->NextRequiredQuery
= RRExpireTime(rr
);
3132 // If we have an active question, then see if we want to schedule a refresher query for this record.
3133 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3134 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3136 rr
->NextRequiredQuery
-= TicksTTL(rr
)/20 * (MaxUnansweredQueries
- rr
->UnansweredQueries
);
3137 rr
->NextRequiredQuery
+= mDNSRandom((mDNSu32
)TicksTTL(rr
)/50);
3138 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3139 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
),
3140 (rr
->NextRequiredQuery
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
));
3143 if (m
->NextCacheCheck
- (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
)) > 0)
3144 m
->NextCacheCheck
= (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
));
3146 if (rr
->DelayDelivery
)
3147 if (m
->NextCacheCheck
- rr
->DelayDelivery
> 0)
3148 m
->NextCacheCheck
= rr
->DelayDelivery
;
3151 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
3152 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
3153 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
3154 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3156 mDNSlocal mStatus
mDNS_Reconfirm_internal(mDNS
*const m
, CacheRecord
*const rr
, mDNSu32 interval
)
3158 if (interval
< kMinimumReconfirmTime
)
3159 interval
= kMinimumReconfirmTime
;
3160 if (interval
> 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
3161 interval
= 0x10000000;
3163 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3164 if (RRExpireTime(rr
) - m
->timenow
> (mDNSs32
)((interval
* 4) / 3))
3166 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3167 // For all the reconfirmations in a given batch, we want to use the same random value
3168 // so that the reconfirmation questions can be grouped into a single query packet
3169 if (!m
->RandomReconfirmDelay
) m
->RandomReconfirmDelay
= 1 + mDNSRandom(0x3FFFFFFF);
3170 interval
+= m
->RandomReconfirmDelay
% ((interval
/3) + 1);
3171 rr
->TimeRcvd
= m
->timenow
- (mDNSs32
)interval
* 3;
3172 rr
->resrec
.rroriginalttl
= (interval
* 4 + mDNSPlatformOneSecond
- 1) / mDNSPlatformOneSecond
;
3173 SetNextCacheCheckTime(m
, rr
);
3175 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
3176 RRExpireTime(rr
) - m
->timenow
, CRDisplayString(m
, rr
), rr
->CRActiveQuestion
);
3177 return(mStatus_NoError
);
3180 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
3182 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3183 // It also appends to the list of known answer records that need to be included,
3184 // and updates the forcast for the size of the known answer section.
3185 mDNSlocal mDNSBool
BuildQuestion(mDNS
*const m
, DNSMessage
*query
, mDNSu8
**queryptr
, DNSQuestion
*q
,
3186 CacheRecord
***kalistptrptr
, mDNSu32
*answerforecast
)
3188 mDNSBool ucast
= (q
->LargeAnswers
|| q
->RequestUnicast
) && m
->CanReceiveUnicastOn5353
;
3189 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3190 const mDNSu8
*const limit
= query
->data
+ NormalMaxDNSMessageData
;
3191 mDNSu8
*newptr
= putQuestion(query
, *queryptr
, limit
- *answerforecast
, &q
->qname
, q
->qtype
, (mDNSu16
)(q
->qclass
| ucbit
));
3194 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3199 mDNSu32 forecast
= *answerforecast
;
3200 const mDNSu32 slot
= HashSlot(&q
->qname
);
3201 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3203 CacheRecord
**ka
= *kalistptrptr
; // Make a working copy of the pointer we're going to update
3205 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3206 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3207 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not already in the known answer list
3208 rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3209 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3210 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
> // and its half-way-to-expiry time is at least 1 second away
3211 mDNSPlatformOneSecond
) // (also ensures we never include goodbye records with TTL=1)
3213 *ka
= rr
; // Link this record into our known answer chain
3214 ka
= &rr
->NextInKAList
;
3215 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3216 forecast
+= 12 + rr
->resrec
.rdestimate
;
3217 // If we're trying to put more than one question in this packet, and it doesn't fit
3218 // then undo that last question and try again next time
3219 if (query
->h
.numQuestions
> 1 && newptr
+ forecast
>= limit
)
3221 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3222 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ forecast
- query
->data
);
3223 query
->h
.numQuestions
--;
3224 ka
= *kalistptrptr
; // Go back to where we started and retract these answer records
3225 while (*ka
) { CacheRecord
*c
= *ka
; *ka
= mDNSNULL
; ka
= &c
->NextInKAList
; }
3226 return(mDNSfalse
); // Return false, so we'll try again in the next packet
3230 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3231 *queryptr
= newptr
; // Update the packet pointer
3232 *answerforecast
= forecast
; // Update the forecast
3233 *kalistptrptr
= ka
; // Update the known answer list pointer
3234 if (ucast
) q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3236 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // For every resource record in our cache,
3237 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
3238 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not in the known answer list
3239 SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) // which answers our question
3241 rr
->UnansweredQueries
++; // indicate that we're expecting a response
3242 rr
->LastUnansweredTime
= m
->timenow
;
3243 SetNextCacheCheckTime(m
, rr
);
3250 // When we have a query looking for a specified name, but there appear to be no answers with
3251 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
3252 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
3253 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
3254 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
3255 // A typical reconfirmation scenario might go like this:
3256 // Depth 0: Name "myhost.local" has no address records
3257 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
3258 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
3259 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
3260 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
3261 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
3262 mDNSlocal
void ReconfirmAntecedents(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const int depth
)
3267 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth
, name
->c
);
3268 FORALL_CACHERECORDS(slot
, cg
, cr
)
3270 domainname
*crtarget
= GetRRDomainNameTarget(&cr
->resrec
);
3271 if (crtarget
&& cr
->resrec
.rdatahash
== namehash
&& SameDomainName(crtarget
, name
))
3273 LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth
, CRDisplayString(m
, cr
));
3274 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
3275 if (depth
< 5) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, depth
+1);
3280 // If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
3281 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
3282 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
3283 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
3284 mDNSlocal
const CacheRecord
*CacheHasAddressTypeForName(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
)
3286 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(name
), namehash
, name
);
3287 const CacheRecord
*cr
= cg
? cg
->members
: mDNSNULL
;
3288 while (cr
&& !RRTypeIsAddressType(cr
->resrec
.rrtype
)) cr
=cr
->next
;
3292 mDNSlocal
const CacheRecord
*FindSPSInCache1(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*const c0
, const CacheRecord
*const c1
)
3294 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(&q
->qname
), q
->qnamehash
, &q
->qname
);
3295 const CacheRecord
*cr
, *bestcr
= mDNSNULL
;
3296 mDNSu32 bestmetric
= 1000000;
3297 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
3298 if (cr
->resrec
.rrtype
== kDNSType_PTR
&& cr
->resrec
.rdlength
>= 6) // If record is PTR type, with long enough name,
3299 if (cr
!= c0
&& cr
!= c1
) // that's not one we've seen before,
3300 if (SameNameRecordAnswersQuestion(&cr
->resrec
, q
)) // and answers our browse query,
3301 if (!IdenticalSameNameRecord(&cr
->resrec
, &m
->SPSRecords
.RR_PTR
.resrec
)) // and is not our own advertised service...
3303 mDNSu32 metric
= SPSMetric(cr
->resrec
.rdata
->u
.name
.c
);
3304 if (bestmetric
> metric
) { bestmetric
= metric
; bestcr
= cr
; }
3309 // Finds the three best Sleep Proxies we currently have in our cache
3310 mDNSexport
void FindSPSInCache(mDNS
*const m
, const DNSQuestion
*const q
, const CacheRecord
*sps
[3])
3312 sps
[0] = FindSPSInCache1(m
, q
, mDNSNULL
, mDNSNULL
);
3313 sps
[1] = !sps
[0] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], mDNSNULL
);
3314 sps
[2] = !sps
[1] ? mDNSNULL
: FindSPSInCache1(m
, q
, sps
[0], sps
[1]);
3317 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3318 mDNSlocal
void ExpireDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
)
3321 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3324 mDNSlocal
void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
, mDNSInterfaceID InterfaceID
)
3327 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
3330 mDNSlocal mDNSBool
SuppressOnThisInterface(const DupSuppressInfo ds
[DupSuppressInfoSize
], const NetworkInterfaceInfo
* const intf
)
3333 mDNSBool v4
= !intf
->IPv4Available
; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3334 mDNSBool v6
= !intf
->IPv6Available
; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3335 for (i
=0; i
<DupSuppressInfoSize
; i
++)
3336 if (ds
[i
].InterfaceID
== intf
->InterfaceID
)
3338 if (ds
[i
].Type
== mDNSAddrType_IPv4
) v4
= mDNStrue
;
3339 else if (ds
[i
].Type
== mDNSAddrType_IPv6
) v6
= mDNStrue
;
3340 if (v4
&& v6
) return(mDNStrue
);
3345 mDNSlocal
int RecordDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 Time
, mDNSInterfaceID InterfaceID
, mDNSs32 Type
)
3349 // See if we have this one in our list somewhere already
3350 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Type
== Type
) break;
3352 // If not, find a slot we can re-use
3353 if (i
>= DupSuppressInfoSize
)
3356 for (j
=1; j
<DupSuppressInfoSize
&& ds
[i
].InterfaceID
; j
++)
3357 if (!ds
[j
].InterfaceID
|| ds
[j
].Time
- ds
[i
].Time
< 0)
3361 // Record the info about this query we saw
3363 ds
[i
].InterfaceID
= InterfaceID
;
3369 mDNSlocal mDNSBool
AccelerateThisQuery(mDNS
*const m
, DNSQuestion
*q
)
3371 // If more than 90% of the way to the query time, we should unconditionally accelerate it
3372 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/10))
3375 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3376 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/2))
3378 // We forecast: qname (n) type (2) class (2)
3379 mDNSu32 forecast
= (mDNSu32
)DomainNameLength(&q
->qname
) + 4;
3380 const mDNSu32 slot
= HashSlot(&q
->qname
);
3381 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3382 const CacheRecord
*rr
;
3383 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
3384 if (rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
3385 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
3386 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
>= 0 && // and it is less than half-way to expiry
3387 rr
->NextRequiredQuery
- (m
->timenow
+ q
->ThisQInterval
) > 0)// and we'll ask at least once again before NextRequiredQuery
3389 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3390 forecast
+= 12 + rr
->resrec
.rdestimate
;
3391 if (forecast
>= 512) return(mDNSfalse
); // If this would add 512 bytes or more to the packet, don't accelerate
3399 // How Standard Queries are generated:
3400 // 1. The Question Section contains the question
3401 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3403 // How Probe Queries are generated:
3404 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3405 // if some other host is already using *any* records with this name, we want to know about it.
3406 // 2. The Authority Section contains the proposed values we intend to use for one or more
3407 // of our records with that name (analogous to the Update section of DNS Update packets)
3408 // because if some other host is probing at the same time, we each want to know what the other is
3409 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3411 mDNSlocal
void SendQueries(mDNS
*const m
)
3419 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3420 mDNSs32 maxExistingQuestionInterval
= 0;
3421 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
3422 CacheRecord
*KnownAnswerList
= mDNSNULL
;
3424 // 1. If time for a query, work out what we need to do
3425 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
3429 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
3430 // to their NextRequiredQuery to be worth batching them together with this one
3431 FORALL_CACHERECORDS(slot
, cg
, rr
)
3432 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3433 if (m
->timenow
+ TicksTTL(rr
)/50 - rr
->NextRequiredQuery
>= 0)
3435 debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr
->UnansweredQueries
, CRDisplayString(m
, rr
));
3436 q
= rr
->CRActiveQuestion
;
3437 ExpireDupSuppressInfoOnInterface(q
->DupSuppress
, m
->timenow
- TicksTTL(rr
)/20, rr
->resrec
.InterfaceID
);
3438 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
3439 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
3440 if (q
->Target
.type
) q
->SendQNow
= mDNSInterfaceMark
; // If targeted query, mark it
3441 else if (!mDNSOpaque16IsZero(q
->TargetQID
)) { q
->LastQTime
= m
->timenow
- q
->ThisQInterval
; rr
->UnansweredQueries
++; }
3442 else if (q
->SendQNow
== mDNSNULL
) q
->SendQNow
= rr
->resrec
.InterfaceID
;
3443 else if (q
->SendQNow
!= rr
->resrec
.InterfaceID
) q
->SendQNow
= mDNSInterfaceMark
;
3446 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
3447 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
3449 // Scan our list of questions to see which:
3450 // *WideArea* queries need to be sent
3451 // *unicast* queries need to be sent
3452 // *multicast* queries we're definitely going to send
3453 if (m
->CurrentQuestion
)
3454 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3455 m
->CurrentQuestion
= m
->Questions
;
3456 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3458 q
= m
->CurrentQuestion
;
3459 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
)) uDNS_CheckCurrentQuestion(m
);
3460 else if (mDNSOpaque16IsZero(q
->TargetQID
) && q
->Target
.type
&& (q
->SendQNow
|| TimeToSendThisQuestion(q
, m
->timenow
)))
3462 mDNSu8
*qptr
= m
->omsg
.data
;
3463 const mDNSu8
*const limit
= m
->omsg
.data
+ sizeof(m
->omsg
.data
);
3465 // 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
3466 if (!q
->LocalSocket
) q
->LocalSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
3469 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, QueryFlags
);
3470 qptr
= putQuestion(&m
->omsg
, qptr
, limit
, &q
->qname
, q
->qtype
, q
->qclass
);
3471 mDNSSendDNSMessage(m
, &m
->omsg
, qptr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->Target
, q
->TargetPort
, mDNSNULL
, mDNSNULL
);
3472 q
->ThisQInterval
*= QuestionIntervalStep
;
3474 if (q
->ThisQInterval
> MaxQuestionInterval
)
3475 q
->ThisQInterval
= MaxQuestionInterval
;
3476 q
->LastQTime
= m
->timenow
;
3477 q
->LastQTxTime
= m
->timenow
;
3478 q
->RecentAnswerPkts
= 0;
3479 q
->SendQNow
= mDNSNULL
;
3480 q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
3482 else if (mDNSOpaque16IsZero(q
->TargetQID
) && !q
->Target
.type
&& TimeToSendThisQuestion(q
, m
->timenow
))
3484 //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3485 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3486 if (maxExistingQuestionInterval
< q
->ThisQInterval
)
3487 maxExistingQuestionInterval
= q
->ThisQInterval
;
3489 // If m->CurrentQuestion wasn't modified out from under us, advance it now
3490 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
3491 // m->CurrentQuestion point to the right question
3492 if (q
== m
->CurrentQuestion
) m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
3494 m
->CurrentQuestion
= mDNSNULL
;
3496 // Scan our list of questions
3497 // (a) to see if there are any more that are worth accelerating, and
3498 // (b) to update the state variables for *all* the questions we're going to send
3499 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
3500 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
3501 // 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.
3502 m
->NextScheduledQuery
= m
->timenow
+ 0x78000000;
3503 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3505 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
||
3506 (!q
->Target
.type
&& ActiveQuestion(q
) && q
->ThisQInterval
<= maxExistingQuestionInterval
&& AccelerateThisQuery(m
,q
))))
3508 // If at least halfway to next query time, advance to next interval
3509 // If less than halfway to next query time, then
3510 // treat this as logically a repeat of the last transmission, without advancing the interval
3511 if (m
->timenow
- (q
->LastQTime
+ q
->ThisQInterval
/2) >= 0)
3513 //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3514 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
3515 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
3516 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->ThisQInterval
/ InitialQuestionInterval
, q
->RequestUnicast
);
3517 q
->ThisQInterval
*= QuestionIntervalStep
;
3518 if (q
->ThisQInterval
> MaxQuestionInterval
)
3519 q
->ThisQInterval
= MaxQuestionInterval
;
3520 else if (q
->CurrentAnswers
== 0 && q
->ThisQInterval
== InitialQuestionInterval
* QuestionIntervalStep3
&& !q
->RequestUnicast
&&
3521 !(RRTypeIsAddressType(q
->qtype
) && CacheHasAddressTypeForName(m
, &q
->qname
, q
->qnamehash
)))
3523 // Generally don't need to log this.
3524 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
3525 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
3526 // and when there simply happen to be no instances of the service the client is looking
3527 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
3528 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3529 q
->qname
.c
, DNSTypeName(q
->qtype
));
3530 // Sending third query, and no answers yet; time to begin doubting the source
3531 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
3535 // Mark for sending. (If no active interfaces, then don't even try.)
3536 q
->SendOnAll
= (q
->SendQNow
== mDNSInterfaceMark
);
3539 q
->SendQNow
= !intf
? mDNSNULL
: (q
->InterfaceID
) ? q
->InterfaceID
: intf
->InterfaceID
;
3540 q
->LastQTime
= m
->timenow
;
3543 // If we recorded a duplicate suppression for this question less than half an interval ago,
3544 // then we consider it recent enough that we don't need to do an identical query ourselves.
3545 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
- q
->ThisQInterval
/2);
3547 q
->LastQTxTime
= m
->timenow
;
3548 q
->RecentAnswerPkts
= 0;
3549 if (q
->RequestUnicast
) q
->RequestUnicast
--;
3551 // For all questions (not just the ones we're sending) check what the next scheduled event will be
3552 SetNextQueryTime(m
,q
);
3556 // 2. Scan our authoritative RR list to see what probes we might need to send
3557 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
3559 m
->NextScheduledProbe
= m
->timenow
+ 0x78000000;
3561 if (m
->CurrentRecord
)
3562 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3563 m
->CurrentRecord
= m
->ResourceRecords
;
3564 while (m
->CurrentRecord
)
3566 AuthRecord
*rr
= m
->CurrentRecord
;
3567 m
->CurrentRecord
= rr
->next
;
3568 if (!AuthRecord_uDNS(rr
) && rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) // For all records that are still probing...
3570 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3571 if (m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) < 0)
3573 SetNextAnnounceProbeTime(m
, rr
);
3575 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3576 else if (rr
->ProbeCount
)
3578 if (rr
->AddressProxy
.type
== mDNSAddrType_IPv4
)
3580 char *ifname
= InterfaceNameForID(m
, rr
->resrec
.InterfaceID
);
3581 if (!ifname
) ifname
= "<NULL InterfaceID>";
3582 LogSPS("SendQueries ARP Probe %d %s %s", rr
->ProbeCount
, ifname
, ARDisplayString(m
,rr
));
3583 SendARP(m
, 1, rr
, zerov4Addr
.b
, zeroEthAddr
.b
, rr
->AddressProxy
.ip
.v4
.b
, rr
->WakeUp
.IMAC
.b
);
3585 else if (rr
->AddressProxy
.type
== mDNSAddrType_IPv6
)
3587 //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
3588 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
3590 // Mark for sending. (If no active interfaces, then don't even try.)
3591 rr
->SendRNow
= (!intf
|| rr
->WakeUp
.HMAC
.l
[0]) ? mDNSNULL
: rr
->resrec
.InterfaceID
? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
3592 rr
->LastAPTime
= m
->timenow
;
3593 // When we have a late conflict that resets a record to probing state we use a special marker value greater
3594 // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
3595 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
3596 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
3598 SetNextAnnounceProbeTime(m
, rr
);
3599 if (rr
->ProbeCount
== 0)
3601 // If this is the last probe for this record, then see if we have any matching records
3602 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
3604 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
)
3605 if (r2
->resrec
.RecordType
== kDNSRecordTypeUnique
&& RecordIsLocalDuplicate(r2
, rr
))
3607 // ... then acknowledge this record to the client.
3608 // We do this optimistically, just as we're about to send the third probe.
3609 // This helps clients that both advertise and browse, and want to filter themselves
3610 // from the browse results list, because it helps ensure that the registration
3611 // confirmation will be delivered 1/4 second *before* the browse "add" event.
3612 // A potential downside is that we could deliver a registration confirmation and then find out
3613 // moments later that there's a name conflict, but applications have to be prepared to handle
3614 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
3615 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
);
3618 // else, if it has now finished probing, move it to state Verified,
3619 // and update m->NextScheduledResponse so it will be announced
3622 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
); // Defensive, just in case it got missed somehow
3623 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
3624 rr
->ThisAPInterval
= DefaultAnnounceIntervalForTypeUnique
;
3625 rr
->LastAPTime
= m
->timenow
- DefaultAnnounceIntervalForTypeUnique
;
3626 SetNextAnnounceProbeTime(m
, rr
);
3630 m
->CurrentRecord
= m
->DuplicateRecords
;
3631 while (m
->CurrentRecord
)
3633 AuthRecord
*rr
= m
->CurrentRecord
;
3634 m
->CurrentRecord
= rr
->next
;
3635 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& rr
->ProbeCount
== 0 && !rr
->Acknowledged
)
3636 AcknowledgeRecord(m
, rr
);
3640 // 3. Now we know which queries and probes we're sending,
3641 // go through our interface list sending the appropriate queries on each interface
3644 const int OwnerRecordSpace
= (m
->AnnounceOwner
&& intf
->MAC
.l
[0]) ? DNSOpt_Header_Space
+ DNSOpt_Owner_Space(&m
->PrimaryMAC
, &intf
->MAC
) : 0;
3646 mDNSu8
*queryptr
= m
->omsg
.data
;
3647 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, QueryFlags
);
3648 if (KnownAnswerList
) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
3649 if (!KnownAnswerList
)
3651 // Start a new known-answer list
3652 CacheRecord
**kalistptr
= &KnownAnswerList
;
3653 mDNSu32 answerforecast
= OwnerRecordSpace
; // We start by assuming we'll need at least enough space to put the Owner Option
3655 // Put query questions in this packet
3656 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3658 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
== intf
->InterfaceID
))
3660 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3661 SuppressOnThisInterface(q
->DupSuppress
, intf
) ? "Suppressing" : "Putting ",
3662 q
->qname
.c
, DNSTypeName(q
->qtype
), queryptr
- m
->omsg
.data
, queryptr
+ answerforecast
- m
->omsg
.data
);
3664 // If we're suppressing this question, or we successfully put it, update its SendQNow state
3665 if (SuppressOnThisInterface(q
->DupSuppress
, intf
) ||
3666 BuildQuestion(m
, &m
->omsg
, &queryptr
, q
, &kalistptr
, &answerforecast
))
3667 q
->SendQNow
= (q
->InterfaceID
|| !q
->SendOnAll
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3671 // Put probe questions in this packet
3672 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3673 if (rr
->SendRNow
== intf
->InterfaceID
)
3675 mDNSBool ucast
= (rr
->ProbeCount
>= DefaultProbeCountForTypeUnique
-1) && m
->CanReceiveUnicastOn5353
;
3676 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
3677 const mDNSu8
*const limit
= m
->omsg
.data
+ (m
->omsg
.h
.numQuestions
? NormalMaxDNSMessageData
: AbsoluteMaxDNSMessageData
);
3678 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3679 mDNSu32 forecast
= answerforecast
+ 12 + rr
->resrec
.rdestimate
;
3680 mDNSu8
*newptr
= putQuestion(&m
->omsg
, queryptr
, limit
- forecast
, rr
->resrec
.name
, kDNSQType_ANY
, (mDNSu16
)(rr
->resrec
.rrclass
| ucbit
));
3684 answerforecast
= forecast
;
3685 rr
->SendRNow
= (rr
->resrec
.InterfaceID
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
3686 rr
->IncludeInProbe
= mDNStrue
;
3687 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
3688 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->ProbeCount
);
3693 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3694 while (KnownAnswerList
)
3696 CacheRecord
*ka
= KnownAnswerList
;
3697 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- ka
->TimeRcvd
)) / mDNSPlatformOneSecond
;
3698 mDNSu8
*newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAnswers
,
3699 &ka
->resrec
, ka
->resrec
.rroriginalttl
- SecsSinceRcvd
, m
->omsg
.data
+ NormalMaxDNSMessageData
- OwnerRecordSpace
);
3702 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
3703 ka
->resrec
.name
->c
, DNSTypeName(ka
->resrec
.rrtype
), queryptr
- m
->omsg
.data
, newptr
- m
->omsg
.data
);
3705 KnownAnswerList
= ka
->NextInKAList
;
3706 ka
->NextInKAList
= mDNSNULL
;
3710 // If we ran out of space and we have more than one question in the packet, that's an error --
3711 // we shouldn't have put more than one question if there was a risk of us running out of space.
3712 if (m
->omsg
.h
.numQuestions
> 1)
3713 LogMsg("SendQueries: Put %d answers; No more space for known answers", m
->omsg
.h
.numAnswers
);
3714 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_TC
;
3719 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3720 if (rr
->IncludeInProbe
)
3722 mDNSu8
*newptr
= PutResourceRecord(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAuthorities
, &rr
->resrec
);
3723 rr
->IncludeInProbe
= mDNSfalse
;
3724 if (newptr
) queryptr
= newptr
;
3725 else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m
,rr
));
3728 if (queryptr
> m
->omsg
.data
)
3730 if (OwnerRecordSpace
)
3733 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
3734 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
3735 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
3736 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
3737 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[0]);
3738 LogSPS("SendQueries putting %s", ARDisplayString(m
, &opt
));
3739 queryptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAdditionals
,
3740 &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
3742 LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3743 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAdditionals
, ARDisplayString(m
, &opt
));
3744 if (queryptr
> m
->omsg
.data
+ NormalMaxDNSMessageData
)
3745 if (m
->omsg
.h
.numQuestions
!= 1 || m
->omsg
.h
.numAnswers
!= 0 || m
->omsg
.h
.numAuthorities
!= 1 || m
->omsg
.h
.numAdditionals
!= 1)
3746 LogMsg("SendQueries: Why did we generate oversized packet with OPT record %p %p %p (%d/%d/%d/%d) %s",
3747 m
->omsg
.data
, m
->omsg
.data
+ NormalMaxDNSMessageData
, queryptr
,
3748 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAdditionals
, ARDisplayString(m
, &opt
));
3751 if ((m
->omsg
.h
.flags
.b
[0] & kDNSFlag0_TC
) && m
->omsg
.h
.numQuestions
> 1)
3752 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m
->omsg
.h
.numQuestions
);
3753 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
3754 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
3755 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
3756 m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAuthorities
== 1 ? "" : "s", intf
->InterfaceID
);
3757 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3758 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
3759 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
3760 if (++pktcount
>= 1000)
3761 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount
); break; }
3762 // There might be more records left in the known answer list, or more questions to send
3763 // on this interface, so go around one more time and try again.
3765 else // Nothing more to send on this interface; go to next
3767 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
3768 #if MDNS_DEBUGMSGS && 0
3769 const char *const msg
= next
? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
3770 debugf(msg
, intf
, next
);
3776 // 4. Final housekeeping
3778 // 4a. Debugging check: Make sure we announced all our records
3779 for (ar
= m
->ResourceRecords
; ar
; ar
=ar
->next
)
3782 if (ar
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
3783 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m
, ar
));
3784 ar
->SendRNow
= mDNSNULL
;
3787 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3788 // that their interface which went away might come back again, the logic will want to send queries
3789 // for those records, but we can't because their interface isn't here any more, so to keep the
3790 // state machine ticking over we just pretend we did so.
3791 // If the interface does not come back in time, the cache record will expire naturally
3792 FORALL_CACHERECORDS(slot
, cg
, cr
)
3793 if (cr
->CRActiveQuestion
&& cr
->UnansweredQueries
< MaxUnansweredQueries
&& m
->timenow
- cr
->NextRequiredQuery
>= 0)
3795 cr
->UnansweredQueries
++;
3796 cr
->CRActiveQuestion
->SendQNow
= mDNSNULL
;
3797 SetNextCacheCheckTime(m
, cr
);
3800 // 4c. Debugging check: Make sure we sent all our planned questions
3801 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3802 // we legitimately couldn't send because the interface is no longer available
3803 for (q
= m
->Questions
; q
; q
=q
->next
)
3806 LogMsg("SendQueries: No active interface to send: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3807 q
->SendQNow
= mDNSNULL
;
3811 mDNSlocal
void SendWakeup(mDNS
*const m
, mDNSInterfaceID InterfaceID
, mDNSEthAddr
*EthAddr
, mDNSOpaque48
*password
)
3814 mDNSu8
*ptr
= m
->omsg
.data
;
3816 if (!InterfaceID
) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
3818 // 0x00 Destination address
3819 for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3821 // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
3822 for (i
=0; i
<6; i
++) *ptr
++ = 0x0;
3824 // 0x0C Ethertype (0x0842)
3828 // 0x0E Wakeup sync sequence
3829 for (i
=0; i
<6; i
++) *ptr
++ = 0xFF;
3832 for (j
=0; j
<16; j
++) for (i
=0; i
<6; i
++) *ptr
++ = EthAddr
->b
[i
];
3835 for (i
=0; i
<6; i
++) *ptr
++ = password
->b
[i
];
3837 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3839 // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
3840 // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
3841 // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
3842 // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
3843 // So, we send one of each, unicast first, then broadcast second.
3844 for (i
=0; i
<6; i
++) m
->omsg
.data
[i
] = 0xFF;
3845 mDNSPlatformSendRawPacket(m
->omsg
.data
, ptr
, InterfaceID
);
3848 // ***************************************************************************
3849 #if COMPILER_LIKES_PRAGMA_MARK
3851 #pragma mark - RR List Management & Task Management
3854 // Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3855 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
3856 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
3857 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
3858 mDNSexport
void AnswerCurrentQuestionWithResourceRecord(mDNS
*const m
, CacheRecord
*const rr
, const QC_result AddRecord
)
3860 DNSQuestion
*const q
= m
->CurrentQuestion
;
3861 mDNSBool followcname
= rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& AddRecord
&&
3862 rr
->resrec
.rrtype
== kDNSType_CNAME
&& q
->qtype
!= kDNSType_CNAME
;
3863 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q
->CurrentAnswers
, AddRecord
? "Add" : "Rmv", rr
->resrec
.rroriginalttl
, CRDisplayString(m
, rr
));
3865 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
3866 // may be called twice, once when the record is received, and again when it's time to notify local clients.
3867 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3869 rr
->LastUsed
= m
->timenow
;
3870 if (AddRecord
== QC_add
&& !q
->DuplicateOf
&& rr
->CRActiveQuestion
!= q
)
3872 if (!rr
->CRActiveQuestion
) m
->rrcache_active
++; // If not previously active, increment rrcache_active count
3873 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
3874 rr
->CRActiveQuestion
= q
; // We know q is non-null
3875 SetNextCacheCheckTime(m
, rr
);
3879 // (a) a no-cache add, where we've already done at least one 'QM' query, or
3880 // (b) a normal add, where we have at least one unique-type answer,
3881 // then there's no need to keep polling the network.
3882 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3883 // We do this for mDNS questions and uDNS one-shot questions, but not for
3884 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
3885 if ((AddRecord
== QC_addnocache
&& !q
->RequestUnicast
) ||
3886 (AddRecord
== QC_add
&& (q
->ExpectUnique
|| (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))))
3887 if (ActiveQuestion(q
) && (mDNSOpaque16IsZero(q
->TargetQID
) || !q
->LongLived
))
3889 q
->LastQTime
= m
->timenow
;
3890 q
->LastQTxTime
= m
->timenow
;
3891 q
->RecentAnswerPkts
= 0;
3892 q
->ThisQInterval
= MaxQuestionInterval
;
3893 q
->RequestUnicast
= mDNSfalse
;
3894 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3897 if (rr
->DelayDelivery
) return; // We'll come back later when CacheRecordDeferredAdd() calls us
3899 // Only deliver negative answers if client has explicitly requested them
3900 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
|| (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
)))
3901 if (!AddRecord
|| !q
->ReturnIntermed
) return;
3903 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
3904 if (q
->QuestionCallback
&& !q
->NoAnswer
&& (!followcname
|| q
->ReturnIntermed
))
3906 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
3907 if (q
->qtype
!= kDNSType_NSEC
&& RRAssertsNonexistence(&rr
->resrec
, q
->qtype
))
3910 MakeNegativeCacheRecord(m
, &neg
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 1, rr
->resrec
.InterfaceID
);
3911 q
->QuestionCallback(m
, q
, &neg
.resrec
, AddRecord
);
3914 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
3915 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3917 // Note: Proceed with caution here because client callback function is allowed to do anything,
3918 // including starting/stopping queries, registering/deregistering records, etc.
3920 if (followcname
&& m
->CurrentQuestion
== q
&& q
->CNAMEReferrals
< 10)
3922 const mDNSu32 c
= q
->CNAMEReferrals
+ 1;
3923 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
3924 // and track CNAMEs coming and going, we should really create a subordinate query here,
3925 // which we would subsequently cancel and retract if the CNAME referral record were removed.
3926 // In reality this is such a corner case we'll ignore it until someone actually needs it.
3927 LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m
, rr
));
3929 // If this query is a duplicate of another query, UpdateQuestionDuplicates called from
3930 // mDNS_StopQuery_internal copies the value of CNAMEReferrals from this query to the other
3931 // query on the Questions list. By setting the new value before calling mDNS_StopQuery_internal,
3932 // we ensure that the duplicate question gets a hgigher value and eventually the check for 10 above
3933 // would be true. Otherwise, the two queries would end up as active questions
3934 // sending mDNSResponder in an infinite loop e.g., Two queries starting off unique but receives
3935 // a CNAME response that refers to itself (test IN CNAME test) which makes it a duplicate of
3936 // one another. This fix now will make sure that stop at the 10th iteration.
3938 // Though CNAME records that refer to itself are not added anymore in mDNSCoreReceiveResponse, this fix is
3939 // still needed to catch the cases where the CNAME referral spans across multiple records with a potential
3940 // cycle in it which in turn can make multiple queries duplicate of each other
3942 q
->CNAMEReferrals
= c
;
3943 mDNS_StopQuery_internal(m
, q
); // Stop old query
3944 AssignDomainName(&q
->qname
, &rr
->resrec
.rdata
->u
.name
); // Update qname
3945 q
->qnamehash
= DomainNameHashValue(&q
->qname
); // and namehash
3946 mDNS_StartQuery_internal(m
, q
); // start new query
3947 q
->CNAMEReferrals
= c
; // and keep count of how many times we've done this
3951 mDNSlocal
void CacheRecordDeferredAdd(mDNS
*const m
, CacheRecord
*rr
)
3953 rr
->DelayDelivery
= 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3954 if (m
->CurrentQuestion
)
3955 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3956 m
->CurrentQuestion
= m
->Questions
;
3957 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3959 DNSQuestion
*q
= m
->CurrentQuestion
;
3960 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3961 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3962 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3963 m
->CurrentQuestion
= q
->next
;
3965 m
->CurrentQuestion
= mDNSNULL
;
3968 mDNSlocal mDNSs32
CheckForSoonToExpireRecords(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const mDNSu32 slot
)
3970 const mDNSs32 threshhold
= m
->timenow
+ mDNSPlatformOneSecond
; // See if there are any records expiring within one second
3971 const mDNSs32 start
= m
->timenow
- 0x10000000;
3972 mDNSs32 delay
= start
;
3973 CacheGroup
*cg
= CacheGroupForName(m
, slot
, namehash
, name
);
3974 const CacheRecord
*rr
;
3975 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
3976 if (threshhold
- RRExpireTime(rr
) >= 0) // If we have records about to expire within a second
3977 if (delay
- RRExpireTime(rr
) < 0) // then delay until after they've been deleted
3978 delay
= RRExpireTime(rr
);
3979 if (delay
- start
> 0) return(NonZeroTime(delay
));
3983 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3984 // If new questions are created as a result of invoking client callbacks, they will be added to
3985 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3986 // rr is a new CacheRecord just received into our cache
3987 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3988 // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3989 // which may change the record list and/or question list.
3990 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3991 mDNSlocal
void CacheRecordAdd(mDNS
*const m
, CacheRecord
*rr
)
3995 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3996 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3997 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3999 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4001 // If this question is one that's actively sending queries, and it's received ten answers within one
4002 // second of sending the last query packet, then that indicates some radical network topology change,
4003 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
4004 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
4005 // because we will anyway send another query within a few seconds. The first reset query is sent out
4006 // randomized over the next four seconds to reduce possible synchronization between machines.
4007 if (q
->LastAnswerPktNum
!= m
->PktNum
)
4009 q
->LastAnswerPktNum
= m
->PktNum
;
4010 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
) && ++q
->RecentAnswerPkts
>= 10 &&
4011 q
->ThisQInterval
> InitialQuestionInterval
* QuestionIntervalStep3
&& m
->timenow
- q
->LastQTxTime
< mDNSPlatformOneSecond
)
4013 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
4014 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->RecentAnswerPkts
, q
->ThisQInterval
);
4015 q
->LastQTime
= m
->timenow
- InitialQuestionInterval
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*4);
4016 q
->ThisQInterval
= InitialQuestionInterval
;
4017 SetNextQueryTime(m
,q
);
4020 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
4021 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->resrec
.rroriginalttl
);
4022 q
->CurrentAnswers
++;
4023 q
->unansweredQueries
= 0;
4024 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
4025 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
4026 if (q
->CurrentAnswers
> 4000)
4028 static int msgcount
= 0;
4029 if (msgcount
++ < 10)
4030 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
4031 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->CurrentAnswers
);
4032 rr
->resrec
.rroriginalttl
= 0;
4033 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4038 if (!rr
->DelayDelivery
)
4040 if (m
->CurrentQuestion
)
4041 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4042 m
->CurrentQuestion
= m
->Questions
;
4043 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
4045 q
= m
->CurrentQuestion
;
4046 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4047 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
4048 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4049 m
->CurrentQuestion
= q
->next
;
4051 m
->CurrentQuestion
= mDNSNULL
;
4054 SetNextCacheCheckTime(m
, rr
);
4057 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4058 // If new questions are created as a result of invoking client callbacks, they will be added to
4059 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4060 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4061 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4062 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4063 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4064 // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4065 // which may change the record list and/or question list.
4066 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4067 mDNSlocal
void NoCacheAnswer(mDNS
*const m
, CacheRecord
*rr
)
4069 LogMsg("No cache space: Delivering non-cached result for %##s", m
->rec
.r
.resrec
.name
->c
);
4070 if (m
->CurrentQuestion
)
4071 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4072 m
->CurrentQuestion
= m
->Questions
;
4073 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
4074 // since we're not caching the record and we'll get no opportunity to do this later
4075 while (m
->CurrentQuestion
)
4077 DNSQuestion
*q
= m
->CurrentQuestion
;
4078 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4079 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_addnocache
); // QC_addnocache means "don't expect remove events for this"
4080 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4081 m
->CurrentQuestion
= q
->next
;
4083 m
->CurrentQuestion
= mDNSNULL
;
4086 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
4087 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
4088 // If new questions are created as a result of invoking client callbacks, they will be added to
4089 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4090 // rr is an existing cache CacheRecord that just expired and is being deleted
4091 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4092 // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4093 // which may change the record list and/or question list.
4094 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4095 mDNSlocal
void CacheRecordRmv(mDNS
*const m
, CacheRecord
*rr
)
4097 if (m
->CurrentQuestion
)
4098 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4099 m
->CurrentQuestion
= m
->Questions
;
4101 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
4102 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
4103 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
4105 DNSQuestion
*q
= m
->CurrentQuestion
;
4106 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4108 verbosedebugf("CacheRecordRmv %p %s", rr
, CRDisplayString(m
, rr
));
4109 q
->FlappingInterface1
= mDNSNULL
;
4110 q
->FlappingInterface2
= mDNSNULL
;
4111 if (q
->CurrentAnswers
== 0)
4112 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4113 q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
4116 q
->CurrentAnswers
--;
4117 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
--;
4118 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
--;
4120 if (rr
->resrec
.rdata
->MaxRDLength
) // Never generate "remove" events for negative results
4122 if (q
->CurrentAnswers
== 0)
4124 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
4125 q
->qname
.c
, DNSTypeName(q
->qtype
));
4126 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
4128 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_rmv
);
4131 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4132 m
->CurrentQuestion
= q
->next
;
4134 m
->CurrentQuestion
= mDNSNULL
;
4137 mDNSlocal
void ReleaseCacheEntity(mDNS
*const m
, CacheEntity
*e
)
4139 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4141 for (i
=0; i
<sizeof(*e
); i
++) ((char*)e
)[i
] = 0xFF;
4143 e
->next
= m
->rrcache_free
;
4144 m
->rrcache_free
= e
;
4145 m
->rrcache_totalused
--;
4148 mDNSlocal
void ReleaseCacheGroup(mDNS
*const m
, CacheGroup
**cp
)
4150 CacheEntity
*e
= (CacheEntity
*)(*cp
);
4151 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4152 if ((*cp
)->rrcache_tail
!= &(*cp
)->members
)
4153 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4154 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
4155 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4156 if ((*cp
)->name
!= (domainname
*)((*cp
)->namestorage
)) mDNSPlatformMemFree((*cp
)->name
);
4157 (*cp
)->name
= mDNSNULL
;
4158 *cp
= (*cp
)->next
; // Cut record from list
4159 ReleaseCacheEntity(m
, e
);
4162 mDNSlocal
void ReleaseCacheRecord(mDNS
*const m
, CacheRecord
*r
)
4164 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
4165 if (r
->resrec
.rdata
&& r
->resrec
.rdata
!= (RData
*)&r
->smallrdatastorage
) mDNSPlatformMemFree(r
->resrec
.rdata
);
4166 r
->resrec
.rdata
= mDNSNULL
;
4167 ReleaseCacheEntity(m
, (CacheEntity
*)r
);
4170 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4171 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4172 // callbacks for old records are delivered before callbacks for newer records.
4173 mDNSlocal
void CheckCacheExpiration(mDNS
*const m
, CacheGroup
*const cg
)
4175 CacheRecord
**rp
= &cg
->members
;
4177 if (m
->lock_rrcache
) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4178 m
->lock_rrcache
= 1;
4182 CacheRecord
*const rr
= *rp
;
4183 mDNSs32 event
= RRExpireTime(rr
);
4184 if (m
->timenow
- event
>= 0) // If expired, delete it
4186 *rp
= rr
->next
; // Cut it from the list
4187 verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
4188 m
->timenow
- rr
->TimeRcvd
, rr
->resrec
.rroriginalttl
, rr
->CRActiveQuestion
, CRDisplayString(m
, rr
));
4189 if (rr
->CRActiveQuestion
) // If this record has one or more active questions, tell them it's going away
4191 CacheRecordRmv(m
, rr
);
4192 m
->rrcache_active
--;
4194 ReleaseCacheRecord(m
, rr
);
4196 else // else, not expired; see if we need to query
4198 if (rr
->DelayDelivery
&& rr
->DelayDelivery
- m
->timenow
> 0)
4199 event
= rr
->DelayDelivery
;
4202 if (rr
->DelayDelivery
) CacheRecordDeferredAdd(m
, rr
);
4203 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
4205 if (m
->timenow
- rr
->NextRequiredQuery
< 0) // If not yet time for next query
4206 event
= rr
->NextRequiredQuery
; // then just record when we want the next query
4207 else // else trigger our question to go out now
4209 // Set NextScheduledQuery to timenow so that SendQueries() will run.
4210 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
4211 m
->NextScheduledQuery
= m
->timenow
;
4212 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4213 // which will correctly update m->NextCacheCheck for us.
4214 event
= m
->timenow
+ 0x3FFFFFFF;
4218 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4219 (event
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
), CRDisplayString(m
, rr
));
4220 if (m
->NextCacheCheck
- (event
+ CacheCheckGracePeriod(rr
)) > 0)
4221 m
->NextCacheCheck
= (event
+ CacheCheckGracePeriod(rr
));
4225 if (cg
->rrcache_tail
!= rp
) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg
->rrcache_tail
, rp
);
4226 cg
->rrcache_tail
= rp
;
4227 m
->lock_rrcache
= 0;
4230 mDNSlocal
void AnswerNewQuestion(mDNS
*const m
)
4232 mDNSBool ShouldQueryImmediately
= mDNStrue
;
4233 DNSQuestion
*q
= m
->NewQuestions
; // Grab the question we're going to answer
4234 const mDNSu32 slot
= HashSlot(&q
->qname
);
4235 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4237 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4239 if (cg
) CheckCacheExpiration(m
, cg
);
4240 m
->NewQuestions
= q
->next
; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4242 if (m
->lock_rrcache
) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4243 // This should be safe, because calling the client's question callback may cause the
4244 // question list to be modified, but should not ever cause the rrcache list to be modified.
4245 // If the client's question callback deletes the question, then m->CurrentQuestion will
4246 // be advanced, and we'll exit out of the loop
4247 m
->lock_rrcache
= 1;
4248 if (m
->CurrentQuestion
)
4249 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4250 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4252 if (q
->NoAnswer
== NoAnswer_Fail
)
4254 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4255 MakeNegativeCacheRecord(m
, &m
->rec
.r
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60, mDNSInterface_Any
);
4256 q
->NoAnswer
= NoAnswer_Normal
; // Temporarily turn off answer suppression
4257 AnswerCurrentQuestionWithResourceRecord(m
, &m
->rec
.r
, QC_addnocache
);
4258 q
->NoAnswer
= NoAnswer_Fail
; // Restore NoAnswer state
4259 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4262 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4263 if (m
->CurrentQuestion
== q
&& q
->InterfaceID
== mDNSInterface_Any
)
4265 if (m
->CurrentRecord
)
4266 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4267 m
->CurrentRecord
= m
->ResourceRecords
;
4268 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4270 AuthRecord
*rr
= m
->CurrentRecord
;
4271 m
->CurrentRecord
= rr
->next
;
4272 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
4273 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4275 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4276 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4279 m
->CurrentRecord
= mDNSNULL
;
4282 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
4284 if (m
->CurrentQuestion
== q
)
4287 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4288 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
))
4290 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
4291 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- rr
->TimeRcvd
)) / mDNSPlatformOneSecond
;
4292 if (rr
->resrec
.rroriginalttl
<= SecsSinceRcvd
)
4294 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
4295 rr
->resrec
.rroriginalttl
, SecsSinceRcvd
, CRDisplayString(m
, rr
), m
->timenow
, rr
->TimeRcvd
);
4296 continue; // Go to next one in loop
4299 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
4300 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4301 if ((rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) || (q
->ExpectUnique
))
4302 ShouldQueryImmediately
= mDNSfalse
;
4303 q
->CurrentAnswers
++;
4304 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
4305 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
4306 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
4307 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4309 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
) && RRTypeIsAddressType(q
->qtype
))
4310 ShouldQueryImmediately
= mDNSfalse
;
4313 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving cache answers");
4315 if (m
->CurrentQuestion
== q
&& ShouldQueryImmediately
&& ActiveQuestion(q
))
4317 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4318 q
->ThisQInterval
= InitialQuestionInterval
;
4319 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4320 if (mDNSOpaque16IsZero(q
->TargetQID
)) // For mDNS, spread packets to avoid a burst of simultaneous queries
4322 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
4323 if (!m
->RandomQueryDelay
)
4324 m
->RandomQueryDelay
= (mDNSPlatformOneSecond
+ mDNSRandom(mDNSPlatformOneSecond
*5) - 1) / 50 + 1;
4325 q
->LastQTime
+= m
->RandomQueryDelay
;
4328 if (m
->NextScheduledQuery
- (q
->LastQTime
+ q
->ThisQInterval
) > 0)
4329 m
->NextScheduledQuery
= (q
->LastQTime
+ q
->ThisQInterval
);
4332 m
->CurrentQuestion
= mDNSNULL
;
4333 m
->lock_rrcache
= 0;
4336 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4337 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
4338 mDNSlocal
void AnswerNewLocalOnlyQuestion(mDNS
*const m
)
4340 DNSQuestion
*q
= m
->NewLocalOnlyQuestions
; // Grab the question we're going to answer
4341 m
->NewLocalOnlyQuestions
= q
->next
; // Advance NewLocalOnlyQuestions to the next (if any)
4343 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4345 if (m
->CurrentQuestion
)
4346 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4347 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
4349 if (m
->CurrentRecord
)
4350 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4351 m
->CurrentRecord
= m
->ResourceRecords
;
4353 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
4355 AuthRecord
*rr
= m
->CurrentRecord
;
4356 m
->CurrentRecord
= rr
->next
;
4357 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4359 AnswerLocalQuestionWithLocalAuthRecord(m
, q
, rr
, mDNStrue
);
4360 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
4364 m
->CurrentQuestion
= mDNSNULL
;
4365 m
->CurrentRecord
= mDNSNULL
;
4368 mDNSlocal CacheEntity
*GetCacheEntity(mDNS
*const m
, const CacheGroup
*const PreserveCG
)
4370 CacheEntity
*e
= mDNSNULL
;
4372 if (m
->lock_rrcache
) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL
); }
4373 m
->lock_rrcache
= 1;
4375 // If we have no free records, ask the client layer to give us some more memory
4376 if (!m
->rrcache_free
&& m
->MainCallback
)
4378 if (m
->rrcache_totalused
!= m
->rrcache_size
)
4379 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4380 m
->rrcache_totalused
, m
->rrcache_size
);
4382 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4383 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4384 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4385 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
4386 // and recycle them, instead of allocating more memory.
4387 if (m
->rrcache_size
> 5000 && m
->rrcache_size
/ 32 > m
->rrcache_active
)
4388 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4389 m
->rrcache_size
, m
->rrcache_active
);
4392 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4393 m
->MainCallback(m
, mStatus_GrowCache
);
4394 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4398 // If we still have no free records, recycle all the records we can.
4399 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4400 if (!m
->rrcache_free
)
4402 mDNSu32 oldtotalused
= m
->rrcache_totalused
;
4404 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4406 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4409 CacheRecord
**rp
= &(*cp
)->members
;
4412 // Records that answer still-active questions are not candidates for recycling
4413 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4414 if ((*rp
)->CRActiveQuestion
|| (*rp
)->NextInCFList
)
4418 CacheRecord
*rr
= *rp
;
4419 *rp
= (*rp
)->next
; // Cut record from list
4420 ReleaseCacheRecord(m
, rr
);
4423 if ((*cp
)->rrcache_tail
!= rp
)
4424 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot
, (*cp
)->rrcache_tail
, rp
);
4425 (*cp
)->rrcache_tail
= rp
;
4426 if ((*cp
)->members
|| (*cp
)==PreserveCG
) cp
=&(*cp
)->next
;
4427 else ReleaseCacheGroup(m
, cp
);
4430 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4431 oldtotalused
- m
->rrcache_totalused
, oldtotalused
, m
->rrcache_totalused
);
4434 if (m
->rrcache_free
) // If there are records in the free list, take one
4436 e
= m
->rrcache_free
;
4437 m
->rrcache_free
= e
->next
;
4438 if (++m
->rrcache_totalused
>= m
->rrcache_report
)
4440 LogInfo("RR Cache now using %ld objects", m
->rrcache_totalused
);
4441 if (m
->rrcache_report
< 100) m
->rrcache_report
+= 10;
4442 else if (m
->rrcache_report
< 1000) m
->rrcache_report
+= 100;
4443 else m
->rrcache_report
+= 1000;
4445 mDNSPlatformMemZero(e
, sizeof(*e
));
4448 m
->lock_rrcache
= 0;
4453 mDNSlocal CacheRecord
*GetCacheRecord(mDNS
*const m
, CacheGroup
*cg
, mDNSu16 RDLength
)
4455 CacheRecord
*r
= (CacheRecord
*)GetCacheEntity(m
, cg
);
4458 r
->resrec
.rdata
= (RData
*)&r
->smallrdatastorage
; // By default, assume we're usually going to be using local storage
4459 if (RDLength
> InlineCacheRDSize
) // If RDLength is too big, allocate extra storage
4461 r
->resrec
.rdata
= (RData
*)mDNSPlatformMemAllocate(sizeofRDataHeader
+ RDLength
);
4462 if (r
->resrec
.rdata
) r
->resrec
.rdata
->MaxRDLength
= r
->resrec
.rdlength
= RDLength
;
4463 else { ReleaseCacheEntity(m
, (CacheEntity
*)r
); r
= mDNSNULL
; }
4469 mDNSlocal CacheGroup
*GetCacheGroup(mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
4471 mDNSu16 namelen
= DomainNameLength(rr
->name
);
4472 CacheGroup
*cg
= (CacheGroup
*)GetCacheEntity(m
, mDNSNULL
);
4473 if (!cg
) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr
->name
->c
); return(mDNSNULL
); }
4474 cg
->next
= m
->rrcache_hash
[slot
];
4475 cg
->namehash
= rr
->namehash
;
4476 cg
->members
= mDNSNULL
;
4477 cg
->rrcache_tail
= &cg
->members
;
4478 cg
->name
= (domainname
*)cg
->namestorage
;
4479 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4480 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4481 if (namelen
> InlineCacheGroupNameSize
) cg
->name
= mDNSPlatformMemAllocate(namelen
);
4484 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr
->name
->c
);
4485 ReleaseCacheEntity(m
, (CacheEntity
*)cg
);
4488 AssignDomainName(cg
->name
, rr
->name
);
4490 if (CacheGroupForRecord(m
, slot
, rr
)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr
->name
->c
);
4491 m
->rrcache_hash
[slot
] = cg
;
4492 if (CacheGroupForRecord(m
, slot
, rr
) != cg
) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr
->name
->c
);
4497 mDNSexport
void mDNS_PurgeCacheResourceRecord(mDNS
*const m
, CacheRecord
*rr
)
4499 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
4500 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
4501 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4502 // a positive answer using an expired record (e.g. from an interface that has gone away).
4503 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4504 // summary deletion without giving the proper callback to any questions that are monitoring it.
4505 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4506 rr
->TimeRcvd
= m
->timenow
- mDNSPlatformOneSecond
* 60;
4507 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4508 rr
->resrec
.rroriginalttl
= 0;
4509 SetNextCacheCheckTime(m
, rr
);
4512 mDNSexport mDNSs32
mDNS_TimeNow(const mDNS
*const m
)
4515 mDNSPlatformLock(m
);
4518 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4519 if (!m
->timenow
) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
4522 if (m
->timenow
) time
= m
->timenow
;
4523 else time
= mDNS_TimeNow_NoLock(m
);
4524 mDNSPlatformUnlock(m
);
4528 // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4529 // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4530 // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4531 #define SetSPSProxyListChanged(X) do { \
4532 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4533 m->SPSProxyListChanged = (X); } while(0)
4535 // Called from mDNS_Execute() to expire stale proxy records
4536 mDNSlocal
void CheckProxyRecords(mDNS
*const m
, AuthRecord
*list
)
4538 m
->CurrentRecord
= list
;
4539 while (m
->CurrentRecord
)
4541 AuthRecord
*rr
= m
->CurrentRecord
;
4542 if (rr
->WakeUp
.HMAC
.l
[0])
4544 if (m
->timenow
- rr
->TimeExpire
< 0) // If proxy record not expired yet, update m->NextScheduledSPS
4546 if (m
->NextScheduledSPS
- rr
->TimeExpire
> 0)
4547 m
->NextScheduledSPS
= rr
->TimeExpire
;
4549 else // else proxy record expired, so remove it
4551 LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4552 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, ARDisplayString(m
, rr
));
4553 SetSPSProxyListChanged(rr
->resrec
.InterfaceID
);
4554 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
4555 // Don't touch rr after this -- memory may have been free'd
4558 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
4559 // because the list may have been changed in that call.
4560 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
4561 m
->CurrentRecord
= rr
->next
;
4565 mDNSexport mDNSs32
mDNS_Execute(mDNS
*const m
)
4567 mDNS_Lock(m
); // Must grab lock before trying to read m->timenow
4569 if (m
->timenow
- m
->NextScheduledEvent
>= 0)
4573 // If there are DNS servers that will come out of the Penalty box, we should do that now
4574 // so that any questions that we send below can start using that
4575 ResetDNSServerPenalties(m
);
4577 verbosedebugf("mDNS_Execute");
4578 if (m
->CurrentQuestion
)
4579 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4581 // 1. If we're past the probe suppression time, we can clear it
4582 if (m
->SuppressProbes
&& m
->timenow
- m
->SuppressProbes
>= 0) m
->SuppressProbes
= 0;
4584 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4585 if (m
->NumFailedProbes
&& m
->timenow
- m
->ProbeFailTime
>= mDNSPlatformOneSecond
* 10) m
->NumFailedProbes
= 0;
4587 // 3. Purge our cache of stale old records
4588 if (m
->rrcache_size
&& m
->timenow
- m
->NextCacheCheck
>= 0)
4591 m
->NextCacheCheck
= m
->timenow
+ 0x3FFFFFFF;
4592 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
4594 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
4597 CheckCacheExpiration(m
, *cp
);
4598 if ((*cp
)->members
) cp
=&(*cp
)->next
;
4599 else ReleaseCacheGroup(m
, cp
);
4604 if (m
->timenow
- m
->NextScheduledSPS
>= 0)
4606 m
->NextScheduledSPS
= m
->timenow
+ 0x3FFFFFFF;
4607 CheckProxyRecords(m
, m
->DuplicateRecords
); // Clear m->DuplicateRecords first, then m->ResourceRecords
4608 CheckProxyRecords(m
, m
->ResourceRecords
);
4611 SetSPSProxyListChanged(mDNSNULL
); // Perform any deferred BPF reconfiguration now
4613 // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
4614 if (m
->AnnounceOwner
&& m
->timenow
- m
->AnnounceOwner
>= 0) m
->AnnounceOwner
= 0;
4616 if (m
->DelaySleep
&& m
->timenow
- m
->DelaySleep
>= 0)
4619 if (m
->SleepState
== SleepState_Transferring
)
4621 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4622 BeginSleepProcessing(m
);
4626 // 4. See if we can answer any of our new local questions from the cache
4627 for (i
=0; m
->NewQuestions
&& i
<1000; i
++)
4629 if (m
->NewQuestions
->DelayAnswering
&& m
->timenow
- m
->NewQuestions
->DelayAnswering
< 0) break;
4630 AnswerNewQuestion(m
);
4632 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4634 for (i
=0; m
->NewLocalOnlyQuestions
&& i
<1000; i
++) AnswerNewLocalOnlyQuestion(m
);
4635 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4637 for (i
=0; i
<1000 && m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
); i
++)
4639 AuthRecord
*rr
= m
->NewLocalRecords
;
4640 m
->NewLocalRecords
= m
->NewLocalRecords
->next
;
4641 AnswerAllLocalQuestionsWithLocalAuthRecord(m
, rr
, mDNStrue
);
4643 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4645 // 5. See what packets we need to send
4646 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| (m
->SleepState
== SleepState_Sleeping
))
4647 DiscardDeregistrations(m
);
4648 if (m
->mDNSPlatformStatus
== mStatus_NoError
&& (m
->SuppressSending
== 0 || m
->timenow
- m
->SuppressSending
>= 0))
4650 // If the platform code is ready, and we're not suppressing packet generation right now
4651 // then send our responses, probes, and questions.
4652 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4653 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4654 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4655 // Finally, we send responses, including the previously mentioned records that just completed probing.
4656 m
->SuppressSending
= 0;
4658 // 6. Send Query packets. This may cause some probing records to advance to announcing state
4659 if (m
->timenow
- m
->NextScheduledQuery
>= 0 || m
->timenow
- m
->NextScheduledProbe
>= 0) SendQueries(m
);
4660 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
4663 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4664 m
->timenow
, m
->NextScheduledQuery
, m
->timenow
- m
->NextScheduledQuery
);
4665 m
->NextScheduledQuery
= m
->timenow
+ mDNSPlatformOneSecond
;
4666 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
4667 if (ActiveQuestion(q
) && q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
<= 0)
4668 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
4670 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
4672 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4673 m
->timenow
, m
->NextScheduledProbe
, m
->timenow
- m
->NextScheduledProbe
);
4674 m
->NextScheduledProbe
= m
->timenow
+ mDNSPlatformOneSecond
;
4677 // 7. Send Response packets, including probing records just advanced to announcing state
4678 if (m
->timenow
- m
->NextScheduledResponse
>= 0) SendResponses(m
);
4679 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
4681 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4682 m
->NextScheduledResponse
= m
->timenow
+ mDNSPlatformOneSecond
;
4686 // Clear RandomDelay values, ready to pick a new different value next time
4687 m
->RandomQueryDelay
= 0;
4688 m
->RandomReconfirmDelay
= 0;
4691 // Note about multi-threaded systems:
4692 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4693 // performing mDNS API operations that change our next scheduled event time.
4695 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4696 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4697 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4698 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4699 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4700 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4701 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4702 // without blocking. This avoids the race condition between the signal from the other thread arriving
4703 // just *before* or just *after* the main thread enters the blocking primitive.
4705 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4706 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4707 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4708 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4709 // by the time it gets to the timer callback function).
4711 #ifndef UNICAST_DISABLED
4714 mDNS_Unlock(m
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4715 return(m
->NextScheduledEvent
);
4718 mDNSlocal
void SuspendLLQs(mDNS
*m
)
4721 for (q
= m
->Questions
; q
; q
= q
->next
)
4722 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->state
== LLQ_Established
)
4723 { q
->ReqLease
= 0; sendLLQRefresh(m
, q
); }
4726 // ActivateUnicastQuery() is called from three places:
4727 // 1. When a new question is created
4728 // 2. On wake from sleep
4729 // 3. When the DNS configuration changes
4730 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4731 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4732 mDNSlocal
void ActivateUnicastQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool ScheduleImmediately
)
4734 // For now this AutoTunnel stuff is specific to Mac OS X.
4735 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4736 #if APPLE_OSX_mDNSResponder
4737 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4738 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4739 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4740 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4741 // returns results for both at the same time.
4742 if (RRTypeIsAddressType(question
->qtype
) && question
->AuthInfo
&& question
->AuthInfo
->AutoTunnel
&& question
->QuestionCallback
!= AutoTunnelCallback
)
4744 question
->NoAnswer
= NoAnswer_Suspended
;
4745 AddNewClientTunnel(m
, question
);
4748 #endif // APPLE_OSX_mDNSResponder
4750 if (!question
->DuplicateOf
)
4752 debugf("ActivateUnicastQuery: %##s %s%s%s",
4753 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->AuthInfo
? " (Private)" : "", ScheduleImmediately
? " ScheduleImmediately" : "");
4754 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
4755 if (question
->LongLived
)
4757 question
->state
= LLQ_InitialRequest
;
4758 question
->id
= zeroOpaque64
;
4759 question
->servPort
= zeroIPPort
;
4760 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
4762 if (ScheduleImmediately
)
4764 question
->ThisQInterval
= InitialQuestionInterval
;
4765 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
4766 SetNextQueryTime(m
, question
);
4771 mDNSexport
void mDNSCoreRestartQueries(mDNS
*const m
)
4775 #ifndef UNICAST_DISABLED
4776 // Retrigger all our uDNS questions
4777 if (m
->CurrentQuestion
)
4778 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
4779 m
->CurrentQuestion
= m
->Questions
;
4780 while (m
->CurrentQuestion
)
4782 q
= m
->CurrentQuestion
;
4783 m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
4784 if (!mDNSOpaque16IsZero(q
->TargetQID
)) ActivateUnicastQuery(m
, q
, mDNStrue
);
4788 // Retrigger all our mDNS questions
4789 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
4790 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
))
4792 q
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
4793 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
4794 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
4795 q
->RecentAnswerPkts
= 0;
4796 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
);
4797 m
->NextScheduledQuery
= m
->timenow
;
4801 // ***************************************************************************
4802 #if COMPILER_LIKES_PRAGMA_MARK
4804 #pragma mark - Power Management (Sleep/Wake)
4807 mDNSlocal
void SendSPSRegistration(mDNS
*const m
, NetworkInterfaceInfo
*intf
, const mDNSOpaque16 id
)
4809 const int optspace
= DNSOpt_Header_Space
+ DNSOpt_LeaseData_Space
+ DNSOpt_Owner_Space(&m
->PrimaryMAC
, &intf
->MAC
);
4810 const int sps
= intf
->NextSPSAttempt
/ 3;
4813 if (!intf
->SPSAddr
[sps
].type
)
4815 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
4816 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
4817 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
4818 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf
->ifname
, intf
->NextSPSAttempt
, sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4822 // Mark our mDNS records (not unicast records) for transfer to SPS
4823 if (mDNSOpaque16IsZero(id
))
4824 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4825 if (rr
->resrec
.RecordType
> kDNSRecordTypeDeregistering
)
4826 if (rr
->resrec
.InterfaceID
== intf
->InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
4827 rr
->SendRNow
= mDNSInterfaceMark
; // mark it now
4831 mDNSu8
*p
= m
->omsg
.data
;
4832 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4833 // For now we follow that same logic for SPS registrations too.
4834 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4835 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4836 InitializeDNSMessage(&m
->omsg
.h
, mDNSOpaque16IsZero(id
) ? mDNS_NewMessageID(m
) : id
, UpdateReqFlags
);
4838 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4839 if (rr
->SendRNow
|| (!mDNSOpaque16IsZero(id
) && !AuthRecord_uDNS(rr
) && mDNSSameOpaque16(rr
->updateid
, id
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0))
4842 const mDNSu8
*const limit
= m
->omsg
.data
+ (m
->omsg
.h
.mDNS_numUpdates
? NormalMaxDNSMessageData
: AbsoluteMaxDNSMessageData
) - optspace
;
4843 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
4844 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the 'unique' bit so PutResourceRecord will set it
4845 newptr
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.mDNS_numUpdates
, &rr
->resrec
, rr
->resrec
.rroriginalttl
, limit
);
4846 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear 'unique' bit back to normal state
4848 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf
->ifname
, p
- m
->omsg
.data
, limit
- m
->omsg
.data
, ARDisplayString(m
, rr
));
4851 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, rr
));
4852 rr
->SendRNow
= mDNSNULL
;
4853 rr
->ThisAPInterval
= mDNSPlatformOneSecond
;
4854 rr
->LastAPTime
= m
->timenow
;
4855 rr
->updateid
= m
->omsg
.h
.id
;
4856 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4857 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
4862 if (!m
->omsg
.h
.mDNS_numUpdates
) break;
4866 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
4867 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
4868 opt
.resrec
.rdlength
= sizeof(rdataOPT
) * 2; // Two options in this OPT record
4869 opt
.resrec
.rdestimate
= sizeof(rdataOPT
) * 2;
4870 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
4871 opt
.resrec
.rdata
->u
.opt
[0].optlen
= DNSOpt_LeaseData_Space
- 4;
4872 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= DEFAULT_UPDATE_LEASE
;
4873 SetupOwnerOpt(m
, intf
, &opt
.resrec
.rdata
->u
.opt
[1]);
4874 LogSPS("SendSPSRegistration put %s %s", intf
->ifname
, ARDisplayString(m
, &opt
));
4875 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
4877 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m
->omsg
.h
.mDNS_numUpdates
, ARDisplayString(m
, &opt
));
4881 // Once we've attempted to register, we need to include our OWNER option in our packets when we re-awaken
4882 m
->SentSleepProxyRegistration
= mDNStrue
;
4884 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf
->ifname
, intf
->NextSPSAttempt
, sps
,
4885 mDNSVal16(m
->omsg
.h
.id
), m
->omsg
.h
.mDNS_numUpdates
, p
- m
->omsg
.data
, &intf
->SPSAddr
[sps
], mDNSVal16(intf
->SPSPort
[sps
]));
4886 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
4887 err
= mDNSSendDNSMessage(m
, &m
->omsg
, p
, intf
->InterfaceID
, mDNSNULL
, &intf
->SPSAddr
[sps
], intf
->SPSPort
[sps
], mDNSNULL
, mDNSNULL
);
4888 if (err
) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err
);
4889 if (err
&& intf
->SPSAddr
[sps
].type
== mDNSAddrType_IPv6
&& intf
->NetWakeResolve
[sps
].ThisQInterval
== -1)
4891 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps
, intf
->NetWakeResolve
[sps
].qname
.c
);
4892 intf
->NetWakeResolve
[sps
].qtype
= kDNSType_A
;
4893 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[sps
]);
4900 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
* 10; // If successful, update NextSPSAttemptTime
4903 if (mDNSOpaque16IsZero(id
) && intf
->NextSPSAttempt
< 8) intf
->NextSPSAttempt
++;
4906 // RetrySPSRegistrations is called from SendResponses, with the lock held
4907 mDNSlocal
void RetrySPSRegistrations(mDNS
*const m
)
4910 NetworkInterfaceInfo
*intf
;
4912 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4913 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4914 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10)
4915 intf
->NextSPSAttemptTime
++;
4917 // Retry any record registrations that are due
4918 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4919 if (!AuthRecord_uDNS(rr
) && !mDNSOpaque16IsZero(rr
->updateid
) && m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
4920 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4921 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== intf
->InterfaceID
)
4923 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m
, rr
));
4924 SendSPSRegistration(m
, intf
, rr
->updateid
);
4927 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4928 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
4929 if (intf
->NextSPSAttempt
&& intf
->NextSPSAttemptTime
== m
->timenow
+ mDNSPlatformOneSecond
* 10 && intf
->NextSPSAttempt
< 8)
4930 intf
->NextSPSAttempt
++;
4933 mDNSlocal
void NetWakeResolve(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
4935 NetworkInterfaceInfo
*intf
= (NetworkInterfaceInfo
*)question
->QuestionContext
;
4936 int sps
= question
- intf
->NetWakeResolve
;
4938 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps
, AddRecord
, RRDisplayString(m
, answer
));
4940 if (!AddRecord
) return; // Don't care about REMOVE events
4941 if (answer
->rrtype
!= question
->qtype
) return; // Don't care about CNAMEs
4943 // if (answer->rrtype == kDNSType_AAAA) return; // To test failing to resolve sleep proxy's address
4945 mDNS_StopQuery(m
, question
);
4946 question
->ThisQInterval
= -1;
4948 if (answer
->rrtype
== kDNSType_SRV
)
4950 intf
->SPSPort
[sps
] = answer
->rdata
->u
.srv
.port
;
4951 AssignDomainName(&question
->qname
, &answer
->rdata
->u
.srv
.target
);
4952 question
->qtype
= kDNSType_AAAA
;
4953 mDNS_StartQuery(m
, question
);
4955 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== sizeof(mDNSv6Addr
) && mDNSv6AddressIsLinkLocal(&answer
->rdata
->u
.ipv6
))
4957 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv6
;
4958 intf
->SPSAddr
[sps
].ip
.v6
= answer
->rdata
->u
.ipv6
;
4960 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4963 else if (answer
->rrtype
== kDNSType_AAAA
&& answer
->rdlength
== 0) // If negative answer for IPv6, look for IPv4 addresses instead
4965 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps
, question
->qname
.c
);
4966 question
->qtype
= kDNSType_A
;
4967 mDNS_StartQuery(m
, question
);
4969 else if (answer
->rrtype
== kDNSType_A
&& answer
->rdlength
== sizeof(mDNSv4Addr
))
4971 intf
->SPSAddr
[sps
].type
= mDNSAddrType_IPv4
;
4972 intf
->SPSAddr
[sps
].ip
.v4
= answer
->rdata
->u
.ipv4
;
4974 if (sps
== intf
->NextSPSAttempt
/3) SendSPSRegistration(m
, intf
, zeroID
); // If we're ready for this result, use it now
4979 mDNSexport mDNSBool
mDNSCoreHaveAdvertisedMulticastServices(mDNS
*const m
)
4982 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
4983 if (rr
->resrec
.rrtype
== kDNSType_SRV
&& !AuthRecord_uDNS(rr
) && !mDNSSameIPPort(rr
->resrec
.rdata
->u
.srv
.port
, DiscardPort
))
4988 mDNSlocal
void SendSleepGoodbyes(mDNS
*const m
)
4991 m
->SleepState
= SleepState_Sleeping
;
4993 #ifndef UNICAST_DISABLED
4994 SleepServiceRegistrations(m
);
4995 SleepRecordRegistrations(m
); // If we have no SPS, need to deregister our uDNS records
4998 // Mark all the records we need to deregister and send them
4999 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5000 if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->RequireGoodbye
)
5001 rr
->ImmedAnswer
= mDNSInterfaceMark
;
5005 // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
5006 mDNSlocal
void BeginSleepProcessing(mDNS
*const m
)
5008 mDNSBool SendGoodbyes
= mDNStrue
;
5009 const CacheRecord
*sps
[3] = { mDNSNULL
};
5011 m
->NextScheduledSPRetry
= m
->timenow
;
5013 if (!m
->SystemWakeOnLANEnabled
) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
5014 else if (!mDNSCoreHaveAdvertisedMulticastServices(m
)) LogSPS("BeginSleepProcessing: No advertised services");
5015 else // If we have at least one advertised service
5017 NetworkInterfaceInfo
*intf
;
5018 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5020 if (!intf
->NetWake
) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf
->ifname
);
5021 #if APPLE_OSX_mDNSResponder
5022 else if (ActivateLocalProxy(m
, intf
->ifname
) == mStatus_NoError
)
5024 SendGoodbyes
= mDNSfalse
;
5025 LogSPS("BeginSleepProcessing: %-6s using local proxy", intf
->ifname
);
5026 // This will leave m->SleepState set to SleepState_Transferring,
5027 // which is okay because with no outstanding resolves, or updates in flight,
5028 // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
5030 #endif // APPLE_OSX_mDNSResponder
5033 FindSPSInCache(m
, &intf
->NetWakeBrowse
, sps
);
5034 if (!sps
[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)",
5035 intf
->ifname
, &intf
->ip
, intf
->NetWakeBrowse
.LastQTime
+ intf
->NetWakeBrowse
.ThisQInterval
- m
->timenow
, intf
->NetWakeBrowse
.ThisQInterval
);
5039 SendGoodbyes
= mDNSfalse
;
5040 intf
->NextSPSAttempt
= 0;
5041 intf
->NextSPSAttemptTime
= m
->timenow
+ mDNSPlatformOneSecond
;
5042 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
5046 if (intf
->SPSAddr
[i
].type
)
5047 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf
->ifname
, i
, intf
->SPSAddr
[i
].type
); *(long*)0 = 0; }
5048 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0)
5049 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf
->ifname
, i
, intf
->NetWakeResolve
[i
].ThisQInterval
); *(long*)0 = 0; }
5051 intf
->SPSAddr
[i
].type
= mDNSAddrType_None
;
5052 if (intf
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery(m
, &intf
->NetWakeResolve
[i
]);
5053 intf
->NetWakeResolve
[i
].ThisQInterval
= -1;
5056 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf
->ifname
, i
, sps
[i
]->resrec
.rroriginalttl
, CRDisplayString(m
, sps
[i
]));
5057 mDNS_SetupQuestion(&intf
->NetWakeResolve
[i
], intf
->InterfaceID
, &sps
[i
]->resrec
.rdata
->u
.name
, kDNSType_SRV
, NetWakeResolve
, intf
);
5058 intf
->NetWakeResolve
[i
].ReturnIntermed
= mDNStrue
;
5059 mDNS_StartQuery_internal(m
, &intf
->NetWakeResolve
[i
]);
5067 if (SendGoodbyes
) // If we didn't find even one Sleep Proxy
5069 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
5070 SendSleepGoodbyes(m
);
5074 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
5075 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
5076 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
5077 mDNSexport
void mDNSCoreMachineSleep(mDNS
*const m
, mDNSBool sleep
)
5083 LogSPS("%s (old state %d) at %ld", sleep
? "Sleeping" : "Waking", m
->SleepState
, m
->timenow
);
5085 if (sleep
&& !m
->SleepState
) // Going to sleep
5087 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5090 mDNSu8 oldstate
= m
->SPSState
;
5091 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5093 if (oldstate
== 1) mDNS_DeregisterService(m
, &m
->SPSRecords
);
5094 mDNS_ReclaimLockAfterCallback();
5097 m
->SleepState
= SleepState_Transferring
;
5098 if (m
->SystemWakeOnLANEnabled
&& m
->DelaySleep
)
5100 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5101 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m
->DelaySleep
- m
->timenow
);
5102 m
->SleepLimit
= m
->DelaySleep
+ mDNSPlatformOneSecond
* 10;
5107 m
->SleepLimit
= m
->timenow
+ mDNSPlatformOneSecond
* 10;
5108 BeginSleepProcessing(m
);
5111 #ifndef UNICAST_DISABLED
5114 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m
->SleepState
,
5115 m
->SleepState
== SleepState_Transferring
? "Transferring" :
5116 m
->SleepState
== SleepState_Sleeping
? "Sleeping" : "?", m
->SleepSeqNum
);
5118 else if (!sleep
) // Waking up
5123 NetworkInterfaceInfo
*intf
;
5125 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5126 if (m
->SleepState
!= SleepState_Awake
)
5128 m
->SleepState
= SleepState_Awake
;
5130 if (m
->SentSleepProxyRegistration
) // Include OWNER option in packets for 60 seconds after waking
5132 m
->SentSleepProxyRegistration
= mDNSfalse
;
5133 m
->AnnounceOwner
= NonZeroTime(m
->timenow
+ 60 * mDNSPlatformOneSecond
);
5135 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5136 // then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5137 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5138 // before we make our determination of whether there's a Sleep Proxy out there we should register with.
5139 m
->DelaySleep
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 16);
5142 if (m
->SPSState
== 3)
5144 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5146 mDNSCoreBeSleepProxyServer(m
, m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
);
5147 mDNS_ReclaimLockAfterCallback();
5150 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5151 // on wake we go through our record list and clear updateid back to zero
5152 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) rr
->updateid
= zeroID
;
5154 // ... and the same for NextSPSAttempt
5155 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
)) intf
->NextSPSAttempt
= -1;
5157 // Restart unicast and multicast queries
5158 mDNSCoreRestartQueries(m
);
5160 // and reactivtate service registrations
5161 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5162 LogInfo("WakeServiceRegistrations %d %d", m
->timenow
, m
->NextSRVUpdate
);
5164 // 2. Re-validate our cache records
5165 m
->NextCacheCheck
= m
->timenow
;
5166 FORALL_CACHERECORDS(slot
, cg
, cr
)
5167 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForWake
);
5169 // 3. Retrigger probing and announcing for all our authoritative records
5170 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5171 if (AuthRecord_uDNS(rr
))
5173 ActivateUnicastRegistration(m
, rr
);
5177 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
5178 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
5179 rr
->AnnounceCount
= InitialAnnounceCount
;
5180 InitializeLastAPTime(m
, rr
);
5183 // 4. Refresh NAT mappings
5184 // We don't want to have to assume that all hardware can necessarily keep accurate
5185 // track of passage of time while asleep, so on wake we refresh our NAT mappings
5186 // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address.
5187 // When we get a DHCP address and mDNS_SetPrimaryInterfaceInfo is called, we'll then set m->retryGetAddr
5188 // to immediately request our external address from the NAT gateway.
5189 m
->retryIntervalGetAddr
= NATMAP_INIT_RETRY
;
5190 m
->retryGetAddr
= m
->timenow
+ mDNSPlatformOneSecond
* 5;
5191 LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m
->retryGetAddr
- m
->timenow
, m
->timenow
);
5192 RecreateNATMappings(m
);
5198 mDNSexport mDNSBool
mDNSCoreReadyForSleep(mDNS
*m
, mDNSs32 now
)
5202 ServiceRecordSet
*srs
;
5203 NetworkInterfaceInfo
*intf
;
5207 if (m
->DelaySleep
) goto notready
;
5209 // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks
5210 if (m
->SleepLimit
- now
> 0 && m
->NextScheduledSPRetry
- now
> 0) goto notready
;
5212 m
->NextScheduledSPRetry
= now
+ 0x40000000UL
;
5214 // See if we might need to retransmit any lost Sleep Proxy Registrations
5215 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5216 if (intf
->NextSPSAttempt
>= 0)
5218 if (now
- intf
->NextSPSAttemptTime
>= 0)
5220 LogSPS("ReadyForSleep retrying SPS %s %d", intf
->ifname
, intf
->NextSPSAttempt
);
5221 SendSPSRegistration(m
, intf
, zeroID
);
5222 // Don't need to "goto notready" here, becase if we do still have record registrations
5223 // that have not been acknowledged yet, we'll catch that in the record list scan below.
5226 if (m
->NextScheduledSPRetry
- intf
->NextSPSAttemptTime
> 0)
5227 m
->NextScheduledSPRetry
= intf
->NextSPSAttemptTime
;
5230 // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
5231 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5232 if (intf
->NetWakeResolve
[0].ThisQInterval
>= 0)
5234 LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf
->ifname
, intf
->NetWakeResolve
[0].qname
.c
, DNSTypeName(intf
->NetWakeResolve
[0].qtype
));
5238 // Scan list of registered records
5239 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5240 if (!AuthRecord_uDNS(rr
))
5241 if (!mDNSOpaque16IsZero(rr
->updateid
))
5242 { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto spsnotready
; }
5244 // Scan list of private LLQs, and make sure they've all completed their handshake with the server
5245 for (q
= m
->Questions
; q
; q
= q
->next
)
5246 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->ReqLease
== 0 && q
->tcp
)
5248 LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5252 // Scan list of registered records
5253 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5254 if (AuthRecord_uDNS(rr
))
5255 if (rr
->state
== regState_Refresh
&& rr
->tcp
)
5256 { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr
->updateid
), ARDisplayString(m
,rr
)); goto notready
; }
5258 // Scan list of registered services
5259 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
5260 if (srs
->state
== regState_NoTarget
&& srs
->tcp
) goto notready
;
5267 // If we failed to complete sleep proxy registration within ten seconds, we give up on that
5268 // and allow up to ten seconds more to complete wide-area deregistration instead
5269 if (now
- m
->SleepLimit
>= 0)
5271 LogMsg("Failed to register with SPS, now sending goodbyes");
5273 for (intf
= GetFirstActiveInterface(m
->HostInterfaces
); intf
; intf
= GetFirstActiveInterface(intf
->next
))
5274 if (intf
->NetWakeBrowse
.ThisQInterval
>= 0)
5276 LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", intf
->ifname
, intf
->NetWakeResolve
[0].qname
.c
, DNSTypeName(intf
->NetWakeResolve
[0].qtype
));
5277 mDNS_DeactivateNetWake_internal(m
, intf
);
5280 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
5281 if (!AuthRecord_uDNS(rr
))
5282 if (!mDNSOpaque16IsZero(rr
->updateid
))
5284 LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m
, rr
));
5285 rr
->updateid
= zeroID
;
5288 // We'd really like to allow up to ten seconds more here,
5289 // but if we don't respond to the sleep notification within 30 seconds
5290 // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake.
5291 // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds
5292 // more for SPS resolves and record registrations to complete, which puts us at 26 seconds.
5293 // If we allow just one more second to send our goodbyes, that puts us at 27 seconds.
5294 m
->SleepLimit
= now
+ mDNSPlatformOneSecond
* 1;
5296 SendSleepGoodbyes(m
);
5304 mDNSexport mDNSs32
mDNSCoreIntervalToNextWake(mDNS
*const m
, mDNSs32 now
)
5308 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5309 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5310 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5311 // and if that happens we don't want to just give up and go back to sleep and never try again.
5312 mDNSs32 e
= now
+ (120 * 60 * mDNSPlatformOneSecond
); // Sleep for at most 120 minutes
5314 NATTraversalInfo
*nat
;
5315 for (nat
= m
->NATTraversals
; nat
; nat
=nat
->next
)
5316 if (nat
->Protocol
&& nat
->ExpiryTime
&& nat
->ExpiryTime
- now
> mDNSPlatformOneSecond
*4)
5318 mDNSs32 t
= nat
->ExpiryTime
- (nat
->ExpiryTime
- now
) / 10; // Wake up when 90% of the way to the expiry time
5319 if (e
- t
> 0) e
= t
;
5320 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5321 nat
, nat
->Protocol
== NATOp_MapTCP
? "TCP" : "UDP",
5322 mDNSVal16(nat
->IntPort
), mDNSVal16(nat
->ExternalPort
), nat
->Result
,
5323 nat
->retryPortMap
? (nat
->retryPortMap
- now
) / mDNSPlatformOneSecond
: 0,
5324 nat
->retryInterval
/ mDNSPlatformOneSecond
,
5325 nat
->ExpiryTime
? (nat
->ExpiryTime
- now
) / mDNSPlatformOneSecond
: 0,
5326 (t
- now
) / mDNSPlatformOneSecond
);
5329 // This loop checks both the time we need to renew wide-area registrations,
5330 // and the time we need to renew Sleep Proxy registrations
5331 for (ar
= m
->ResourceRecords
; ar
; ar
= ar
->next
)
5332 if (ar
->expire
&& ar
->expire
- now
> mDNSPlatformOneSecond
*4)
5334 mDNSs32 t
= ar
->expire
- (ar
->expire
- now
) / 10; // Wake up when 90% of the way to the expiry time
5335 if (e
- t
> 0) e
= t
;
5336 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5337 ar
, ar
->ThisAPInterval
/ mDNSPlatformOneSecond
,
5338 (ar
->LastAPTime
+ ar
->ThisAPInterval
- now
) / mDNSPlatformOneSecond
,
5339 ar
->expire
? (ar
->expire
- now
) / mDNSPlatformOneSecond
: 0,
5340 (t
- now
) / mDNSPlatformOneSecond
, ARDisplayString(m
, ar
));
5346 // ***************************************************************************
5347 #if COMPILER_LIKES_PRAGMA_MARK
5349 #pragma mark - Packet Reception Functions
5352 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5354 mDNSlocal mDNSu8
*GenerateUnicastResponse(const DNSMessage
*const query
, const mDNSu8
*const end
,
5355 const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, DNSMessage
*const response
, AuthRecord
*ResponseRecords
)
5357 mDNSu8
*responseptr
= response
->data
;
5358 const mDNSu8
*const limit
= response
->data
+ sizeof(response
->data
);
5359 const mDNSu8
*ptr
= query
->data
;
5361 mDNSu32 maxttl
= 0x70000000;
5364 // Initialize the response fields so we can answer the questions
5365 InitializeDNSMessage(&response
->h
, query
->h
.id
, ResponseFlags
);
5368 // *** 1. Write out the list of questions we are actually going to answer with this packet
5373 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5376 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &q
); // get the question...
5377 if (!ptr
) return(mDNSNULL
);
5379 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // and search our list of proposed answers
5381 if (rr
->NR_AnswerTo
== ptr
) // If we're going to generate a record answering this question
5382 { // then put the question in the question section
5383 responseptr
= putQuestion(response
, responseptr
, limit
, &q
.qname
, q
.qtype
, q
.qclass
);
5384 if (!responseptr
) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL
); }
5385 break; // break out of the ResponseRecords loop, and go on to the next question
5390 if (response
->h
.numQuestions
== 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL
); }
5394 // *** 2. Write Answers
5396 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5397 if (rr
->NR_AnswerTo
)
5399 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAnswers
, &rr
->resrec
,
5400 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5401 if (p
) responseptr
= p
;
5402 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response
->h
.flags
.b
[0] |= kDNSFlag0_TC
; }
5406 // *** 3. Write Additionals
5408 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5409 if (rr
->NR_AdditionalTo
&& !rr
->NR_AnswerTo
)
5411 mDNSu8
*p
= PutResourceRecordTTL(response
, responseptr
, &response
->h
.numAdditionals
, &rr
->resrec
,
5412 maxttl
< rr
->resrec
.rroriginalttl
? maxttl
: rr
->resrec
.rroriginalttl
);
5413 if (p
) responseptr
= p
;
5414 else debugf("GenerateUnicastResponse: No more space for additionals");
5417 return(responseptr
);
5420 // AuthRecord *our is our Resource Record
5421 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5422 // Returns 0 if there is no conflict
5423 // Returns +1 if there was a conflict and we won
5424 // Returns -1 if there was a conflict and we lost and have to rename
5425 mDNSlocal
int CompareRData(const AuthRecord
*const our
, const CacheRecord
*const pkt
)
5427 mDNSu8 ourdata
[256], *ourptr
= ourdata
, *ourend
;
5428 mDNSu8 pktdata
[256], *pktptr
= pktdata
, *pktend
;
5429 if (!our
) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5430 if (!pkt
) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5432 ourend
= putRData(mDNSNULL
, ourdata
, ourdata
+ sizeof(ourdata
), &our
->resrec
);
5433 pktend
= putRData(mDNSNULL
, pktdata
, pktdata
+ sizeof(pktdata
), &pkt
->resrec
);
5434 while (ourptr
< ourend
&& pktptr
< pktend
&& *ourptr
== *pktptr
) { ourptr
++; pktptr
++; }
5435 if (ourptr
>= ourend
&& pktptr
>= pktend
) return(0); // If data identical, not a conflict
5437 if (ourptr
>= ourend
) return(-1); // Our data ran out first; We lost
5438 if (pktptr
>= pktend
) return(+1); // Packet data ran out first; We won
5439 if (*pktptr
> *ourptr
) return(-1); // Our data is numerically lower; We lost
5440 if (*pktptr
< *ourptr
) return(+1); // Packet data is numerically lower; We won
5442 LogMsg("CompareRData ERROR: Invalid state");
5446 // See if we have an authoritative record that's identical to this packet record,
5447 // whose canonical DependentOn record is the specified master record.
5448 // The DependentOn pointer is typically used for the TXT record of service registrations
5449 // It indicates that there is no inherent conflict detection for the TXT record
5450 // -- it depends on the SRV record to resolve name conflicts
5451 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
5452 // pointer chain (if any) to make sure we reach the canonical DependentOn record
5453 // If the record has no DependentOn, then just return that record's pointer
5454 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5455 mDNSlocal mDNSBool
MatchDependentOn(const mDNS
*const m
, const CacheRecord
*const pktrr
, const AuthRecord
*const master
)
5457 const AuthRecord
*r1
;
5458 for (r1
= m
->ResourceRecords
; r1
; r1
=r1
->next
)
5460 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5462 const AuthRecord
*r2
= r1
;
5463 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5464 if (r2
== master
) return(mDNStrue
);
5467 for (r1
= m
->DuplicateRecords
; r1
; r1
=r1
->next
)
5469 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
5471 const AuthRecord
*r2
= r1
;
5472 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
5473 if (r2
== master
) return(mDNStrue
);
5479 // Find the canonical RRSet pointer for this RR received in a packet.
5480 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
5481 // pointers (if any) to make sure we return the canonical member of this name/type/class
5482 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5483 mDNSlocal
const AuthRecord
*FindRRSet(const mDNS
*const m
, const CacheRecord
*const pktrr
)
5485 const AuthRecord
*rr
;
5486 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
5488 if (IdenticalResourceRecord(&rr
->resrec
, &pktrr
->resrec
))
5490 while (rr
->RRSet
&& rr
!= rr
->RRSet
) rr
= rr
->RRSet
;
5497 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
5498 // as one of our records (our) but different rdata.
5499 // 1. If our record is not a type that's supposed to be unique, we don't care.
5500 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
5501 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
5502 // points to our record, ignore this conflict (e.g. the packet record matches one of our
5503 // TXT records, and that record is marked as dependent on 'our', its SRV record).
5504 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
5505 // are members of the same RRSet, then this is not a conflict.
5506 mDNSlocal mDNSBool
PacketRRConflict(const mDNS
*const m
, const AuthRecord
*const our
, const CacheRecord
*const pktrr
)
5508 // If not supposed to be unique, not a conflict
5509 if (!(our
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)) return(mDNSfalse
);
5511 // If a dependent record, not a conflict
5512 if (our
->DependentOn
|| MatchDependentOn(m
, pktrr
, our
)) return(mDNSfalse
);
5515 // If the pktrr matches a member of ourset, not a conflict
5516 const AuthRecord
*ourset
= our
->RRSet
? our
->RRSet
: our
;
5517 const AuthRecord
*pktset
= FindRRSet(m
, pktrr
);
5518 if (pktset
== ourset
) return(mDNSfalse
);
5520 // For records we're proxying, where we don't know the full
5521 // relationship between the records, having any matching record
5522 // in our AuthRecords list is sufficient evidence of non-conflict
5523 if (our
->WakeUp
.HMAC
.l
[0] && pktset
) return(mDNSfalse
);
5526 // Okay, this is a conflict
5530 // Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
5531 // the record list and/or question list.
5532 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5533 mDNSlocal
void ResolveSimultaneousProbe(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5534 DNSQuestion
*q
, AuthRecord
*our
)
5537 const mDNSu8
*ptr
= LocateAuthorities(query
, end
);
5538 mDNSBool FoundUpdate
= mDNSfalse
;
5540 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
5542 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
5544 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5546 FoundUpdate
= mDNStrue
;
5547 if (PacketRRConflict(m
, our
, &m
->rec
.r
))
5549 int result
= (int)our
->resrec
.rrclass
- (int)m
->rec
.r
.resrec
.rrclass
;
5550 if (!result
) result
= (int)our
->resrec
.rrtype
- (int)m
->rec
.r
.resrec
.rrtype
;
5551 if (!result
) result
= CompareRData(our
, &m
->rec
.r
);
5554 const char *const msg
= (result
< 0) ? "lost:" : (result
> 0) ? "won: " : "tie: ";
5555 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5556 LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our
->ProbeCount
, msg
, our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5558 // 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.
5559 // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
5560 // If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
5563 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
5564 our
->ProbeCount
= DefaultProbeCountForTypeUnique
;
5565 our
->AnnounceCount
= InitialAnnounceCount
;
5566 InitializeLastAPTime(m
, our
);
5573 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
5574 LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our
->resrec
.rdatahash
, ARDisplayString(m
, our
));
5578 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5581 LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
5583 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5586 mDNSlocal CacheRecord
*FindIdenticalRecordInCache(const mDNS
*const m
, const ResourceRecord
*const pktrr
)
5588 mDNSu32 slot
= HashSlot(pktrr
->name
);
5589 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, pktrr
);
5591 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5592 if (pktrr
->InterfaceID
== rr
->resrec
.InterfaceID
&& IdenticalSameNameRecord(pktrr
, &rr
->resrec
)) break;
5596 // Called from ProcessQuery when we get an mDNS packet with an owner record in it
5597 mDNSlocal
void ClearProxyRecords(mDNS
*const m
, const OwnerOptData
*const owner
, AuthRecord
*const thelist
)
5599 m
->CurrentRecord
= thelist
;
5600 while (m
->CurrentRecord
)
5602 AuthRecord
*const rr
= m
->CurrentRecord
;
5603 if (m
->rec
.r
.resrec
.InterfaceID
== rr
->resrec
.InterfaceID
&& mDNSSameEthAddress(&owner
->HMAC
, &rr
->WakeUp
.HMAC
))
5604 if (owner
->seq
!= rr
->WakeUp
.seq
|| m
->timenow
- rr
->TimeRcvd
> mDNSPlatformOneSecond
* 60)
5606 LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
5607 m
->ProxyRecords
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, rr
->WakeUp
.seq
, owner
->seq
, ARDisplayString(m
, rr
));
5608 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
5609 SetSPSProxyListChanged(m
->rec
.r
.resrec
.InterfaceID
);
5611 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
5612 // because the list may have been changed in that call.
5613 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
5614 m
->CurrentRecord
= rr
->next
;
5618 // ProcessQuery examines a received query to see if we have any answers to give
5619 mDNSlocal mDNSu8
*ProcessQuery(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
5620 const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, mDNSBool QueryWasMulticast
,
5621 mDNSBool QueryWasLocalUnicast
, DNSMessage
*const response
)
5623 mDNSBool FromLocalSubnet
= srcaddr
&& AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
5624 AuthRecord
*ResponseRecords
= mDNSNULL
;
5625 AuthRecord
**nrp
= &ResponseRecords
;
5626 CacheRecord
*ExpectedAnswers
= mDNSNULL
; // Records in our cache we expect to see updated
5627 CacheRecord
**eap
= &ExpectedAnswers
;
5628 DNSQuestion
*DupQuestions
= mDNSNULL
; // Our questions that are identical to questions in this packet
5629 DNSQuestion
**dqp
= &DupQuestions
;
5630 mDNSs32 delayresponse
= 0;
5631 mDNSBool SendLegacyResponse
= mDNSfalse
;
5633 mDNSu8
*responseptr
= mDNSNULL
;
5638 // *** 1. Look in Additional Section for an OPT record
5640 ptr
= LocateOptRR(query
, end
, DNSOpt_OwnerData_ID_Space
);
5643 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &m
->rec
);
5644 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
5646 const rdataOPT
*opt
;
5647 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
5648 // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
5649 // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
5650 for (opt
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; opt
< e
; opt
++)
5651 if (opt
->opt
== kDNSOpt_Owner
&& opt
->u
.owner
.vers
== 0 && opt
->u
.owner
.HMAC
.l
[0])
5653 ClearProxyRecords(m
, &opt
->u
.owner
, m
->DuplicateRecords
);
5654 ClearProxyRecords(m
, &opt
->u
.owner
, m
->ResourceRecords
);
5657 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5661 // *** 2. Parse Question Section and mark potential answers
5664 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
5666 mDNSBool QuestionNeedsMulticastResponse
;
5667 int NumAnswersForThisQuestion
= 0;
5668 AuthRecord
*NSECAnswer
= mDNSNULL
;
5669 DNSQuestion pktq
, *q
;
5670 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &pktq
); // get the question...
5671 if (!ptr
) goto exit
;
5673 // The only queries that *need* a multicast response are:
5674 // * Queries sent via multicast
5676 // * that don't have the kDNSQClass_UnicastResponse bit set
5677 // These queries need multicast responses because other clients will:
5678 // * suppress their own identical questions when they see these questions, and
5679 // * expire their cache records if they don't see the expected responses
5680 // For other queries, we may still choose to send the occasional multicast response anyway,
5681 // to keep our neighbours caches warm, and for ongoing conflict detection.
5682 QuestionNeedsMulticastResponse
= QueryWasMulticast
&& !LegacyQuery
&& !(pktq
.qclass
& kDNSQClass_UnicastResponse
);
5683 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
5684 pktq
.qclass
&= ~kDNSQClass_UnicastResponse
;
5686 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
5687 // can result in user callbacks which may change the record list and/or question list.
5688 // Also note: we just mark potential answer records here, without trying to build the
5689 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
5690 // from that list while we're in the middle of trying to build it.
5691 if (m
->CurrentRecord
)
5692 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
5693 m
->CurrentRecord
= m
->ResourceRecords
;
5694 while (m
->CurrentRecord
)
5696 rr
= m
->CurrentRecord
;
5697 m
->CurrentRecord
= rr
->next
;
5698 if (AnyTypeRecordAnswersQuestion(&rr
->resrec
, &pktq
) && (QueryWasMulticast
|| QueryWasLocalUnicast
|| rr
->AllowRemoteQuery
))
5700 if (RRTypeAnswersQuestionType(&rr
->resrec
, pktq
.qtype
))
5702 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
5703 ResolveSimultaneousProbe(m
, query
, end
, &pktq
, rr
);
5704 else if (ResourceRecordIsValidAnswer(rr
))
5706 NumAnswersForThisQuestion
++;
5707 // Note: We should check here if this is a probe-type query, and if so, generate an immediate
5708 // unicast answer back to the source, because timeliness in answering probes is important.
5711 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
5712 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
5713 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
5714 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
5715 // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
5716 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
5717 if (QuestionNeedsMulticastResponse
|| (!FromLocalSubnet
&& QueryWasMulticast
&& !LegacyQuery
))
5719 // We only mark this question for sending if it is at least one second since the last time we multicast it
5720 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
5721 // This is to guard against the case where someone blasts us with queries as fast as they can.
5722 if (m
->timenow
- (rr
->LastMCTime
+ mDNSPlatformOneSecond
) >= 0 ||
5723 (rr
->LastMCInterface
!= mDNSInterfaceMark
&& rr
->LastMCInterface
!= InterfaceID
))
5724 rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5726 else if (!rr
->NR_AnswerTo
) rr
->NR_AnswerTo
= LegacyQuery
? ptr
: (mDNSu8
*)~1;
5729 else if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
5731 // If we don't have any answers for this question, but we do own another record with the same name,
5732 // then mark it to generate an NSEC record on this interface
5733 if (!NSECAnswer
) NSECAnswer
= rr
;
5738 if (NumAnswersForThisQuestion
== 0 && NSECAnswer
)
5740 NumAnswersForThisQuestion
++;
5741 NSECAnswer
->SendNSECNow
= InterfaceID
;
5742 m
->NextScheduledResponse
= m
->timenow
;
5745 // If we couldn't answer this question, someone else might be able to,
5746 // so use random delay on response to reduce collisions
5747 if (NumAnswersForThisQuestion
== 0) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5749 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5750 if (QuestionNeedsMulticastResponse
)
5752 // We only do the following accelerated cache expiration and duplicate question suppression processing
5753 // for non-truncated multicast queries with multicast responses.
5754 // For any query generating a unicast response we don't do this because we can't assume we will see the response.
5755 // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
5756 // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
5757 if (QuestionNeedsMulticastResponse
&& !(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5760 const mDNSu32 slot
= HashSlot(&pktq
.qname
);
5761 CacheGroup
*cg
= CacheGroupForName(m
, slot
, pktq
.qnamehash
, &pktq
.qname
);
5764 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
5765 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5766 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5767 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5769 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
5770 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &pktq
) && cr
->resrec
.rdlength
<= SmallRecordLimit
)
5771 if (!cr
->NextInKAList
&& eap
!= &cr
->NextInKAList
)
5774 eap
= &cr
->NextInKAList
;
5775 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5776 if (cr
->MPUnansweredQ
== 0 || m
->timenow
- cr
->MPLastUnansweredQT
>= mDNSPlatformOneSecond
)
5778 // Although MPUnansweredQ is only really used for multi-packet query processing,
5779 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
5780 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
5781 cr
->MPUnansweredQ
++;
5782 cr
->MPLastUnansweredQT
= m
->timenow
;
5783 cr
->MPExpectingKA
= mDNStrue
;
5788 // Check if this question is the same as any of mine.
5789 // We only do this for non-truncated queries. Right now it would be too complicated to try
5790 // to keep track of duplicate suppression state between multiple packets, especially when we
5791 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
5792 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5793 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
5795 for (q
= m
->Questions
; q
; q
=q
->next
)
5796 if (!q
->Target
.type
&& ActiveQuestion(q
) && m
->timenow
- q
->LastQTxTime
> mDNSPlatformOneSecond
/ 4)
5797 if (!q
->InterfaceID
|| q
->InterfaceID
== InterfaceID
)
5798 if (q
->NextInDQList
== mDNSNULL
&& dqp
!= &q
->NextInDQList
)
5799 if (q
->qtype
== pktq
.qtype
&&
5800 q
->qclass
== pktq
.qclass
&&
5801 q
->qnamehash
== pktq
.qnamehash
&& SameDomainName(&q
->qname
, &pktq
.qname
))
5802 { *dqp
= q
; dqp
= &q
->NextInDQList
; }
5807 // *** 3. Now we can safely build the list of marked answers
5809 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) // Now build our list of potential answers
5810 if (rr
->NR_AnswerTo
) // If we marked the record...
5811 AddRecordToResponseList(&nrp
, rr
, mDNSNULL
); // ... add it to the list
5814 // *** 4. Add additional records
5816 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
5819 // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
5821 for (i
=0; i
<query
->h
.numAnswers
; i
++) // For each record in the query's answer section...
5823 // Get the record...
5824 CacheRecord
*ourcacherr
;
5825 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &m
->rec
);
5826 if (!ptr
) goto exit
;
5828 // See if this Known-Answer suppresses any of our currently planned answers
5829 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5830 if (MustSendRecord(rr
) && ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5831 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5833 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5834 for (rr
=m
->ResourceRecords
; rr
; rr
=rr
->next
)
5836 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5837 if (rr
->ImmedAnswer
== InterfaceID
&& ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
5839 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5841 if (mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= zerov4Addr
;
5843 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5845 if (mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= zerov6Addr
;
5847 if (mDNSIPv4AddressIsZero(rr
->v4Requester
) && mDNSIPv6AddressIsZero(rr
->v6Requester
))
5849 rr
->ImmedAnswer
= mDNSNULL
;
5850 rr
->ImmedUnicast
= mDNSfalse
;
5851 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5852 LogMsg("Suppressed after%4d: %s", m
->timenow
- rr
->ImmedAnswerMarkTime
, ARDisplayString(m
, rr
));
5858 ourcacherr
= FindIdenticalRecordInCache(m
, &m
->rec
.r
.resrec
);
5860 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5861 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5862 // 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).
5863 if (ourcacherr
&& ourcacherr
->MPExpectingKA
&& m
->timenow
- ourcacherr
->MPLastUnansweredQT
< mDNSPlatformOneSecond
)
5865 ourcacherr
->MPUnansweredKA
++;
5866 ourcacherr
->MPExpectingKA
= mDNSfalse
;
5870 // Having built our ExpectedAnswers list from the questions in this packet, we then remove
5871 // any records that are suppressed by the Known Answer list in this packet.
5872 eap
= &ExpectedAnswers
;
5875 CacheRecord
*cr
= *eap
;
5876 if (cr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalResourceRecord(&m
->rec
.r
.resrec
, &cr
->resrec
))
5877 { *eap
= cr
->NextInKAList
; cr
->NextInKAList
= mDNSNULL
; }
5878 else eap
= &cr
->NextInKAList
;
5881 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5884 dqp
= &DupQuestions
;
5887 DNSQuestion
*q
= *dqp
;
5888 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
5889 { *dqp
= q
->NextInDQList
; q
->NextInDQList
= mDNSNULL
; }
5890 else dqp
= &q
->NextInDQList
;
5893 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5897 // *** 6. Cancel any additionals that were added because of now-deleted records
5899 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5900 if (rr
->NR_AdditionalTo
&& !MustSendRecord(rr
->NR_AdditionalTo
))
5901 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
5904 // *** 7. Mark the send flags on the records we plan to send
5906 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
5908 if (rr
->NR_AnswerTo
)
5910 mDNSBool SendMulticastResponse
= mDNSfalse
; // Send modern multicast response
5911 mDNSBool SendUnicastResponse
= mDNSfalse
; // Send modern unicast response (not legacy unicast response)
5913 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5914 if (m
->timenow
- (rr
->LastMCTime
+ TicksTTL(rr
)/4) >= 0)
5916 SendMulticastResponse
= mDNStrue
;
5917 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5918 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5919 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5920 if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) rr
->NR_AnswerTo
= (mDNSu8
*)~0;
5923 // If the client insists on a multicast response, then we'd better send one
5924 if (rr
->NR_AnswerTo
== (mDNSu8
*)~0) SendMulticastResponse
= mDNStrue
;
5925 else if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) SendUnicastResponse
= mDNStrue
;
5926 else if (rr
->NR_AnswerTo
) SendLegacyResponse
= mDNStrue
;
5928 if (SendMulticastResponse
|| SendUnicastResponse
)
5930 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5931 rr
->ImmedAnswerMarkTime
= m
->timenow
;
5933 m
->NextScheduledResponse
= m
->timenow
;
5934 // If we're already planning to send this on another interface, just send it on all interfaces
5935 if (rr
->ImmedAnswer
&& rr
->ImmedAnswer
!= InterfaceID
)
5936 rr
->ImmedAnswer
= mDNSInterfaceMark
;
5939 rr
->ImmedAnswer
= InterfaceID
; // Record interface to send it on
5940 if (SendUnicastResponse
) rr
->ImmedUnicast
= mDNStrue
;
5941 if (srcaddr
->type
== mDNSAddrType_IPv4
)
5943 if (mDNSIPv4AddressIsZero(rr
->v4Requester
)) rr
->v4Requester
= srcaddr
->ip
.v4
;
5944 else if (!mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= onesIPv4Addr
;
5946 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
5948 if (mDNSIPv6AddressIsZero(rr
->v6Requester
)) rr
->v6Requester
= srcaddr
->ip
.v6
;
5949 else if (!mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= onesIPv6Addr
;
5953 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5954 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5955 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5956 // else, for a simple unique record reply, we can reply immediately; no need for delay
5957 if (query
->h
.flags
.b
[0] & kDNSFlag0_TC
) delayresponse
= mDNSPlatformOneSecond
* 20; // Divided by 50 = 400ms
5958 else if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
5960 else if (rr
->NR_AdditionalTo
&& rr
->NR_AdditionalTo
->NR_AnswerTo
== (mDNSu8
*)~0)
5962 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
5963 // If two clients on different interfaces do queries that invoke the same optional additional answer,
5964 // then the earlier client is out of luck
5965 rr
->ImmedAdditional
= InterfaceID
;
5966 // No need to set m->NextScheduledResponse here
5967 // We'll send these additional records when we send them, or not, as the case may be
5972 // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
5974 if (delayresponse
&& (!m
->SuppressSending
|| (m
->SuppressSending
- m
->timenow
) < (delayresponse
+ 49) / 50))
5976 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5977 mDNSs32 oldss
= m
->SuppressSending
;
5978 if (oldss
&& delayresponse
)
5979 LogMsg("Current SuppressSending delay%5ld; require%5ld", m
->SuppressSending
- m
->timenow
, (delayresponse
+ 49) / 50);
5981 // Pick a random delay:
5982 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
5983 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5984 // This is an integer value, with resolution determined by the platform clock rate.
5985 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
5986 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5987 // The +49 before dividing is to ensure we round up, not down, to ensure that even
5988 // on platforms where the native clock rate is less than fifty ticks per second,
5989 // we still guarantee that the final calculated delay is at least one platform tick.
5990 // We want to make sure we don't ever allow the delay to be zero ticks,
5991 // because if that happens we'll fail the Bonjour Conformance Test.
5992 // Our final computed delay is 20-120ms for normal delayed replies,
5993 // or 400-500ms in the case of multi-packet known-answer lists.
5994 m
->SuppressSending
= m
->timenow
+ (delayresponse
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*5) + 49) / 50;
5995 if (m
->SuppressSending
== 0) m
->SuppressSending
= 1;
5996 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5997 if (oldss
&& delayresponse
)
5998 LogMsg("Set SuppressSending to %5ld", m
->SuppressSending
- m
->timenow
);
6003 // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
6005 if (SendLegacyResponse
)
6006 responseptr
= GenerateUnicastResponse(query
, end
, InterfaceID
, LegacyQuery
, response
, ResponseRecords
);
6009 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6012 // *** 10. Finally, clear our link chains ready for use next time
6014 while (ResponseRecords
)
6016 rr
= ResponseRecords
;
6017 ResponseRecords
= rr
->NextResponse
;
6018 rr
->NextResponse
= mDNSNULL
;
6019 rr
->NR_AnswerTo
= mDNSNULL
;
6020 rr
->NR_AdditionalTo
= mDNSNULL
;
6023 while (ExpectedAnswers
)
6025 CacheRecord
*cr
= ExpectedAnswers
;
6026 ExpectedAnswers
= cr
->NextInKAList
;
6027 cr
->NextInKAList
= mDNSNULL
;
6029 // For non-truncated queries, we can definitively say that we should expect
6030 // to be seeing a response for any records still left in the ExpectedAnswers list
6031 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
6032 if (cr
->UnansweredQueries
== 0 || m
->timenow
- cr
->LastUnansweredTime
>= mDNSPlatformOneSecond
)
6034 cr
->UnansweredQueries
++;
6035 cr
->LastUnansweredTime
= m
->timenow
;
6036 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6037 if (cr
->UnansweredQueries
> 1)
6038 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
6039 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
6041 SetNextCacheCheckTime(m
, cr
);
6044 // If we've seen multiple unanswered queries for this record,
6045 // then mark it to expire in five seconds if we don't get a response by then.
6046 if (cr
->UnansweredQueries
>= MaxUnansweredQueries
)
6048 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6049 // Only show debugging message if this record was not about to expire anyway
6050 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
6051 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
6052 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
6054 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
6056 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6057 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
6058 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
6059 // possible packet loss of up to 20% of the additional KA packets.)
6060 else if (cr
->MPUnansweredQ
* 4 > cr
->MPUnansweredKA
* 5 + 8)
6062 // We want to do this conservatively.
6063 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
6064 // then we don't want them to all hit the network simultaneously with their final expiration queries.
6065 // By setting the record to expire in four minutes, we achieve two things:
6066 // (a) the 90-95% final expiration queries will be less bunched together
6067 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
6068 mDNSu32 remain
= (mDNSu32
)(RRExpireTime(cr
) - m
->timenow
) / 4;
6069 if (remain
> 240 * (mDNSu32
)mDNSPlatformOneSecond
)
6070 remain
= 240 * (mDNSu32
)mDNSPlatformOneSecond
;
6072 // Only show debugging message if this record was not about to expire anyway
6073 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
6074 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
6075 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
6077 if (remain
<= 60 * (mDNSu32
)mDNSPlatformOneSecond
)
6078 cr
->UnansweredQueries
++; // Treat this as equivalent to one definite unanswered query
6079 cr
->MPUnansweredQ
= 0; // Clear MPQ/MPKA statistics
6080 cr
->MPUnansweredKA
= 0;
6081 cr
->MPExpectingKA
= mDNSfalse
;
6083 if (remain
< kDefaultReconfirmTimeForNoAnswer
)
6084 remain
= kDefaultReconfirmTimeForNoAnswer
;
6085 mDNS_Reconfirm_internal(m
, cr
, remain
);
6090 while (DupQuestions
)
6092 DNSQuestion
*q
= DupQuestions
;
6093 DupQuestions
= q
->NextInDQList
;
6094 q
->NextInDQList
= mDNSNULL
;
6095 i
= RecordDupSuppressInfo(q
->DupSuppress
, m
->timenow
, InterfaceID
, srcaddr
->type
);
6096 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q
->qname
.c
, DNSTypeName(q
->qtype
), InterfaceID
,
6097 srcaddr
->type
== mDNSAddrType_IPv4
? "v4" : "v6", i
);
6100 return(responseptr
);
6103 mDNSlocal
void mDNSCoreReceiveQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
6104 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6105 const mDNSInterfaceID InterfaceID
)
6107 mDNSu8
*responseend
= mDNSNULL
;
6108 mDNSBool QueryWasLocalUnicast
= srcaddr
&& dstaddr
&&
6109 !mDNSAddrIsDNSMulticast(dstaddr
) && AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
6111 if (!InterfaceID
&& dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
))
6113 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6114 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
6115 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6116 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6117 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6118 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6119 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6123 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6124 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6125 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6126 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6127 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6128 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6129 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6131 responseend
= ProcessQuery(m
, msg
, end
, srcaddr
, InterfaceID
,
6132 !mDNSSameIPPort(srcport
, MulticastDNSPort
), mDNSAddrIsDNSMulticast(dstaddr
), QueryWasLocalUnicast
, &m
->omsg
);
6134 if (responseend
) // If responseend is non-null, that means we built a unicast response packet
6136 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
6137 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
6138 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
6139 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s",
6140 srcaddr
, mDNSVal16(srcport
), InterfaceID
, srcaddr
->type
);
6141 mDNSSendDNSMessage(m
, &m
->omsg
, responseend
, InterfaceID
, mDNSNULL
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
6146 mDNSlocal mDNSBool
TrustedSource(const mDNS
*const m
, const mDNSAddr
*const srcaddr
)
6150 (void)srcaddr
; // Unused
6151 for (s
= m
->DNSServers
; s
; s
= s
->next
)
6152 if (mDNSSameAddress(srcaddr
, &s
->addr
)) return(mDNStrue
);
6157 struct UDPSocket_struct
6159 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
6162 mDNSlocal DNSQuestion
*ExpectingUnicastResponseForQuestion(const mDNS
*const m
, const mDNSIPPort port
, const mDNSOpaque16 id
, const DNSQuestion
*const question
)
6165 for (q
= m
->Questions
; q
; q
=q
->next
)
6166 if (q
->LocalSocket
&&
6167 mDNSSameIPPort (q
->LocalSocket
->port
, port
) &&
6168 mDNSSameOpaque16(q
->TargetQID
, id
) &&
6169 q
->qtype
== question
->qtype
&&
6170 q
->qclass
== question
->qclass
&&
6171 q
->qnamehash
== question
->qnamehash
&&
6172 SameDomainName(&q
->qname
, &question
->qname
))
6177 mDNSlocal mDNSBool
ExpectingUnicastResponseForRecord(mDNS
*const m
, const mDNSAddr
*const srcaddr
, const mDNSBool SrcLocal
, const mDNSIPPort port
, const mDNSOpaque16 id
, const CacheRecord
*const rr
)
6182 for (q
= m
->Questions
; q
; q
=q
->next
)
6183 if (!q
->DuplicateOf
&& ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
6185 if (!mDNSOpaque16IsZero(q
->TargetQID
))
6187 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id
), mDNSVal16(q
->TargetQID
), CRDisplayString(m
, rr
));
6188 if (mDNSSameOpaque16(q
->TargetQID
, id
))
6190 if (q
->LocalSocket
&& mDNSSameIPPort(q
->LocalSocket
->port
, port
)) return(mDNStrue
);
6191 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
6192 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
6193 // if (TrustedSource(m, srcaddr)) return(mDNStrue);
6194 LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
6195 q
->qname
.c
, DNSTypeName(q
->qtype
), &q
->Target
, mDNSVal16(q
->LocalSocket
? q
->LocalSocket
->port
: zeroIPPort
), srcaddr
, mDNSVal16(port
), CRDisplayString(m
, rr
));
6201 if (SrcLocal
&& q
->ExpectUnicastResp
&& (mDNSu32
)(m
->timenow
- q
->ExpectUnicastResp
) < (mDNSu32
)(mDNSPlatformOneSecond
*2))
6208 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
6209 // Currently this applies only to rdata types containing more than one domainname,
6210 // or types where the domainname is not the last item in the structure.
6211 // In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
6212 mDNSlocal mDNSu16
GetRDLengthMem(const ResourceRecord
*const rr
)
6216 case kDNSType_SOA
: return sizeof(rdataSOA
);
6217 case kDNSType_RP
: return sizeof(rdataRP
);
6218 case kDNSType_PX
: return sizeof(rdataPX
);
6219 case kDNSType_NSEC
:return sizeof(rdataNSEC
);
6220 default: return rr
->rdlength
;
6224 mDNSexport CacheRecord
*CreateNewCacheEntry(mDNS
*const m
, const mDNSu32 slot
, CacheGroup
*cg
)
6226 CacheRecord
*rr
= mDNSNULL
;
6227 mDNSu16 RDLength
= GetRDLengthMem(&m
->rec
.r
.resrec
);
6229 if (!m
->rec
.r
.resrec
.InterfaceID
) debugf("CreateNewCacheEntry %s", CRDisplayString(m
, &m
->rec
.r
));
6231 //if (RDLength > InlineCacheRDSize)
6232 // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
6234 if (!cg
) cg
= GetCacheGroup(m
, slot
, &m
->rec
.r
.resrec
); // If we don't have a CacheGroup for this name, make one now
6235 if (cg
) rr
= GetCacheRecord(m
, cg
, RDLength
); // Make a cache record, being careful not to recycle cg
6236 if (!rr
) NoCacheAnswer(m
, &m
->rec
.r
);
6239 RData
*saveptr
= rr
->resrec
.rdata
; // Save the rr->resrec.rdata pointer
6240 *rr
= m
->rec
.r
; // Block copy the CacheRecord object
6241 rr
->resrec
.rdata
= saveptr
; // Restore rr->resrec.rdata after the structure assignment
6242 rr
->resrec
.name
= cg
->name
; // And set rr->resrec.name to point into our CacheGroup header
6244 // If this is an oversized record with external storage allocated, copy rdata to external storage
6245 if (rr
->resrec
.rdata
== (RData
*)&rr
->smallrdatastorage
&& RDLength
> InlineCacheRDSize
)
6246 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6247 else if (rr
->resrec
.rdata
!= (RData
*)&rr
->smallrdatastorage
&& RDLength
<= InlineCacheRDSize
)
6248 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
6249 if (RDLength
> InlineCacheRDSize
)
6250 mDNSPlatformMemCopy(rr
->resrec
.rdata
, m
->rec
.r
.resrec
.rdata
, sizeofRDataHeader
+ RDLength
);
6252 rr
->next
= mDNSNULL
; // Clear 'next' pointer
6253 *(cg
->rrcache_tail
) = rr
; // Append this record to tail of cache slot list
6254 cg
->rrcache_tail
= &(rr
->next
); // Advance tail pointer
6255 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
6256 rr
->DelayDelivery
= NonZeroTime(m
->timenow
);
6257 else if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
&& // If marked unique,
6258 rr
->resrec
.rdata
->MaxRDLength
!= 0) // and non-negative, assume we may have
6259 rr
->DelayDelivery
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
); // to delay delivery of this 'add' event
6261 rr
->DelayDelivery
= CheckForSoonToExpireRecords(m
, rr
->resrec
.name
, rr
->resrec
.namehash
, slot
);
6263 CacheRecordAdd(m
, rr
); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
6268 mDNSlocal
void RefreshCacheRecord(mDNS
*const m
, CacheRecord
*rr
, mDNSu32 ttl
)
6270 rr
->TimeRcvd
= m
->timenow
;
6271 rr
->resrec
.rroriginalttl
= ttl
;
6272 rr
->UnansweredQueries
= 0;
6273 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6274 rr
->MPUnansweredQ
= 0;
6275 rr
->MPUnansweredKA
= 0;
6276 rr
->MPExpectingKA
= mDNSfalse
;
6278 SetNextCacheCheckTime(m
, rr
);
6281 mDNSexport
void GrantCacheExtensions(mDNS
*const m
, DNSQuestion
*q
, mDNSu32 lease
)
6284 const mDNSu32 slot
= HashSlot(&q
->qname
);
6285 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
6286 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6287 if (rr
->CRActiveQuestion
== q
)
6289 //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
6290 RefreshCacheRecord(m
, rr
, lease
);
6294 mDNSlocal mDNSu32
GetEffectiveTTL(const uDNS_LLQType LLQType
, mDNSu32 ttl
) // TTL in seconds
6296 if (LLQType
== uDNS_LLQ_Entire
) ttl
= kLLQ_DefLease
;
6297 else if (LLQType
== uDNS_LLQ_Events
)
6299 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
6300 if (ttl
== 0xFFFFFFFF) ttl
= 0;
6301 else ttl
= kLLQ_DefLease
;
6303 else // else not LLQ (standard uDNS response)
6305 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
6306 // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL
6307 if (ttl
> 0x60000000UL
/ mDNSPlatformOneSecond
) ttl
= 0x60000000UL
/ mDNSPlatformOneSecond
;
6309 // Adjustment factor to avoid race condition:
6310 // 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.
6311 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
6312 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
6313 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
6314 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
6315 // the cached copy at our local caching server will already have expired, so the server will be forced
6316 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
6319 // For mDNS, TTL zero means "delete this record"
6320 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
6321 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
6322 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
6323 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
6324 if (ttl
< 15) ttl
= 15;
6330 // Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
6331 // the record list and/or question list.
6332 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6333 // InterfaceID non-NULL tells us the interface this multicast response was received on
6334 // InterfaceID NULL tells us this was a unicast response
6335 // dstaddr NULL tells us we received this over an outgoing TCP connection we made
6336 mDNSlocal
void mDNSCoreReceiveResponse(mDNS
*const m
,
6337 const DNSMessage
*const response
, const mDNSu8
*end
,
6338 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6339 const mDNSInterfaceID InterfaceID
)
6342 mDNSBool ResponseMCast
= dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
);
6343 mDNSBool ResponseSrcLocal
= !srcaddr
|| AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
6344 uDNS_LLQType LLQType
= uDNS_recvLLQResponse(m
, response
, end
, srcaddr
, srcport
);
6346 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
6347 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
6348 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
6349 CacheRecord
*CacheFlushRecords
= (CacheRecord
*)1;
6350 CacheRecord
**cfp
= &CacheFlushRecords
;
6352 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
6353 // to guard against spoof responses, then the only credible protection against that is cryptographic
6354 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
6355 int firstauthority
= response
->h
.numAnswers
;
6356 int firstadditional
= firstauthority
+ response
->h
.numAuthorities
;
6357 int totalrecords
= firstadditional
+ response
->h
.numAdditionals
;
6358 const mDNSu8
*ptr
= response
->data
;
6360 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
6361 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
6362 srcaddr
, dstaddr
, InterfaceID
,
6363 response
->h
.numQuestions
, response
->h
.numQuestions
== 1 ? ", " : "s,",
6364 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6365 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6366 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s", LLQType
);
6368 // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
6369 // When a DNS client receives a reply with TC
6370 // set, it should ignore that response, and query again, using a
6371 // mechanism, such as a TCP connection, that will permit larger replies.
6372 // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
6373 // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
6374 // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
6375 // <rdar://problem/6690034> Can't bind to Active Directory
6376 // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
6377 // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
6378 // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
6379 // and not even do the TCP query.
6380 // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
6381 if (!InterfaceID
&& (response
->h
.flags
.b
[0] & kDNSFlag0_TC
)) return;
6383 if (LLQType
== uDNS_LLQ_Ignore
) return;
6385 // 1. We ignore questions (if any) in mDNS response packets
6386 // 2. If this is an LLQ response, we handle it much the same
6387 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
6388 // answer as being the authoritative complete RRSet, and respond by deleting all other
6389 // matching cache records that don't appear in this packet.
6390 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
6391 if (ResponseMCast
|| LLQType
== uDNS_LLQ_Events
|| (response
->h
.flags
.b
[0] & kDNSFlag0_TC
))
6392 ptr
= LocateAnswers(response
, end
);
6393 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
6394 // in this response packet are immediately deemed to be invalid.
6397 mDNSu8 rcode
= (mDNSu8
)(response
->h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
6398 mDNSBool failure
= !(rcode
== kDNSFlag1_RC_NoErr
|| rcode
== kDNSFlag1_RC_NXDomain
|| rcode
== kDNSFlag1_RC_NotAuth
);
6399 mDNSBool returnEarly
= mDNSfalse
;
6400 // We could possibly combine this with the similar loop at the end of this function --
6401 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
6402 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
6403 // which it was received (or refreshed), and then at the end if we find any cache records which
6404 // answer questions in this packet's question section, but which aren't tagged with this packet's
6405 // packet number, then we deduce they are old and delete them
6406 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6408 DNSQuestion q
, *qptr
= mDNSNULL
;
6409 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6410 if (ptr
&& (!dstaddr
|| (qptr
= ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
))))
6415 const mDNSu32 slot
= HashSlot(&q
.qname
);
6416 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6417 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6418 if (q
.InterfaceID
== rr
->resrec
.InterfaceID
&& SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6420 debugf("uDNS marking %p %##s (%s) %p %s", q
.InterfaceID
, q
.qname
.c
, DNSTypeName(q
.qtype
),
6421 rr
->resrec
.InterfaceID
, CRDisplayString(m
, rr
));
6422 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
6423 rr
->TimeRcvd
= m
->timenow
- TicksTTL(rr
) - 1;
6424 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6431 LogInfo("Server %p responded with code %d to query %##s (%s)", qptr
->qDNSServer
, rcode
, q
.qname
.c
, DNSTypeName(q
.qtype
));
6432 PenalizeDNSServer(m
, qptr
, mDNSfalse
);
6434 returnEarly
= mDNStrue
;
6440 LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
6441 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
6442 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6443 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s");
6444 // not goto exit because we won't have any CacheFlushRecords and we do not want to
6445 // generate negative cache entries (we want to query the next server)
6450 for (i
= 0; i
< totalrecords
&& ptr
&& ptr
< end
; i
++)
6452 // All responses sent via LL multicast are acceptable for caching
6453 // All responses received over our outbound TCP connections are acceptable for caching
6454 mDNSBool AcceptableResponse
= ResponseMCast
|| !dstaddr
|| LLQType
;
6455 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
6456 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
6458 const mDNSu8 RecordType
=
6459 (i
< firstauthority
) ? (mDNSu8
)kDNSRecordTypePacketAns
:
6460 (i
< firstadditional
) ? (mDNSu8
)kDNSRecordTypePacketAuth
: (mDNSu8
)kDNSRecordTypePacketAdd
;
6461 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, RecordType
, &m
->rec
);
6462 if (!ptr
) goto exit
; // Break out of the loop and clean up our CacheFlushRecords list before exiting
6464 // Don't want to cache OPT or TSIG pseudo-RRs
6465 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
|| m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
6466 { m
->rec
.r
.resrec
.RecordType
= 0; continue; }
6468 // if a CNAME record points to itself, then don't add it to the cache
6469 if ((m
->rec
.r
.resrec
.rrtype
== kDNSType_CNAME
) && SameDomainName(m
->rec
.r
.resrec
.name
, &m
->rec
.r
.resrec
.rdata
->u
.name
))
6471 LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m
->rec
.r
.resrec
.name
->c
);
6472 m
->rec
.r
.resrec
.RecordType
= 0;
6476 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
6477 // In the case of active LLQs, we'll get remove events when the records actually do go away
6478 // In the case of polling LLQs, we assume the record remains valid until the next poll
6479 if (!mDNSOpaque16IsZero(response
->h
.id
))
6480 m
->rec
.r
.resrec
.rroriginalttl
= GetEffectiveTTL(LLQType
, m
->rec
.r
.resrec
.rroriginalttl
);
6482 // If response was not sent via LL multicast,
6483 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
6484 if (!AcceptableResponse
) AcceptableResponse
= ExpectingUnicastResponseForRecord(m
, srcaddr
, ResponseSrcLocal
, dstport
, response
->h
.id
, &m
->rec
.r
);
6486 // 1. Check that this packet resource record does not conflict with any of ours
6487 if (mDNSOpaque16IsZero(response
->h
.id
) && m
->rec
.r
.resrec
.rrtype
!= kDNSType_NSEC
)
6489 if (m
->CurrentRecord
)
6490 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
6491 m
->CurrentRecord
= m
->ResourceRecords
;
6492 while (m
->CurrentRecord
)
6494 AuthRecord
*rr
= m
->CurrentRecord
;
6495 m
->CurrentRecord
= rr
->next
;
6496 // We accept all multicast responses, and unicast responses resulting from queries we issued
6497 // For other unicast responses, this code accepts them only for responses with an
6498 // (apparently) local source address that pertain to a record of our own that's in probing state
6499 if (!AcceptableResponse
&& !(ResponseSrcLocal
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)) continue;
6501 if (PacketRRMatchesSignature(&m
->rec
.r
, rr
)) // If interface, name, type (if shared record) and class match...
6503 // ... check to see if type and rdata are identical
6504 if (IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6506 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
6507 if (m
->rec
.r
.resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/2 || m
->SleepState
)
6509 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
6510 if (rr
->ImmedAnswer
== InterfaceID
) { rr
->ImmedAnswer
= mDNSNULL
; rr
->ImmedUnicast
= mDNSfalse
; }
6514 if (rr
->ImmedAnswer
== mDNSNULL
) { rr
->ImmedAnswer
= InterfaceID
; m
->NextScheduledResponse
= m
->timenow
; }
6515 else if (rr
->ImmedAnswer
!= InterfaceID
) { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6518 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
6519 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0 && PacketRRConflict(m
, rr
, &m
->rec
.r
))
6521 LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
6522 LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6524 // If this record is marked DependentOn another record for conflict detection purposes,
6525 // then *that* record has to be bumped back to probing state to resolve the conflict
6526 if (rr
->DependentOn
)
6528 while (rr
->DependentOn
) rr
= rr
->DependentOn
;
6529 LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
6532 // If we've just whacked this record's ProbeCount, don't need to do it again
6533 if (rr
->ProbeCount
> DefaultProbeCountForTypeUnique
)
6534 LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m
, rr
));
6535 else if (rr
->ProbeCount
== DefaultProbeCountForTypeUnique
)
6536 LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m
, rr
));
6539 LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr
, mDNSVal16(srcport
), CRDisplayString(m
, &m
->rec
.r
));
6540 // If we'd previously verified this record, put it back to probing state and try again
6541 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
6543 LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m
, rr
));
6544 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
6545 // We set ProbeCount to one more than the usual value so we know we've already touched this record.
6546 // This is because our single probe for "example-name.local" could yield a response with (say) two A records and
6547 // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
6548 // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
6549 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
+ 1;
6550 rr
->AnnounceCount
= InitialAnnounceCount
;
6551 InitializeLastAPTime(m
, rr
);
6552 RecordProbeFailure(m
, rr
); // Repeated late conflicts also cause us to back off to the slower probing rate
6554 // If we're probing for this record, we just failed
6555 else if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
6557 LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr
->ProbeCount
, ARDisplayString(m
, rr
));
6558 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6560 // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
6561 // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
6562 else if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
6564 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m
, rr
));
6565 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
6568 LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
6571 // Else, matching signature, different type or rdata, but not a considered a conflict.
6572 // If the packet record has the cache-flush bit set, then we check to see if we
6573 // have any record(s) of the same type that we should re-assert to rescue them
6574 // (see note about "multi-homing and bridged networks" at the end of this function).
6575 else if (m
->rec
.r
.resrec
.rrtype
== rr
->resrec
.rrtype
)
6576 if ((m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && m
->timenow
- rr
->LastMCTime
> mDNSPlatformOneSecond
/2)
6577 { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
6582 if (!AcceptableResponse
)
6584 const CacheRecord
*cr
;
6585 for (cr
= CacheFlushRecords
; cr
!= (CacheRecord
*)1; cr
= cr
->NextInCFList
)
6587 domainname
*target
= GetRRDomainNameTarget(&cr
->resrec
);
6588 if (target
&& cr
->resrec
.rdatahash
== m
->rec
.r
.resrec
.namehash
&& SameDomainName(target
, m
->rec
.r
.resrec
.name
))
6589 { AcceptableResponse
= mDNStrue
; break; }
6593 // 2. See if we want to add this packet resource record to our cache
6594 // We only try to cache answers if we have a cache to put them in
6595 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
6596 if (!AcceptableResponse
) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m
, &m
->rec
.r
));
6597 if (m
->rrcache_size
&& AcceptableResponse
)
6599 const mDNSu32 slot
= HashSlot(m
->rec
.r
.resrec
.name
);
6600 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &m
->rec
.r
.resrec
);
6603 // 2a. Check if this packet resource record is already in our cache
6604 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6606 // If we found this exact resource record, refresh its TTL
6607 if (rr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
6609 if (m
->rec
.r
.resrec
.rdlength
> InlineCacheRDSize
)
6610 verbosedebugf("Found record size %5d interface %p already in cache: %s",
6611 m
->rec
.r
.resrec
.rdlength
, InterfaceID
, CRDisplayString(m
, &m
->rec
.r
));
6612 rr
->TimeRcvd
= m
->timenow
;
6614 if (m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
)
6616 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
6617 if (rr
->NextInCFList
== mDNSNULL
&& cfp
!= &rr
->NextInCFList
&& LLQType
!= uDNS_LLQ_Events
)
6618 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6620 // If this packet record is marked unique, and our previous cached copy was not, then fix it
6621 if (!(rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))
6624 for (q
= m
->Questions
; q
; q
=q
->next
) if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
)) q
->UniqueAnswers
++;
6625 rr
->resrec
.RecordType
= m
->rec
.r
.resrec
.RecordType
;
6629 if (!mDNSPlatformMemSame(m
->rec
.r
.resrec
.rdata
->u
.data
, rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
))
6631 // If the rdata of the packet record differs in name capitalization from the record in our cache
6632 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
6633 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
6634 rr
->resrec
.rroriginalttl
= 0;
6635 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6636 SetNextCacheCheckTime(m
, rr
);
6637 // DO NOT break out here -- we want to continue as if we never found it
6639 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0)
6642 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
6643 RefreshCacheRecord(m
, rr
, m
->rec
.r
.resrec
.rroriginalttl
);
6645 // We have to reset the question interval to MaxQuestionInterval so that we don't keep
6646 // polling the network once we get a valid response back. For the first time when a new
6647 // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that.
6648 // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server
6649 // configuration changed, without flushing the cache, we reset the question interval here.
6650 // Currently, we do this for for both multicast and unicast questions as long as the record
6651 // type is unique. For unicast, resource record is always unique and for multicast it is
6652 // true for records like A etc. but not for PTR.
6653 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
)
6655 for (q
= m
->Questions
; q
; q
=q
->next
)
6658 if (!q
->DuplicateOf
&& !q
->LongLived
&&
6659 ActiveQuestion(q
) && ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
6661 q
->LastQTime
= m
->timenow
;
6662 q
->LastQTxTime
= m
->timenow
;
6663 q
->RecentAnswerPkts
= 0;
6664 q
->ThisQInterval
= MaxQuestionInterval
;
6665 q
->RequestUnicast
= mDNSfalse
;
6666 q
->unansweredQueries
= 0;
6667 debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
6676 // If the packet TTL is zero, that means we're deleting this record.
6677 // To give other hosts on the network a chance to protest, we push the deletion
6678 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
6679 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
6680 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
6681 debugf("DE for %s", CRDisplayString(m
, rr
));
6682 rr
->resrec
.rroriginalttl
= 1;
6683 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6684 SetNextCacheCheckTime(m
, rr
);
6690 // If packet resource record not in our cache, add it now
6691 // (unless it is just a deletion of a record we never had, in which case we don't care)
6692 if (!rr
&& m
->rec
.r
.resrec
.rroriginalttl
> 0)
6694 rr
= CreateNewCacheEntry(m
, slot
, cg
);
6695 if (rr
&& (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && LLQType
!= uDNS_LLQ_Events
)
6696 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
6699 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6703 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6705 // If we've just received one or more records with their cache flush bits set,
6706 // then scan that cache slot to see if there are any old stale records we need to flush
6707 while (CacheFlushRecords
!= (CacheRecord
*)1)
6709 CacheRecord
*r1
= CacheFlushRecords
, *r2
;
6710 const mDNSu32 slot
= HashSlot(r1
->resrec
.name
);
6711 const CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &r1
->resrec
);
6712 CacheFlushRecords
= CacheFlushRecords
->NextInCFList
;
6713 r1
->NextInCFList
= mDNSNULL
;
6715 // Look for records in the cache with the same signature as this new one with the cache flush
6716 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
6717 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
6718 // We make these TTL adjustments *only* for records that still have *more* than one second
6719 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
6720 // (and now has half a second remaining) could inadvertently get its life extended, by either
6721 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
6722 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
6723 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
6724 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
6725 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
6726 // To avoid this, we need to ensure that the cache flushing operation will only act to
6727 // *decrease* a record's remaining lifetime, never *increase* it.
6728 for (r2
= cg
? cg
->members
: mDNSNULL
; r2
; r2
=r2
->next
)
6729 if (r1
->resrec
.InterfaceID
== r2
->resrec
.InterfaceID
&&
6730 r1
->resrec
.rrtype
== r2
->resrec
.rrtype
&&
6731 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
)
6733 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
6734 // else, if record is old, mark it to be flushed
6735 if (m
->timenow
- r2
->TimeRcvd
< mDNSPlatformOneSecond
&& RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6737 // If we find mismatched TTLs in an RRSet, correct them.
6738 // We only do this for records with a TTL of 2 or higher. It's possible to have a
6739 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
6740 // which we treat as a goodbye followed by an addition) and in that case it would be
6741 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
6742 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
6743 // because certain early Bonjour devices are known to have this specific mismatch, and
6744 // there's no point filling syslog with messages about something we already know about.
6745 // We also don't log this for uDNS responses, since a caching name server is obliged
6746 // to give us an aged TTL to correct for how long it has held the record,
6747 // so our received TTLs are expected to vary in that case
6748 if (r2
->resrec
.rroriginalttl
!= r1
->resrec
.rroriginalttl
&& r1
->resrec
.rroriginalttl
> 1)
6750 if (!(r2
->resrec
.rroriginalttl
== 240 && r1
->resrec
.rroriginalttl
== 60 && r2
->resrec
.rrtype
== kDNSType_TXT
) &&
6751 mDNSOpaque16IsZero(response
->h
.id
))
6752 LogInfo("Correcting TTL from %4d to %4d for %s",
6753 r2
->resrec
.rroriginalttl
, r1
->resrec
.rroriginalttl
, CRDisplayString(m
, r2
));
6754 r2
->resrec
.rroriginalttl
= r1
->resrec
.rroriginalttl
;
6756 r2
->TimeRcvd
= m
->timenow
;
6758 else // else, if record is old, mark it to be flushed
6760 verbosedebugf("Cache flush %p X %p %s", r1
, r2
, CRDisplayString(m
, r2
));
6761 // We set stale records to expire in one second.
6762 // This gives the owner a chance to rescue it if necessary.
6763 // This is important in the case of multi-homing and bridged networks:
6764 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
6765 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
6766 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
6767 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
6768 // By delaying the deletion by one second, we give X a change to notice that this bridging has
6769 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
6771 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
6772 // final expiration queries for this record.
6774 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
6775 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
6776 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
6777 if (r2
->TimeRcvd
== m
->timenow
&& r2
->resrec
.rroriginalttl
<= 1 && r2
->UnansweredQueries
== MaxUnansweredQueries
)
6779 debugf("Cache flush for DE record %s", CRDisplayString(m
, r2
));
6780 r2
->resrec
.rroriginalttl
= 0;
6781 m
->NextCacheCheck
= m
->timenow
;
6782 m
->NextScheduledEvent
= m
->timenow
;
6784 else if (RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
6786 // We only set a record to expire in one second if it currently has *more* than a second to live
6787 // If it's already due to expire in a second or less, we just leave it alone
6788 r2
->resrec
.rroriginalttl
= 1;
6789 r2
->UnansweredQueries
= MaxUnansweredQueries
;
6790 r2
->TimeRcvd
= m
->timenow
- 1;
6791 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
6792 // that we marked for deletion via an explicit DE record
6795 SetNextCacheCheckTime(m
, r2
);
6797 if (r1
->DelayDelivery
) // If we were planning to delay delivery of this record, see if we still need to
6799 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
6800 r1
->DelayDelivery
= CheckForSoonToExpireRecords(m
, r1
->resrec
.name
, r1
->resrec
.namehash
, slot
);
6801 if (!r1
->DelayDelivery
) CacheRecordDeferredAdd(m
, r1
);
6805 // See if we need to generate negative cache entries for unanswered unicast questions
6806 ptr
= response
->data
;
6807 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
6810 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
6811 if (ptr
&& (!dstaddr
|| ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
)))
6813 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
6814 // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
6815 // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
6816 // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
6817 // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
6818 // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
6819 // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
6820 // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
6821 // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
6822 // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
6823 if (!InterfaceID
&& q
.qtype
!= kDNSType_SOA
&& IsLocalDomain(&q
.qname
))
6824 LogInfo("Not generating negative cache entry for %##s (%s)", q
.qname
.c
, DNSTypeName(q
.qtype
));
6827 CacheRecord
*rr
, *neg
= mDNSNULL
;
6828 mDNSu32 slot
= HashSlot(&q
.qname
);
6829 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
6830 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
6831 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
6833 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
6834 if (rr
->TimeRcvd
+ TicksTTL(rr
) - m
->timenow
> 0) break;
6835 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
6836 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
) neg
= rr
;
6841 // We start off assuming a negative caching TTL of 60 seconds
6842 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
6843 mDNSu32 negttl
= 60;
6845 const domainname
*name
= &q
.qname
;
6846 mDNSu32 hash
= q
.qnamehash
;
6848 // Special case for our special Microsoft Active Directory "local SOA" check.
6849 // Some cheap home gateways don't include an SOA record in the authority section when
6850 // they send negative responses, so we don't know how long to cache the negative result.
6851 // Because we don't want to keep hitting the root name servers with our query to find
6852 // if we're on a network using Microsoft Active Directory using "local" as a private
6853 // internal top-level domain, we make sure to cache the negative result for at least one day.
6854 if (q
.qtype
== kDNSType_SOA
&& SameDomainName(&q
.qname
, &localdomain
)) negttl
= 60 * 60 * 24;
6856 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
6857 if (response
->h
.numAuthorities
&& (ptr
= LocateAuthorities(response
, end
)) != mDNSNULL
)
6859 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
6860 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_SOA
)
6862 const rdataSOA
*const soa
= (const rdataSOA
*)m
->rec
.r
.resrec
.rdata
->u
.data
;
6863 mDNSu32 ttl_s
= soa
->min
;
6864 // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
6865 // for the SOA record for ".", where the record is reported as non-cacheable
6866 // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
6867 if (ttl_s
> m
->rec
.r
.resrec
.rroriginalttl
&& m
->rec
.r
.resrec
.name
->c
[0])
6868 ttl_s
= m
->rec
.r
.resrec
.rroriginalttl
;
6869 if (negttl
< ttl_s
) negttl
= ttl_s
;
6871 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
6872 // with an Authority Section SOA record for d.com, then this is a hint that the authority
6873 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
6874 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
6875 if (q
.qtype
== kDNSType_SOA
)
6877 int qcount
= CountLabels(&q
.qname
);
6878 int scount
= CountLabels(m
->rec
.r
.resrec
.name
);
6879 if (qcount
- 1 > scount
)
6880 if (SameDomainName(SkipLeadingLabels(&q
.qname
, qcount
- scount
), m
->rec
.r
.resrec
.name
))
6881 repeat
= qcount
- 1 - scount
;
6884 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6887 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
6888 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
6889 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
6890 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
6891 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
6892 // so that we back off our polling rate and don't keep hitting the server continually.
6895 if (negttl
< neg
->resrec
.rroriginalttl
* 2)
6896 negttl
= neg
->resrec
.rroriginalttl
* 2;
6901 negttl
= GetEffectiveTTL(LLQType
, negttl
); // Add 25% grace period if necessary
6903 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
6906 debugf("Renewing negative TTL from %d to %d %s", neg
->resrec
.rroriginalttl
, negttl
, CRDisplayString(m
, neg
));
6907 RefreshCacheRecord(m
, neg
, negttl
);
6911 debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl
, name
->c
, DNSTypeName(q
.qtype
));
6912 MakeNegativeCacheRecord(m
, &m
->rec
.r
, name
, hash
, q
.qtype
, q
.qclass
, negttl
, mDNSInterface_Any
);
6913 CreateNewCacheEntry(m
, slot
, cg
);
6914 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6917 name
= (const domainname
*)(name
->c
+ 1 + name
->c
[0]);
6918 hash
= DomainNameHashValue(name
);
6919 slot
= HashSlot(name
);
6920 cg
= CacheGroupForName(m
, slot
, hash
, name
);
6928 mDNSlocal
void SPSRecordCallback(mDNS
*const m
, AuthRecord
*const ar
, mStatus result
)
6930 if (result
&& result
!= mStatus_MemFree
)
6931 LogInfo("SPS Callback %d %s", result
, ARDisplayString(m
, ar
));
6933 if (result
== mStatus_NameConflict
)
6935 char *ifname
= InterfaceNameForID(m
, ar
->resrec
.InterfaceID
);
6936 if (!ifname
) ifname
= "<NULL InterfaceID>";
6937 LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", ifname
, &ar
->WakeUp
.HMAC
, ARDisplayString(m
, ar
));
6938 SendWakeup(m
, ar
->resrec
.InterfaceID
, &ar
->WakeUp
.IMAC
, &ar
->WakeUp
.password
);
6940 else if (result
== mStatus_MemFree
)
6943 mDNSPlatformMemFree(ar
);
6947 mDNSlocal
void mDNSCoreReceiveUpdate(mDNS
*const m
,
6948 const DNSMessage
*const msg
, const mDNSu8
*end
,
6949 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
6950 const mDNSInterfaceID InterfaceID
)
6954 mDNSu8
*p
= m
->omsg
.data
;
6955 OwnerOptData owner
= zeroOwner
; // Need to zero this, so we'll know if this Update packet was missing its Owner option
6956 mDNSu32 updatelease
= 0;
6959 LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6960 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6961 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
6962 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
6963 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
6964 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
6965 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
6967 if (!InterfaceID
|| !m
->SPSSocket
|| !mDNSSameIPPort(dstport
, m
->SPSSocket
->port
)) return;
6969 if (mDNS_PacketLoggingEnabled
)
6970 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
6972 ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
+ DNSOpt_OwnerData_ID_Space
);
6975 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
6976 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
6979 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
6980 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
6982 if (o
->opt
== kDNSOpt_Lease
) updatelease
= o
->u
.updatelease
;
6983 else if (o
->opt
== kDNSOpt_Owner
&& o
->u
.owner
.vers
== 0) owner
= o
->u
.owner
;
6986 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
6989 InitializeDNSMessage(&m
->omsg
.h
, msg
->h
.id
, UpdateRespFlags
);
6991 if (!updatelease
|| !owner
.HMAC
.l
[0])
6993 static int msgs
= 0;
6997 LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr
, mDNSVal16(srcport
),
6998 !updatelease
? " No lease" : "", !owner
.HMAC
.l
[0] ? " No owner" : "");
7000 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_FormErr
;
7002 else if (m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
> MAX_PROXY_RECORDS
)
7004 static int msgs
= 0;
7008 LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr
, mDNSVal16(srcport
),
7009 m
->ProxyRecords
, msg
->h
.mDNS_numUpdates
, m
->ProxyRecords
+ msg
->h
.mDNS_numUpdates
, MAX_PROXY_RECORDS
);
7011 m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
;
7015 LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner
.HMAC
, &owner
.IMAC
, &owner
.password
, owner
.seq
);
7017 if (updatelease
> 24 * 60 * 60)
7018 updatelease
= 24 * 60 * 60;
7020 if (updatelease
> 0x40000000UL
/ mDNSPlatformOneSecond
)
7021 updatelease
= 0x40000000UL
/ mDNSPlatformOneSecond
;
7023 ptr
= LocateAuthorities(msg
, end
);
7024 for (i
= 0; i
< msg
->h
.mDNS_numUpdates
&& ptr
&& ptr
< end
; i
++)
7026 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
7029 mDNSu16 RDLengthMem
= GetRDLengthMem(&m
->rec
.r
.resrec
);
7030 AuthRecord
*ar
= mDNSPlatformMemAllocate(sizeof(AuthRecord
) - sizeof(RDataBody
) + RDLengthMem
);
7031 if (!ar
) { m
->omsg
.h
.flags
.b
[1] |= kDNSFlag1_RC_Refused
; break; }
7034 mDNSu8 RecordType
= m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
? kDNSRecordTypeUnique
: kDNSRecordTypeShared
;
7035 m
->rec
.r
.resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
;
7036 mDNS_SetupResourceRecord(ar
, mDNSNULL
, InterfaceID
, m
->rec
.r
.resrec
.rrtype
, m
->rec
.r
.resrec
.rroriginalttl
, RecordType
, SPSRecordCallback
, ar
);
7037 AssignDomainName(&ar
->namestorage
, m
->rec
.r
.resrec
.name
);
7038 ar
->resrec
.rdlength
= GetRDLength(&m
->rec
.r
.resrec
, mDNSfalse
);
7039 ar
->resrec
.rdata
->MaxRDLength
= RDLengthMem
;
7040 mDNSPlatformMemCopy(ar
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdata
->u
.data
, RDLengthMem
);
7042 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_PTR
)
7044 mDNSs32 t
= ReverseMapDomainType(m
->rec
.r
.resrec
.name
);
7045 if (t
== mDNSAddrType_IPv4
) GetIPv4FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
7046 else if (t
== mDNSAddrType_IPv6
) GetIPv6FromName(&ar
->AddressProxy
, m
->rec
.r
.resrec
.name
);
7047 debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t
, ar
->AddressProxy
.type
, &ar
->AddressProxy
, ARDisplayString(m
, ar
));
7048 if (ar
->AddressProxy
.type
) SetSPSProxyListChanged(InterfaceID
);
7050 ar
->TimeRcvd
= m
->timenow
;
7051 ar
->TimeExpire
= m
->timenow
+ updatelease
* mDNSPlatformOneSecond
;
7052 if (m
->NextScheduledSPS
- ar
->TimeExpire
> 0)
7053 m
->NextScheduledSPS
= ar
->TimeExpire
;
7054 mDNS_Register_internal(m
, ar
);
7055 // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
7056 if (ar
->resrec
.rrtype
== kDNSType_AAAA
) ar
->resrec
.rroriginalttl
= 0;
7058 LogSPS("SPS Registered %4d %X %s", m
->ProxyRecords
, RecordType
, ARDisplayString(m
,ar
));
7061 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
7064 if (m
->omsg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)
7066 LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr
, mDNSVal16(srcport
));
7067 ClearProxyRecords(m
, &owner
, m
->DuplicateRecords
);
7068 ClearProxyRecords(m
, &owner
, m
->ResourceRecords
);
7072 mDNS_SetupResourceRecord(&opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
7073 opt
.resrec
.rrclass
= NormalMaxDNSMessageData
;
7074 opt
.resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
7075 opt
.resrec
.rdestimate
= sizeof(rdataOPT
);
7076 opt
.resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_Lease
;
7077 opt
.resrec
.rdata
->u
.opt
[0].u
.updatelease
= updatelease
;
7078 p
= PutResourceRecordTTLWithLimit(&m
->omsg
, p
, &m
->omsg
.h
.numAdditionals
, &opt
.resrec
, opt
.resrec
.rroriginalttl
, m
->omsg
.data
+ AbsoluteMaxDNSMessageData
);
7082 if (p
) mDNSSendDNSMessage(m
, &m
->omsg
, p
, InterfaceID
, m
->SPSSocket
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
7085 mDNSlocal
void mDNSCoreReceiveUpdateR(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSInterfaceID InterfaceID
)
7090 mDNSu32 updatelease
= 60 * 60; // If SPS fails to indicate lease time, assume one hour
7091 const mDNSu8
*ptr
= LocateOptRR(msg
, end
, DNSOpt_LeaseData_Space
);
7094 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &m
->rec
);
7095 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
)
7098 const rdataOPT
*const e
= (const rdataOPT
*)&m
->rec
.r
.resrec
.rdata
->u
.data
[m
->rec
.r
.resrec
.rdlength
];
7099 for (o
= &m
->rec
.r
.resrec
.rdata
->u
.opt
[0]; o
< e
; o
++)
7100 if (o
->opt
== kDNSOpt_Lease
)
7102 updatelease
= o
->u
.updatelease
;
7103 LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease
);
7106 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
7109 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
7110 if (rr
->resrec
.InterfaceID
== InterfaceID
|| (!rr
->resrec
.InterfaceID
&& (rr
->ForceMCast
|| IsLocalDomain(rr
->resrec
.name
))))
7111 if (mDNSSameOpaque16(rr
->updateid
, msg
->h
.id
))
7113 rr
->updateid
= zeroID
;
7114 rr
->expire
= NonZeroTime(m
->timenow
+ updatelease
* mDNSPlatformOneSecond
);
7115 LogSPS("Sleep Proxy registered record %5d %s", updatelease
, ARDisplayString(m
,rr
));
7119 // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
7120 // may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
7121 if (m
->SleepLimit
) m
->NextScheduledSPRetry
= m
->timenow
;
7124 mDNSexport
void MakeNegativeCacheRecord(mDNS
*const m
, CacheRecord
*const cr
,
7125 const domainname
*const name
, const mDNSu32 namehash
, const mDNSu16 rrtype
, const mDNSu16 rrclass
, mDNSu32 ttl_seconds
, mDNSInterfaceID InterfaceID
)
7127 if (cr
== &m
->rec
.r
&& m
->rec
.r
.resrec
.RecordType
)
7129 LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m
, &m
->rec
.r
));
7135 // Create empty resource record
7136 cr
->resrec
.RecordType
= kDNSRecordTypePacketNegative
;
7137 cr
->resrec
.InterfaceID
= InterfaceID
;
7138 cr
->resrec
.name
= name
; // Will be updated to point to cg->name when we call CreateNewCacheEntry
7139 cr
->resrec
.rrtype
= rrtype
;
7140 cr
->resrec
.rrclass
= rrclass
;
7141 cr
->resrec
.rroriginalttl
= ttl_seconds
;
7142 cr
->resrec
.rdlength
= 0;
7143 cr
->resrec
.rdestimate
= 0;
7144 cr
->resrec
.namehash
= namehash
;
7145 cr
->resrec
.rdatahash
= 0;
7146 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
7147 cr
->resrec
.rdata
->MaxRDLength
= 0;
7149 cr
->NextInKAList
= mDNSNULL
;
7150 cr
->TimeRcvd
= m
->timenow
;
7151 cr
->DelayDelivery
= 0;
7152 cr
->NextRequiredQuery
= m
->timenow
;
7153 cr
->LastUsed
= m
->timenow
;
7154 cr
->CRActiveQuestion
= mDNSNULL
;
7155 cr
->UnansweredQueries
= 0;
7156 cr
->LastUnansweredTime
= 0;
7157 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
7158 cr
->MPUnansweredQ
= 0;
7159 cr
->MPLastUnansweredQT
= 0;
7160 cr
->MPUnansweredKA
= 0;
7161 cr
->MPExpectingKA
= mDNSfalse
;
7163 cr
->NextInCFList
= mDNSNULL
;
7166 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, void *const pkt
, const mDNSu8
*const end
,
7167 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
,
7168 const mDNSInterfaceID InterfaceID
)
7170 mDNSInterfaceID ifid
= InterfaceID
;
7171 DNSMessage
*msg
= (DNSMessage
*)pkt
;
7172 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
7173 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
7174 const mDNSu8 UpdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_Update
;
7175 const mDNSu8 UpdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
7177 mDNSu8
*ptr
= mDNSNULL
;
7178 mDNSBool TLS
= (dstaddr
== (mDNSAddr
*)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
7179 if (TLS
) dstaddr
= mDNSNULL
;
7181 #ifndef UNICAST_DISABLED
7182 if (mDNSSameAddress(srcaddr
, &m
->Router
))
7184 #ifdef _LEGACY_NAT_TRAVERSAL_
7185 if (mDNSSameIPPort(srcport
, SSDPPort
) || (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)))
7188 LNT_ConfigureRouterInfo(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7193 if (mDNSSameIPPort(srcport
, NATPMPPort
))
7196 uDNS_ReceiveNATPMPPacket(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
7201 #ifdef _LEGACY_NAT_TRAVERSAL_
7202 else if (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr
, mDNSVal16(srcport
)); return; }
7206 if ((unsigned)(end
- (mDNSu8
*)pkt
) < sizeof(DNSMessageHeader
))
7208 LogMsg("DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
- (mDNSu8
*)pkt
);
7211 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
7212 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
7213 ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
7214 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
7215 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
7216 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
7217 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
7219 if (!m
) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
7221 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
7222 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
7223 if (srcaddr
&& !mDNSAddressIsValid(srcaddr
)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr
); return; }
7227 #ifndef UNICAST_DISABLED
7228 if (!dstaddr
|| (!mDNSAddressIsAllDNSLinkGroup(dstaddr
) && (QR_OP
== StdR
|| QR_OP
== UpdR
)))
7229 if (!mDNSOpaque16IsZero(msg
->h
.id
)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
7231 ifid
= mDNSInterface_Any
;
7232 if (mDNS_PacketLoggingEnabled
)
7233 DumpPacket(m
, mStatus_NoError
, mDNSfalse
, TLS
? "TLS" : !dstaddr
? "TCP" : "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
7234 uDNS_ReceiveMsg(m
, msg
, end
, srcaddr
, srcport
);
7235 // Note: mDNSCore also needs to get access to received unicast responses
7238 if (QR_OP
== StdQ
) mDNSCoreReceiveQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7239 else if (QR_OP
== StdR
) mDNSCoreReceiveResponse(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
7240 else if (QR_OP
== UpdQ
) mDNSCoreReceiveUpdate (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
);
7241 else if (QR_OP
== UpdR
) mDNSCoreReceiveUpdateR (m
, msg
, end
, InterfaceID
);
7244 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
7245 msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1], srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), end
- (mDNSu8
*)pkt
, InterfaceID
);
7246 if (mDNS_LoggingEnabled
)
7249 while (i
<end
- (mDNSu8
*)pkt
)
7252 char *p
= buffer
+ mDNS_snprintf(buffer
, sizeof(buffer
), "%04X", i
);
7253 do if (i
<end
- (mDNSu8
*)pkt
) p
+= mDNS_snprintf(p
, sizeof(buffer
), " %02X", ((mDNSu8
*)pkt
)[i
]); while (++i
& 15);
7254 LogInfo("%s", buffer
);
7258 // Packet reception often causes a change to the task list:
7259 // 1. Inbound queries can cause us to need to send responses
7260 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
7261 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
7262 // 4. Response packets that answer questions may cause our client to issue new questions
7266 // ***************************************************************************
7267 #if COMPILER_LIKES_PRAGMA_MARK
7269 #pragma mark - Searcher Functions
7272 // Targets are considered the same if both queries are untargeted, or
7273 // if both are targeted to the same address+port
7274 // (If Target address is zero, TargetPort is undefined)
7275 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
7276 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
7278 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
7279 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
7280 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
7281 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
7282 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
7284 // If IsLLQ(Q) is true, it means the question is both:
7285 // (a) long-lived and
7286 // (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
7287 // for multicast questions, we don't want to treat LongLived as anything special
7288 #define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
7290 mDNSlocal DNSQuestion
*FindDuplicateQuestion(const mDNS
*const m
, const DNSQuestion
*const question
)
7293 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
7294 // This prevents circular references, where two questions are each marked as a duplicate of the other.
7295 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
7296 // further in the list.
7297 for (q
= m
->Questions
; q
&& q
!= question
; q
=q
->next
) // Scan our list for another question
7298 if (q
->InterfaceID
== question
->InterfaceID
&& // with the same InterfaceID,
7299 SameQTarget(q
, question
) && // and same unicast/multicast target settings
7300 q
->qtype
== question
->qtype
&& // type,
7301 q
->qclass
== question
->qclass
&& // class,
7302 IsLLQ(q
) == IsLLQ(question
) && // and long-lived status matches
7303 (!q
->AuthInfo
|| question
->AuthInfo
) && // to avoid deadlock, don't make public query dup of a private one
7304 q
->qnamehash
== question
->qnamehash
&&
7305 SameDomainName(&q
->qname
, &question
->qname
)) // and name
7310 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
7311 mDNSlocal
void UpdateQuestionDuplicates(mDNS
*const m
, DNSQuestion
*const question
)
7314 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7315 if (q
->DuplicateOf
== question
) // To see if any questions were referencing this as their duplicate
7316 if ((q
->DuplicateOf
= FindDuplicateQuestion(m
, q
)) == mDNSNULL
)
7318 // If q used to be a duplicate, but now is not,
7319 // then inherit the state from the question that's going away
7320 q
->LastQTime
= question
->LastQTime
;
7321 q
->ThisQInterval
= question
->ThisQInterval
;
7322 q
->ExpectUnicastResp
= question
->ExpectUnicastResp
;
7323 q
->LastAnswerPktNum
= question
->LastAnswerPktNum
;
7324 q
->RecentAnswerPkts
= question
->RecentAnswerPkts
;
7325 q
->RequestUnicast
= question
->RequestUnicast
;
7326 q
->LastQTxTime
= question
->LastQTxTime
;
7327 q
->CNAMEReferrals
= question
->CNAMEReferrals
;
7328 q
->nta
= question
->nta
;
7329 q
->servAddr
= question
->servAddr
;
7330 q
->servPort
= question
->servPort
;
7331 q
->qDNSServer
= question
->qDNSServer
;
7332 q
->unansweredQueries
= question
->unansweredQueries
;
7334 q
->TargetQID
= question
->TargetQID
;
7335 q
->LocalSocket
= question
->LocalSocket
;
7337 q
->state
= question
->state
;
7338 // q->tcp = question->tcp;
7339 q
->ReqLease
= question
->ReqLease
;
7340 q
->expire
= question
->expire
;
7341 q
->ntries
= question
->ntries
;
7342 q
->id
= question
->id
;
7344 question
->LocalSocket
= mDNSNULL
;
7345 question
->nta
= mDNSNULL
; // If we've got a GetZoneData in progress, transfer it to the newly active question
7346 // question->tcp = mDNSNULL;
7349 debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7353 LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7354 q
->nta
->ZoneDataContext
= q
;
7357 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
7358 if (question
->tcp
) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
7360 if (question
->state
== LLQ_Established
)
7362 LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
7363 question
->state
= 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
7366 SetNextQueryTime(m
,q
);
7370 mDNSinline mDNSs32
PenaltyTimeForServer(mDNS
*m
, DNSServer
*server
)
7373 if (server
->penaltyTime
!= 0)
7375 ptime
= server
->penaltyTime
- m
->timenow
;
7378 // This should always be a positive value between 0 and DNSSERVER_PENALTY_TIME
7379 // If it does not get reset in ResetDNSServerPenalties for some reason, we do it
7381 LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty", ptime
, server
->penaltyTime
, m
->timenow
);
7382 server
->penaltyTime
= 0;
7389 // Return the next server to "prev" if it is a match and unpenalized
7390 mDNSlocal DNSServer
*GetNextUnPenalizedServer(mDNS
*m
, DNSServer
*prev
)
7392 int curmatchlen
= -1;
7393 DNSServer
*curr
= m
->DNSServers
;
7395 if (prev
== mDNSNULL
) return mDNSNULL
;
7397 while (curr
!= mDNSNULL
&& curr
!= prev
)
7400 if (curr
== mDNSNULL
)
7404 // We need to set the curmatchlen as though we are walking the list
7405 // from the beginning. Otherwise, we may not pick the best match.
7406 // For example, if we are looking up xxx.com, and we used the "xxx.com"
7407 // entry the previous time and the next one is "com", we should not pick
7409 curmatchlen
= CountLabels(&curr
->domain
);
7411 while (curr
!= mDNSNULL
)
7413 int scount
= CountLabels(&curr
->domain
);
7415 // Should not be delete because it is marked temporarily for cleaning up
7416 // entries during configuration change and we pass NULL as the last argument
7417 // to GetServerForName
7418 if (curr
->flags
& DNSServer_FlagDelete
)
7420 LogInfo("GetServerForName: DNS Server is marked delete, cannot happen");
7426 debugf("GetNextUnPenalizedServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d", &curr
->addr
, curr
->domain
.c
, curr
->penaltyTime
, PenaltyTimeForServer(m
,curr
));
7428 // Note the "==" in comparing scount and curmatchlen. When we picked a match
7429 // for the question the first time, we already made sure that prev is the best match.
7430 // Any other match is as good if we can find another entry with same number of
7431 // labels. There can't be better matches that have more labels, because
7432 // we would have picked that in the first place. Also we don't care what the
7433 // name in the question is as we picked the best server for the question first
7434 // time and the domain name is in prev now
7436 if ((curr
->penaltyTime
== 0) && (scount
== curmatchlen
) && SameDomainName(&prev
->domain
, &curr
->domain
))
7444 //Checks to see whether the newname is a better match for the name, given the best one we have
7445 //seen so far (given in bestcount).
7446 //Returns -1 if the newname is not a better match
7447 //Returns 0 if the newname is the same as the old match
7448 //Returns 1 if the newname is a better match
7449 mDNSlocal
int BetterMatchForName(const domainname
*name
, int namecount
, const domainname
*newname
, int newcount
,
7452 // If the name contains fewer labels than the new server's domain or the new name
7453 // contains fewer labels than the current best, then it can't possibly be a better match
7454 if (namecount
< newcount
|| newcount
< bestcount
) return -1;
7456 // If there is no match, return -1 and the caller will skip this newname for
7459 // If we find a match and the number of labels is the same as bestcount, then
7460 // we return 0 so that the caller can do additional logic to pick one of
7461 // the best based on some other factors e.g., penaltyTime
7463 // If we find a match and the number of labels is more than bestcount, then we
7464 // return 1 so that the caller can pick this over the old one.
7466 // NOTE: newcount can either be equal or greater than bestcount beause of the
7469 if (SameDomainName(SkipLeadingLabels(name
, namecount
- newcount
), newname
))
7470 return bestcount
== newcount
? 0 : 1;
7475 // Get the Best server that matches a name. If you find penalized servers, look for the one
7476 // that will come out of the penalty box soon
7477 mDNSlocal DNSServer
*GetAnyBestServer(mDNS
*m
, const domainname
*name
)
7479 DNSServer
*curmatch
= mDNSNULL
;
7480 int bestmatchlen
= -1, namecount
= name
? CountLabels(name
) : 0;
7482 mDNSs32 bestPenaltyTime
;
7486 bestPenaltyTime
= DNSSERVER_PENALTY_TIME
+ 1;
7487 for (curr
= m
->DNSServers
; curr
; curr
= curr
->next
)
7489 int currcount
= CountLabels(&curr
->domain
);
7490 mDNSs32 currPenaltyTime
= PenaltyTimeForServer(m
, curr
);
7492 debugf("GetAnyBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d",
7493 &curr
->addr
, curr
->domain
.c
, curr
->penaltyTime
, currPenaltyTime
);
7496 // If there are multiple best servers for a given question, we will pick the first one
7497 // if none of them are penalized. If some of them are penalized in that list, we pick
7498 // the least penalized one. BetterMatchForName walks through all best matches and
7499 // "currPenaltyTime < bestPenaltyTime" check lets us either pick the first best server
7500 // in the list when there are no penalized servers and least one among them
7501 // when there are some penalized servers
7503 if (!(curr
->flags
& DNSServer_FlagDelete
))
7506 bettermatch
= BetterMatchForName(name
, namecount
, &curr
->domain
, currcount
, bestmatchlen
);
7508 // If we found a better match (bettermatch == 1) then we don't need to
7509 // compare penalty times. But if we found an equal match, then we compare
7510 // the penalty times to pick a better match
7512 if ((bettermatch
== 1) || ((bettermatch
== 0) && currPenaltyTime
< bestPenaltyTime
))
7513 { curmatch
= curr
; bestmatchlen
= currcount
; bestPenaltyTime
= currPenaltyTime
;}
7520 // Look up a DNS Server, matching by name in split-dns configurations.
7521 mDNSexport DNSServer
*GetServerForName(mDNS
*m
, const domainname
*name
, DNSServer
*prev
)
7523 DNSServer
*curmatch
= mDNSNULL
;
7525 // prev is the previous DNS server used by some question
7526 if (prev
!= mDNSNULL
)
7528 curmatch
= GetNextUnPenalizedServer(m
, prev
);
7529 if (curmatch
!= mDNSNULL
)
7531 LogInfo("GetServerForName: Good DNS server %#a:%d (Penalty Time Left %d) found", &curmatch
->addr
,
7532 mDNSVal16(curmatch
->port
), (curmatch
->penaltyTime
? (curmatch
->penaltyTime
- m
->timenow
) : 0));
7537 // We are here for many reasons.
7539 // 1. We are looking up the DNS server first time for this question
7540 // 2. We reached the end of list looking for unpenalized servers
7542 // In the case of (1) we want to find the best match for the name. If nothing is penalized,
7543 // we want the first one in the list. If some are penalized, we want the one that will get
7544 // out of penalty box sooner
7546 // In the case of (2) we want to select the first server that matches the name if StrictUnicastOrdering
7547 // is TRUE. As penaltyTime is zero for all of them in that case, we automatically achieve that below.
7548 // If StrictUnicastOrdering is FALSE, we want to pick the least penalized server in the list
7550 curmatch
= GetAnyBestServer(m
, name
);
7552 if (curmatch
!= mDNSNULL
)
7553 LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) found", &curmatch
->addr
,
7554 mDNSVal16(curmatch
->port
), (curmatch
->penaltyTime
? (curmatch
->penaltyTime
- m
->timenow
) : 0));
7556 LogInfo("GetServerForName: no DNS server found");
7561 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
7562 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
7564 // Called in normal client context (lock not held)
7565 mDNSlocal
void LLQNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
7570 LogInfo("LLQNATCallback external address:port %.4a:%u", &n
->ExternalAddress
, mDNSVal16(n
->ExternalPort
));
7571 for (q
= m
->Questions
; q
; q
=q
->next
)
7572 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
)
7573 startLLQHandshake(m
, q
); // If ExternalPort is zero, will do StartLLQPolling instead
7574 #if APPLE_OSX_mDNSResponder
7575 UpdateAutoTunnelDomainStatuses(m
);
7580 mDNSexport mStatus
mDNS_StartQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7582 if (question
->Target
.type
&& !ValidQuestionTarget(question
))
7584 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
7585 question
->Target
.type
, mDNSVal16(question
->TargetPort
));
7586 question
->Target
.type
= mDNSAddrType_None
;
7589 if (!question
->Target
.type
) question
->TargetPort
= zeroIPPort
; // If question->Target specified clear TargetPort
7591 question
->TargetQID
=
7592 #ifndef UNICAST_DISABLED
7593 (question
->Target
.type
|| (question
->InterfaceID
== mDNSInterface_Unicast
) ||
7594 (question
->InterfaceID
!= mDNSInterface_LocalOnly
&& !question
->ForceMCast
&& !IsLocalDomain(&question
->qname
)))
7595 ? mDNS_NewMessageID(m
) :
7596 #endif // UNICAST_DISABLED
7599 debugf("mDNS_StartQuery: %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7601 if (m
->rrcache_size
== 0) // Can't do queries if we have no cache space allocated
7602 return(mStatus_NoCache
);
7608 if (!ValidateDomainName(&question
->qname
))
7610 LogMsg("Attempt to start query with invalid qname %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7611 return(mStatus_Invalid
);
7614 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
7616 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) q
= &m
->LocalOnlyQuestions
;
7617 while (*q
&& *q
!= question
) q
=&(*q
)->next
;
7621 LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
7622 question
->qname
.c
, DNSTypeName(question
->qtype
), question
);
7623 return(mStatus_AlreadyRegistered
);
7628 // If this question is referencing a specific interface, verify it exists
7629 if (question
->InterfaceID
&& question
->InterfaceID
!= mDNSInterface_LocalOnly
&& question
->InterfaceID
!= mDNSInterface_Unicast
)
7631 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, question
->InterfaceID
);
7633 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
7634 question
->InterfaceID
, question
->qname
.c
, DNSTypeName(question
->qtype
));
7637 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
7638 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
7639 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
7640 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
7641 // that to go out immediately.
7642 question
->next
= mDNSNULL
;
7643 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // MUST do this before FindDuplicateQuestion()
7644 question
->DelayAnswering
= CheckForSoonToExpireRecords(m
, &question
->qname
, question
->qnamehash
, HashSlot(&question
->qname
));
7645 question
->LastQTime
= m
->timenow
;
7646 question
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
7647 question
->ExpectUnicastResp
= 0;
7648 question
->LastAnswerPktNum
= m
->PktNum
;
7649 question
->RecentAnswerPkts
= 0;
7650 question
->CurrentAnswers
= 0;
7651 question
->LargeAnswers
= 0;
7652 question
->UniqueAnswers
= 0;
7653 question
->FlappingInterface1
= mDNSNULL
;
7654 question
->FlappingInterface2
= mDNSNULL
;
7655 question
->AuthInfo
= GetAuthInfoForQuestion(m
, question
); // Must do this before calling FindDuplicateQuestion()
7656 question
->DuplicateOf
= FindDuplicateQuestion(m
, question
);
7657 question
->NextInDQList
= mDNSNULL
;
7658 question
->SendQNow
= mDNSNULL
;
7659 question
->SendOnAll
= mDNSfalse
;
7660 question
->RequestUnicast
= 0;
7661 question
->LastQTxTime
= m
->timenow
;
7662 question
->CNAMEReferrals
= 0;
7664 // We'll create our question->LocalSocket on demand, if needed.
7665 // We won't need one for duplicate questions, or from questions answered immediately out of the cache.
7666 // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
7667 // NAT mapping for receiving inbound add/remove events.
7668 question
->LocalSocket
= mDNSNULL
;
7669 question
->qDNSServer
= mDNSNULL
;
7670 question
->unansweredQueries
= 0;
7671 question
->nta
= mDNSNULL
;
7672 question
->servAddr
= zeroAddr
;
7673 question
->servPort
= zeroIPPort
;
7674 question
->tcp
= mDNSNULL
;
7675 question
->NoAnswer
= NoAnswer_Normal
;
7677 question
->state
= LLQ_InitialRequest
;
7678 question
->ReqLease
= 0;
7679 question
->expire
= 0;
7680 question
->ntries
= 0;
7681 question
->id
= zeroOpaque64
;
7683 if (question
->DuplicateOf
) question
->AuthInfo
= question
->DuplicateOf
->AuthInfo
;
7685 for (i
=0; i
<DupSuppressInfoSize
; i
++)
7686 question
->DupSuppress
[i
].InterfaceID
= mDNSNULL
;
7688 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
7689 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->InterfaceID
, m
->timenow
,
7690 question
->LastQTime
+ question
->ThisQInterval
- m
->timenow
,
7691 question
->DelayAnswering
? question
->DelayAnswering
- m
->timenow
: 0,
7692 question
, question
->DuplicateOf
? "duplicate of" : "not duplicate", question
->DuplicateOf
);
7694 if (question
->InterfaceID
== mDNSInterface_LocalOnly
)
7696 if (!m
->NewLocalOnlyQuestions
) m
->NewLocalOnlyQuestions
= question
;
7700 if (!m
->NewQuestions
) m
->NewQuestions
= question
;
7702 // If the question's id is non-zero, then it's Wide Area
7703 // MUST NOT do this Wide Area setup until near the end of
7704 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
7705 // NS, etc.) and if we haven't finished setting up our own question and setting
7706 // m->NewQuestions if necessary then we could end up recursively re-entering
7707 // this routine with the question list data structures in an inconsistent state.
7708 if (!mDNSOpaque16IsZero(question
->TargetQID
))
7710 question
->qDNSServer
= GetServerForName(m
, &question
->qname
, mDNSNULL
);
7711 ActivateUnicastQuery(m
, question
, mDNSfalse
);
7713 // If long-lived query, and we don't have our NAT mapping active, start it now
7714 if (question
->LongLived
&& !m
->LLQNAT
.clientContext
)
7716 m
->LLQNAT
.Protocol
= NATOp_MapUDP
;
7717 m
->LLQNAT
.IntPort
= m
->UnicastPort4
;
7718 m
->LLQNAT
.RequestedPort
= m
->UnicastPort4
;
7719 m
->LLQNAT
.clientCallback
= LLQNATCallback
;
7720 m
->LLQNAT
.clientContext
= (void*)1; // Means LLQ NAT Traversal is active
7721 mDNS_StartNATOperation_internal(m
, &m
->LLQNAT
);
7724 #if APPLE_OSX_mDNSResponder
7725 if (question
->LongLived
)
7726 UpdateAutoTunnelDomainStatuses(m
);
7730 SetNextQueryTime(m
,question
);
7733 return(mStatus_NoError
);
7737 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
7738 mDNSexport
void CancelGetZoneData(mDNS
*const m
, ZoneData
*nta
)
7740 debugf("CancelGetZoneData %##s (%s)", nta
->question
.qname
.c
, DNSTypeName(nta
->question
.qtype
));
7741 mDNS_StopQuery_internal(m
, &nta
->question
);
7742 mDNSPlatformMemFree(nta
);
7745 mDNSexport mStatus
mDNS_StopQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
7747 const mDNSu32 slot
= HashSlot(&question
->qname
);
7748 CacheGroup
*cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7750 DNSQuestion
**qp
= &m
->Questions
;
7752 //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7754 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) qp
= &m
->LocalOnlyQuestions
;
7755 while (*qp
&& *qp
!= question
) qp
=&(*qp
)->next
;
7756 if (*qp
) *qp
= (*qp
)->next
;
7760 if (question
->ThisQInterval
>= 0) // Only log error message if the query was supposed to be active
7762 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
7763 question
->qname
.c
, DNSTypeName(question
->qtype
));
7767 return(mStatus_BadReferenceErr
);
7770 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
7771 UpdateQuestionDuplicates(m
, question
);
7772 // But don't trash ThisQInterval until afterwards.
7773 question
->ThisQInterval
= -1;
7775 // If there are any cache records referencing this as their active question, then see if there is any
7776 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
7777 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7779 if (rr
->CRActiveQuestion
== question
)
7782 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
7783 if (ActiveQuestion(q
) && ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
7785 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
7786 rr
->CRActiveQuestion
= q
; // Question used to be active; new value may or may not be null
7787 if (!q
) m
->rrcache_active
--; // If no longer active, decrement rrcache_active count
7791 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
7792 // bump its pointer forward one question.
7793 if (m
->CurrentQuestion
== question
)
7795 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
7796 question
->qname
.c
, DNSTypeName(question
->qtype
));
7797 m
->CurrentQuestion
= question
->next
;
7800 if (m
->NewQuestions
== question
)
7802 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
7803 question
->qname
.c
, DNSTypeName(question
->qtype
));
7804 m
->NewQuestions
= question
->next
;
7807 if (m
->NewLocalOnlyQuestions
== question
) m
->NewLocalOnlyQuestions
= question
->next
;
7809 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
7810 question
->next
= mDNSNULL
;
7812 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
7814 // And finally, cancel any associated GetZoneData operation that's still running.
7815 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
7816 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
7817 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
7818 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
7819 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
7820 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
7821 if (question
->LocalSocket
) { mDNSPlatformUDPClose(question
->LocalSocket
); question
->LocalSocket
= mDNSNULL
; }
7822 if (!mDNSOpaque16IsZero(question
->TargetQID
) && question
->LongLived
)
7824 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
7826 for (q
= m
->Questions
; q
; q
=q
->next
)
7827 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
) break;
7830 if (!m
->LLQNAT
.clientContext
) // Should never happen, but just in case...
7831 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
7834 LogInfo("Stopping LLQNAT");
7835 mDNS_StopNATOperation_internal(m
, &m
->LLQNAT
);
7836 m
->LLQNAT
.clientContext
= mDNSNULL
; // Means LLQ NAT Traversal not running
7840 // If necessary, tell server it can delete this LLQ state
7841 if (question
->state
== LLQ_Established
)
7843 question
->ReqLease
= 0;
7844 sendLLQRefresh(m
, question
);
7845 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
7846 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
7847 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
7848 // we let that run out its natural course and complete asynchronously.
7851 question
->tcp
->question
= mDNSNULL
;
7852 question
->tcp
= mDNSNULL
;
7855 #if APPLE_OSX_mDNSResponder
7856 UpdateAutoTunnelDomainStatuses(m
);
7860 return(mStatus_NoError
);
7863 mDNSexport mStatus
mDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
7867 status
= mDNS_StartQuery_internal(m
, question
);
7872 mDNSexport mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
7876 status
= mDNS_StopQuery_internal(m
, question
);
7881 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
7882 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
7883 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
7884 // specifically to catch and report if the client callback does try to make API calls
7885 mDNSexport mStatus
mDNS_StopQueryWithRemoves(mDNS
*const m
, DNSQuestion
*const question
)
7891 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
7892 for (qq
= m
->NewQuestions
; qq
; qq
=qq
->next
) if (qq
== question
) break;
7894 status
= mDNS_StopQuery_internal(m
, question
);
7895 if (status
== mStatus_NoError
&& !qq
)
7897 const CacheRecord
*rr
;
7898 const mDNSu32 slot
= HashSlot(&question
->qname
);
7899 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
7900 LogInfo("Generating terminal removes for %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
7901 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
7902 if (rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& SameNameRecordAnswersQuestion(&rr
->resrec
, question
))
7904 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
7905 if (question
->QuestionCallback
)
7906 question
->QuestionCallback(m
, question
, &rr
->resrec
, mDNSfalse
);
7913 mDNSexport mStatus
mDNS_Reconfirm(mDNS
*const m
, CacheRecord
*const cr
)
7917 status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7918 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7923 mDNSexport mStatus
mDNS_ReconfirmByValue(mDNS
*const m
, ResourceRecord
*const rr
)
7925 mStatus status
= mStatus_BadReferenceErr
;
7928 cr
= FindIdenticalRecordInCache(m
, rr
);
7929 debugf("mDNS_ReconfirmByValue: %p %s", cr
, RRDisplayString(m
, rr
));
7930 if (cr
) status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7931 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
7936 mDNSlocal mStatus
mDNS_StartBrowse_internal(mDNS
*const m
, DNSQuestion
*const question
,
7937 const domainname
*const srv
, const domainname
*const domain
,
7938 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7940 question
->InterfaceID
= InterfaceID
;
7941 question
->Target
= zeroAddr
;
7942 question
->qtype
= kDNSType_PTR
;
7943 question
->qclass
= kDNSClass_IN
;
7944 question
->LongLived
= mDNSfalse
;
7945 question
->ExpectUnique
= mDNSfalse
;
7946 question
->ForceMCast
= ForceMCast
;
7947 question
->ReturnIntermed
= mDNSfalse
;
7948 question
->QuestionCallback
= Callback
;
7949 question
->QuestionContext
= Context
;
7950 if (!ConstructServiceName(&question
->qname
, mDNSNULL
, srv
, domain
)) return(mStatus_BadParamErr
);
7952 #ifndef UNICAST_DISABLED
7953 if (Question_uDNS(question
))
7955 question
->LongLived
= mDNStrue
;
7956 question
->ThisQInterval
= InitialQuestionInterval
;
7957 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
7959 #endif // UNICAST_DISABLED
7960 return(mDNS_StartQuery_internal(m
, question
));
7963 mDNSexport mStatus
mDNS_StartBrowse(mDNS
*const m
, DNSQuestion
*const question
,
7964 const domainname
*const srv
, const domainname
*const domain
,
7965 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
7969 status
= mDNS_StartBrowse_internal(m
, question
, srv
, domain
, InterfaceID
, ForceMCast
, Callback
, Context
);
7974 mDNSlocal mDNSBool
MachineHasActiveIPv6(mDNS
*const m
)
7976 NetworkInterfaceInfo
*intf
;
7977 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
7978 if (intf
->ip
.type
== mDNSAddrType_IPv6
) return(mDNStrue
);
7982 mDNSlocal
void FoundServiceInfoSRV(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
7984 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
7985 mDNSBool PortChanged
= !mDNSSameIPPort(query
->info
->port
, answer
->rdata
->u
.srv
.port
);
7986 if (!AddRecord
) return;
7987 if (answer
->rrtype
!= kDNSType_SRV
) return;
7989 query
->info
->port
= answer
->rdata
->u
.srv
.port
;
7991 // If this is our first answer, then set the GotSRV flag and start the address query
7994 query
->GotSRV
= mDNStrue
;
7995 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
7996 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
7997 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
7998 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
7999 mDNS_StartQuery(m
, &query
->qAv4
);
8000 // Only do the AAAA query if this machine actually has IPv6 active
8001 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
8003 // If this is not our first answer, only re-issue the address query if the target host name has changed
8004 else if ((query
->qAv4
.InterfaceID
!= query
->qSRV
.InterfaceID
&& query
->qAv4
.InterfaceID
!= answer
->InterfaceID
) ||
8005 !SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
))
8007 mDNS_StopQuery(m
, &query
->qAv4
);
8008 if (query
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &query
->qAv6
);
8009 if (SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
) && !PortChanged
)
8011 // If we get here, it means:
8012 // 1. This is not our first SRV answer
8013 // 2. The interface ID is different, but the target host and port are the same
8014 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
8015 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
8016 query
->qAv4
.InterfaceID
= query
->qSRV
.InterfaceID
; // Will be mDNSInterface_Any, or a specific interface
8017 query
->qAv6
.InterfaceID
= query
->qSRV
.InterfaceID
;
8021 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
8022 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
8023 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
8024 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
8026 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query
->qAv4
.qname
.c
, DNSTypeName(query
->qAv4
.qtype
));
8027 mDNS_StartQuery(m
, &query
->qAv4
);
8028 // Only do the AAAA query if this machine actually has IPv6 active
8029 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
8031 else if (query
->ServiceInfoQueryCallback
&& query
->GotADD
&& query
->GotTXT
&& PortChanged
)
8033 if (++query
->Answers
>= 100)
8034 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
8035 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.srv
.target
.c
,
8036 mDNSVal16(answer
->rdata
->u
.srv
.port
));
8037 query
->ServiceInfoQueryCallback(m
, query
);
8039 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
8040 // callback function is allowed to do anything, including deleting this query and freeing its memory.
8043 mDNSlocal
void FoundServiceInfoTXT(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
8045 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
8046 if (!AddRecord
) return;
8047 if (answer
->rrtype
!= kDNSType_TXT
) return;
8048 if (answer
->rdlength
> sizeof(query
->info
->TXTinfo
)) return;
8050 query
->GotTXT
= mDNStrue
;
8051 query
->info
->TXTlen
= answer
->rdlength
;
8052 query
->info
->TXTinfo
[0] = 0; // In case answer->rdlength is zero
8053 mDNSPlatformMemCopy(query
->info
->TXTinfo
, answer
->rdata
->u
.txt
.c
, answer
->rdlength
);
8055 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query
->info
->name
.c
, query
->GotADD
);
8057 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
8058 // callback function is allowed to do anything, including deleting this query and freeing its memory.
8059 if (query
->ServiceInfoQueryCallback
&& query
->GotADD
)
8061 if (++query
->Answers
>= 100)
8062 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
8063 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.txt
.c
);
8064 query
->ServiceInfoQueryCallback(m
, query
);
8068 mDNSlocal
void FoundServiceInfo(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
8070 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
8071 //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
8072 if (!AddRecord
) return;
8074 if (answer
->rrtype
== kDNSType_A
)
8076 query
->info
->ip
.type
= mDNSAddrType_IPv4
;
8077 query
->info
->ip
.ip
.v4
= answer
->rdata
->u
.ipv4
;
8079 else if (answer
->rrtype
== kDNSType_AAAA
)
8081 query
->info
->ip
.type
= mDNSAddrType_IPv6
;
8082 query
->info
->ip
.ip
.v6
= answer
->rdata
->u
.ipv6
;
8086 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer
->name
->c
, answer
->rrtype
, DNSTypeName(answer
->rrtype
));
8090 query
->GotADD
= mDNStrue
;
8091 query
->info
->InterfaceID
= answer
->InterfaceID
;
8093 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query
->info
->ip
.type
, query
->info
->name
.c
, query
->GotTXT
);
8095 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
8096 // callback function is allowed to do anything, including deleting this query and freeing its memory.
8097 if (query
->ServiceInfoQueryCallback
&& query
->GotTXT
)
8099 if (++query
->Answers
>= 100)
8100 debugf(answer
->rrtype
== kDNSType_A
?
8101 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
8102 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
8103 query
->Answers
, query
->qSRV
.qname
.c
, &answer
->rdata
->u
.data
);
8104 query
->ServiceInfoQueryCallback(m
, query
);
8108 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
8109 // If the query is not interface-specific, then InterfaceID may be zero
8110 // Each time the Callback is invoked, the remainder of the fields will have been filled in
8111 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
8112 mDNSexport mStatus
mDNS_StartResolveService(mDNS
*const m
,
8113 ServiceInfoQuery
*query
, ServiceInfo
*info
, mDNSServiceInfoQueryCallback
*Callback
, void *Context
)
8118 query
->qSRV
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
8119 query
->qSRV
.InterfaceID
= info
->InterfaceID
;
8120 query
->qSRV
.Target
= zeroAddr
;
8121 AssignDomainName(&query
->qSRV
.qname
, &info
->name
);
8122 query
->qSRV
.qtype
= kDNSType_SRV
;
8123 query
->qSRV
.qclass
= kDNSClass_IN
;
8124 query
->qSRV
.LongLived
= mDNSfalse
;
8125 query
->qSRV
.ExpectUnique
= mDNStrue
;
8126 query
->qSRV
.ForceMCast
= mDNSfalse
;
8127 query
->qSRV
.ReturnIntermed
= mDNSfalse
;
8128 query
->qSRV
.QuestionCallback
= FoundServiceInfoSRV
;
8129 query
->qSRV
.QuestionContext
= query
;
8131 query
->qTXT
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
8132 query
->qTXT
.InterfaceID
= info
->InterfaceID
;
8133 query
->qTXT
.Target
= zeroAddr
;
8134 AssignDomainName(&query
->qTXT
.qname
, &info
->name
);
8135 query
->qTXT
.qtype
= kDNSType_TXT
;
8136 query
->qTXT
.qclass
= kDNSClass_IN
;
8137 query
->qTXT
.LongLived
= mDNSfalse
;
8138 query
->qTXT
.ExpectUnique
= mDNStrue
;
8139 query
->qTXT
.ForceMCast
= mDNSfalse
;
8140 query
->qTXT
.ReturnIntermed
= mDNSfalse
;
8141 query
->qTXT
.QuestionCallback
= FoundServiceInfoTXT
;
8142 query
->qTXT
.QuestionContext
= query
;
8144 query
->qAv4
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
8145 query
->qAv4
.InterfaceID
= info
->InterfaceID
;
8146 query
->qAv4
.Target
= zeroAddr
;
8147 query
->qAv4
.qname
.c
[0] = 0;
8148 query
->qAv4
.qtype
= kDNSType_A
;
8149 query
->qAv4
.qclass
= kDNSClass_IN
;
8150 query
->qAv4
.LongLived
= mDNSfalse
;
8151 query
->qAv4
.ExpectUnique
= mDNStrue
;
8152 query
->qAv4
.ForceMCast
= mDNSfalse
;
8153 query
->qAv4
.ReturnIntermed
= mDNSfalse
;
8154 query
->qAv4
.QuestionCallback
= FoundServiceInfo
;
8155 query
->qAv4
.QuestionContext
= query
;
8157 query
->qAv6
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
8158 query
->qAv6
.InterfaceID
= info
->InterfaceID
;
8159 query
->qAv6
.Target
= zeroAddr
;
8160 query
->qAv6
.qname
.c
[0] = 0;
8161 query
->qAv6
.qtype
= kDNSType_AAAA
;
8162 query
->qAv6
.qclass
= kDNSClass_IN
;
8163 query
->qAv6
.LongLived
= mDNSfalse
;
8164 query
->qAv6
.ExpectUnique
= mDNStrue
;
8165 query
->qAv6
.ForceMCast
= mDNSfalse
;
8166 query
->qAv6
.ReturnIntermed
= mDNSfalse
;
8167 query
->qAv6
.QuestionCallback
= FoundServiceInfo
;
8168 query
->qAv6
.QuestionContext
= query
;
8170 query
->GotSRV
= mDNSfalse
;
8171 query
->GotTXT
= mDNSfalse
;
8172 query
->GotADD
= mDNSfalse
;
8176 query
->ServiceInfoQueryCallback
= Callback
;
8177 query
->ServiceInfoQueryContext
= Context
;
8179 // info->name = Must already be set up by client
8180 // info->interface = Must already be set up by client
8181 info
->ip
= zeroAddr
;
8182 info
->port
= zeroIPPort
;
8185 // We use mDNS_StartQuery_internal here because we're already holding the lock
8186 status
= mDNS_StartQuery_internal(m
, &query
->qSRV
);
8187 if (status
== mStatus_NoError
) status
= mDNS_StartQuery_internal(m
, &query
->qTXT
);
8188 if (status
!= mStatus_NoError
) mDNS_StopResolveService(m
, query
);
8194 mDNSexport
void mDNS_StopResolveService (mDNS
*const m
, ServiceInfoQuery
*q
)
8197 // We use mDNS_StopQuery_internal here because we're already holding the lock
8198 if (q
->qSRV
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qSRV
);
8199 if (q
->qTXT
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qTXT
);
8200 if (q
->qAv4
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv4
);
8201 if (q
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv6
);
8205 mDNSexport mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
8206 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
8208 question
->InterfaceID
= InterfaceID
;
8209 question
->Target
= zeroAddr
;
8210 question
->qtype
= kDNSType_PTR
;
8211 question
->qclass
= kDNSClass_IN
;
8212 question
->LongLived
= mDNSfalse
;
8213 question
->ExpectUnique
= mDNSfalse
;
8214 question
->ForceMCast
= mDNSfalse
;
8215 question
->ReturnIntermed
= mDNSfalse
;
8216 question
->QuestionCallback
= Callback
;
8217 question
->QuestionContext
= Context
;
8218 if (DomainType
> mDNS_DomainTypeMax
) return(mStatus_BadParamErr
);
8219 if (!MakeDomainNameFromDNSNameString(&question
->qname
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
8220 if (!dom
) dom
= &localdomain
;
8221 if (!AppendDomainName(&question
->qname
, dom
)) return(mStatus_BadParamErr
);
8222 return(mDNS_StartQuery(m
, question
));
8225 // ***************************************************************************
8226 #if COMPILER_LIKES_PRAGMA_MARK
8228 #pragma mark - Responder Functions
8231 mDNSexport mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
)
8235 status
= mDNS_Register_internal(m
, rr
);
8240 mDNSexport mStatus
mDNS_Update(mDNS
*const m
, AuthRecord
*const rr
, mDNSu32 newttl
,
8241 const mDNSu16 newrdlength
, RData
*const newrdata
, mDNSRecordUpdateCallback
*Callback
)
8243 #ifndef UNICAST_DISABLED
8244 mDNSBool unicast
= !(rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(rr
->resrec
.name
));
8246 mDNSBool unicast
= mDNSfalse
;
8249 if (!ValidateRData(rr
->resrec
.rrtype
, newrdlength
, newrdata
))
8251 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr
->resrec
, &newrdata
->u
, m
->MsgBuffer
));
8252 return(mStatus_Invalid
);
8257 // If TTL is unspecified, leave TTL unchanged
8258 if (newttl
== 0) newttl
= rr
->resrec
.rroriginalttl
;
8260 // If we already have an update queued up which has not gone through yet,
8261 // give the client a chance to free that memory
8262 if (!unicast
&& rr
->NewRData
)
8264 RData
*n
= rr
->NewRData
;
8265 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
8266 if (rr
->UpdateCallback
)
8267 rr
->UpdateCallback(m
, rr
, n
); // ...and let the client free this memory, if necessary
8270 rr
->NewRData
= newrdata
;
8271 rr
->newrdlength
= newrdlength
;
8272 rr
->UpdateCallback
= Callback
;
8274 if (unicast
) { mStatus status
= uDNS_UpdateRecord(m
, rr
); mDNS_Unlock(m
); return(status
); }
8276 if (rr
->resrec
.rroriginalttl
== newttl
&&
8277 rr
->resrec
.rdlength
== newrdlength
&& mDNSPlatformMemSame(rr
->resrec
.rdata
->u
.data
, newrdata
->u
.data
, newrdlength
))
8278 CompleteRDataUpdate(m
, rr
);
8282 domainname type
, domain
;
8283 DeconstructServiceName(rr
->resrec
.name
, &name
, &type
, &domain
);
8284 rr
->AnnounceCount
= InitialAnnounceCount
;
8285 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
8286 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
8287 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
8288 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
8289 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
8290 if (SameDomainLabel(type
.c
, (mDNSu8
*)"\x6_ichat")) rr
->AnnounceCount
= 1;
8291 InitializeLastAPTime(m
, rr
);
8292 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
8293 if (!rr
->UpdateBlocked
&& rr
->UpdateCredits
) rr
->UpdateCredits
--;
8294 if (!rr
->NextUpdateCredit
) rr
->NextUpdateCredit
= NonZeroTime(m
->timenow
+ kUpdateCreditRefreshInterval
);
8295 if (rr
->AnnounceCount
> rr
->UpdateCredits
+ 1) rr
->AnnounceCount
= (mDNSu8
)(rr
->UpdateCredits
+ 1);
8296 if (rr
->UpdateCredits
<= 5)
8298 mDNSu32 delay
= 6 - rr
->UpdateCredits
; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
8299 if (!rr
->UpdateBlocked
) rr
->UpdateBlocked
= NonZeroTime(m
->timenow
+ (mDNSs32
)delay
* mDNSPlatformOneSecond
);
8300 rr
->ThisAPInterval
*= 4;
8301 rr
->LastAPTime
= rr
->UpdateBlocked
- rr
->ThisAPInterval
;
8302 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
8303 rr
->resrec
.name
->c
, delay
, delay
> 1 ? "s" : "");
8305 rr
->resrec
.rroriginalttl
= newttl
;
8309 return(mStatus_NoError
);
8312 // Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
8313 // the record list and/or question list.
8314 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8315 mDNSexport mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
)
8319 status
= mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
8324 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
8325 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
8327 mDNSlocal NetworkInterfaceInfo
*FindFirstAdvertisedInterface(mDNS
*const m
)
8329 NetworkInterfaceInfo
*intf
;
8330 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8331 if (intf
->Advertise
) break;
8335 mDNSlocal
void AdvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8337 char buffer
[MAX_REVERSE_MAPPING_NAME
];
8338 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
8339 if (!primary
) primary
= set
; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
8341 // Send dynamic update for non-linklocal IPv4 Addresses
8342 mDNS_SetupResourceRecord(&set
->RR_A
, mDNSNULL
, set
->InterfaceID
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNS_HostNameCallback
, set
);
8343 mDNS_SetupResourceRecord(&set
->RR_PTR
, mDNSNULL
, set
->InterfaceID
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
8344 mDNS_SetupResourceRecord(&set
->RR_HINFO
, mDNSNULL
, set
->InterfaceID
, kDNSType_HINFO
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
8346 #if ANSWER_REMOTE_HOSTNAME_QUERIES
8347 set
->RR_A
.AllowRemoteQuery
= mDNStrue
;
8348 set
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
8349 set
->RR_HINFO
.AllowRemoteQuery
= mDNStrue
;
8351 // 1. Set up Address record to map from host name ("foo.local.") to IP address
8352 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
8353 AssignDomainName(&set
->RR_A
.namestorage
, &m
->MulticastHostname
);
8354 if (set
->ip
.type
== mDNSAddrType_IPv4
)
8356 set
->RR_A
.resrec
.rrtype
= kDNSType_A
;
8357 set
->RR_A
.resrec
.rdata
->u
.ipv4
= set
->ip
.ip
.v4
;
8358 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8359 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.",
8360 set
->ip
.ip
.v4
.b
[3], set
->ip
.ip
.v4
.b
[2], set
->ip
.ip
.v4
.b
[1], set
->ip
.ip
.v4
.b
[0]);
8362 else if (set
->ip
.type
== mDNSAddrType_IPv6
)
8365 set
->RR_A
.resrec
.rrtype
= kDNSType_AAAA
;
8366 set
->RR_A
.resrec
.rdata
->u
.ipv6
= set
->ip
.ip
.v6
;
8367 for (i
= 0; i
< 16; i
++)
8369 static const char hexValues
[] = "0123456789ABCDEF";
8370 buffer
[i
* 4 ] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] & 0x0F];
8371 buffer
[i
* 4 + 1] = '.';
8372 buffer
[i
* 4 + 2] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] >> 4];
8373 buffer
[i
* 4 + 3] = '.';
8375 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
8378 MakeDomainNameFromDNSNameString(&set
->RR_PTR
.namestorage
, buffer
);
8379 set
->RR_PTR
.AutoTarget
= Target_AutoHost
; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
8380 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
8382 set
->RR_A
.RRSet
= &primary
->RR_A
; // May refer to self
8384 mDNS_Register_internal(m
, &set
->RR_A
);
8385 mDNS_Register_internal(m
, &set
->RR_PTR
);
8387 if (!NO_HINFO
&& m
->HIHardware
.c
[0] > 0 && m
->HISoftware
.c
[0] > 0 && m
->HIHardware
.c
[0] + m
->HISoftware
.c
[0] <= 254)
8389 mDNSu8
*p
= set
->RR_HINFO
.resrec
.rdata
->u
.data
;
8390 AssignDomainName(&set
->RR_HINFO
.namestorage
, &m
->MulticastHostname
);
8391 set
->RR_HINFO
.DependentOn
= &set
->RR_A
;
8392 mDNSPlatformMemCopy(p
, &m
->HIHardware
, 1 + (mDNSu32
)m
->HIHardware
.c
[0]);
8394 mDNSPlatformMemCopy(p
, &m
->HISoftware
, 1 + (mDNSu32
)m
->HISoftware
.c
[0]);
8395 mDNS_Register_internal(m
, &set
->RR_HINFO
);
8399 debugf("Not creating HINFO record: platform support layer provided no information");
8400 set
->RR_HINFO
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
8404 mDNSlocal
void DeadvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8406 NetworkInterfaceInfo
*intf
;
8408 // If we still have address records referring to this one, update them
8409 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
8410 AuthRecord
*A
= primary
? &primary
->RR_A
: mDNSNULL
;
8411 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8412 if (intf
->RR_A
.RRSet
== &set
->RR_A
)
8413 intf
->RR_A
.RRSet
= A
;
8415 // Unregister these records.
8416 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
8417 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
8418 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
8419 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
8420 if (set
->RR_A
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_A
, mDNS_Dereg_normal
);
8421 if (set
->RR_PTR
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_PTR
, mDNS_Dereg_normal
);
8422 if (set
->RR_HINFO
.resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_HINFO
, mDNS_Dereg_normal
);
8425 mDNSexport
void mDNS_SetFQDN(mDNS
*const m
)
8427 domainname newmname
;
8428 NetworkInterfaceInfo
*intf
;
8432 if (!AppendDomainLabel(&newmname
, &m
->hostlabel
)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8433 if (!AppendLiteralLabelString(&newmname
, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8437 if (SameDomainNameCS(&m
->MulticastHostname
, &newmname
)) debugf("mDNS_SetFQDN - hostname unchanged");
8440 AssignDomainName(&m
->MulticastHostname
, &newmname
);
8442 // 1. Stop advertising our address records on all interfaces
8443 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8444 if (intf
->Advertise
) DeadvertiseInterface(m
, intf
);
8446 // 2. Start advertising our address records using the new name
8447 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8448 if (intf
->Advertise
) AdvertiseInterface(m
, intf
);
8451 // 3. Make sure that any AutoTarget SRV records (and the like) get updated
8452 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8453 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
8458 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8460 (void)rr
; // Unused parameter
8464 char *msg
= "Unknown result";
8465 if (result
== mStatus_NoError
) msg
= "Name registered";
8466 else if (result
== mStatus_NameConflict
) msg
= "Name conflict";
8467 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8471 if (result
== mStatus_NoError
)
8473 // Notify the client that the host name is successfully registered
8474 if (m
->MainCallback
)
8475 m
->MainCallback(m
, mStatus_NoError
);
8477 else if (result
== mStatus_NameConflict
)
8479 domainlabel oldlabel
= m
->hostlabel
;
8481 // 1. First give the client callback a chance to pick a new name
8482 if (m
->MainCallback
)
8483 m
->MainCallback(m
, mStatus_NameConflict
);
8485 // 2. If the client callback didn't do it, add (or increment) an index ourselves
8486 // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
8487 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
8488 if (SameDomainLabel(m
->hostlabel
.c
, oldlabel
.c
))
8489 IncrementLabelSuffix(&m
->hostlabel
, mDNSfalse
);
8491 // 3. Generate the FQDNs from the hostlabel,
8492 // and make sure all SRV records, etc., are updated to reference our new hostname
8494 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel
.c
, m
->hostlabel
.c
);
8496 else if (result
== mStatus_MemFree
)
8498 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
8499 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
8500 debugf("mDNS_HostNameCallback: MemFree (ignored)");
8503 LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result
, rr
->resrec
.name
->c
);
8506 mDNSlocal
void UpdateInterfaceProtocols(mDNS
*const m
, NetworkInterfaceInfo
*active
)
8508 NetworkInterfaceInfo
*intf
;
8509 active
->IPv4Available
= mDNSfalse
;
8510 active
->IPv6Available
= mDNSfalse
;
8511 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8512 if (intf
->InterfaceID
== active
->InterfaceID
)
8514 if (intf
->ip
.type
== mDNSAddrType_IPv4
&& intf
->McastTxRx
) active
->IPv4Available
= mDNStrue
;
8515 if (intf
->ip
.type
== mDNSAddrType_IPv6
&& intf
->McastTxRx
) active
->IPv6Available
= mDNStrue
;
8519 mDNSlocal
void RestartRecordGetZoneData(mDNS
* const m
)
8522 ServiceRecordSet
*s
;
8524 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8525 if (AuthRecord_uDNS(rr
))
8527 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr
->resrec
.name
->c
);
8528 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
8529 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
8532 for (s
= m
->ServiceRegistrations
; s
; s
= s
->uDNS_next
)
8534 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s
->RR_SRV
.resrec
.name
->c
);
8535 if (s
->srs_nta
) CancelGetZoneData(m
, s
->srs_nta
);
8536 s
->srs_nta
= StartGetZoneData(m
, s
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, s
);
8540 mDNSlocal
void InitializeNetWakeState(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8543 set
->NetWakeBrowse
.ThisQInterval
= -1;
8546 set
->NetWakeResolve
[i
].ThisQInterval
= -1;
8547 set
->SPSAddr
[i
].type
= mDNSAddrType_None
;
8549 set
->NextSPSAttempt
= -1;
8550 set
->NextSPSAttemptTime
= m
->timenow
;
8553 mDNSexport
void mDNS_ActivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8555 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8556 while (p
&& p
!= set
) p
=p
->next
;
8557 if (!p
) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8559 if (set
->InterfaceActive
)
8561 LogSPS("ActivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8562 mDNS_StartBrowse_internal(m
, &set
->NetWakeBrowse
, &SleepProxyServiceType
, &localdomain
, set
->InterfaceID
, mDNSfalse
, m
->SPSBrowseCallback
, set
);
8566 mDNSexport
void mDNS_DeactivateNetWake_internal(mDNS
*const m
, NetworkInterfaceInfo
*set
)
8568 NetworkInterfaceInfo
*p
= m
->HostInterfaces
;
8569 while (p
&& p
!= set
) p
=p
->next
;
8570 if (!p
) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set
); return; }
8572 if (set
->NetWakeBrowse
.ThisQInterval
>= 0)
8575 LogSPS("DeactivateNetWake for %s (%#a)", set
->ifname
, &set
->ip
);
8577 // Stop our browse and resolve operations
8578 mDNS_StopQuery_internal(m
, &set
->NetWakeBrowse
);
8579 for (i
=0; i
<3; i
++) if (set
->NetWakeResolve
[i
].ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &set
->NetWakeResolve
[i
]);
8581 // Make special call to the browse callback to let it know it can to remove all records for this interface
8582 if (m
->SPSBrowseCallback
) m
->SPSBrowseCallback(m
, &set
->NetWakeBrowse
, mDNSNULL
, mDNSfalse
);
8584 // Reset our variables back to initial state, so we're ready for when NetWake is turned back on
8585 // (includes resetting NetWakeBrowse.ThisQInterval back to -1)
8586 InitializeNetWakeState(m
, set
);
8590 mDNSexport mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8593 mDNSBool FirstOfType
= mDNStrue
;
8594 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8596 if (!set
->InterfaceID
)
8597 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set
->ip
); return(mStatus_Invalid
); }
8599 if (!mDNSAddressIsValidNonZero(&set
->mask
))
8600 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set
->ip
, &set
->mask
); return(mStatus_Invalid
); }
8604 // Assume this interface will be active now, unless we find a duplicate already in the list
8605 set
->InterfaceActive
= mDNStrue
;
8606 set
->IPv4Available
= (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
);
8607 set
->IPv6Available
= (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
);
8609 InitializeNetWakeState(m
, set
);
8611 // Scan list to see if this InterfaceID is already represented
8616 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
8618 return(mStatus_AlreadyRegistered
);
8621 if ((*p
)->InterfaceID
== set
->InterfaceID
)
8623 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
8624 set
->InterfaceActive
= mDNSfalse
;
8625 if (set
->ip
.type
== (*p
)->ip
.type
) FirstOfType
= mDNSfalse
;
8626 if (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
) (*p
)->IPv4Available
= mDNStrue
;
8627 if (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
) (*p
)->IPv6Available
= mDNStrue
;
8633 set
->next
= mDNSNULL
;
8637 AdvertiseInterface(m
, set
);
8639 LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set
->InterfaceID
, set
->ifname
, &set
->ip
,
8640 set
->InterfaceActive
?
8641 "not represented in list; marking active and retriggering queries" :
8642 "already represented in list; marking inactive for now");
8644 if (set
->NetWake
) mDNS_ActivateNetWake_internal(m
, set
);
8646 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8647 // giving the false impression that there's an active representative of this interface when there really isn't.
8648 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
8649 // even if we believe that we previously had an active representative of this interface.
8650 if (set
->McastTxRx
&& ((m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) || FirstOfType
|| set
->InterfaceActive
))
8653 // If flapping, delay between first and second queries is eight seconds instead of one
8654 mDNSs32 delay
= flapping
? mDNSPlatformOneSecond
* 5 : 0;
8655 mDNSu8 announce
= flapping
? (mDNSu8
)1 : InitialAnnounceCount
;
8658 // Use a small amount of randomness:
8659 // In the case of a network administrator turning on an Ethernet hub so that all the
8660 // connected machines establish link at exactly the same time, we don't want them all
8661 // to go and hit the network with identical queries at exactly the same moment.
8662 newSS
= m
->timenow
+ (mDNSs32
)mDNSRandom((mDNSu32
)InitialQuestionInterval
);
8663 #if APPLE_OSX_mDNSResponder
8664 // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
8665 // of network change notifications in a row, and we don't know when we're done getting notified.
8666 // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
8667 newSS
+= mDNSPlatformOneSecond
* 2;
8669 if (!m
->SuppressSending
|| newSS
- m
->SuppressSending
< 0) m
->SuppressSending
= newSS
;
8673 LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)",
8674 set
->ifname
, &set
->ip
);
8675 if (!m
->SuppressProbes
||
8676 m
->SuppressProbes
- (m
->timenow
+ delay
) < 0)
8677 m
->SuppressProbes
= (m
->timenow
+ delay
);
8680 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
8681 if (mDNSOpaque16IsZero(q
->TargetQID
))
8682 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
) // If non-specific Q, or Q on this specific interface,
8683 { // then reactivate this question
8684 mDNSBool dodelay
= flapping
&& (q
->FlappingInterface1
== set
->InterfaceID
|| q
->FlappingInterface2
== set
->InterfaceID
);
8685 mDNSs32 initial
= dodelay
? InitialQuestionInterval
* QuestionIntervalStep2
: InitialQuestionInterval
;
8686 mDNSs32 qdelay
= dodelay
? mDNSPlatformOneSecond
* 5 : 0;
8687 if (dodelay
) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q
->qname
.c
, DNSTypeName(q
->qtype
));
8689 if (!q
->ThisQInterval
|| q
->ThisQInterval
> initial
)
8691 q
->ThisQInterval
= initial
;
8692 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
8694 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ qdelay
;
8695 q
->RecentAnswerPkts
= 0;
8696 SetNextQueryTime(m
,q
);
8699 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
8700 // we now need them to re-probe if necessary, and then re-announce.
8701 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
8702 if (!AuthRecord_uDNS(rr
))
8703 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8705 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
8706 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
8707 if (rr
->AnnounceCount
< announce
) rr
->AnnounceCount
= announce
;
8708 InitializeLastAPTime(m
, rr
);
8712 RestartRecordGetZoneData(m
);
8715 return(mStatus_NoError
);
8718 // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
8719 // the record list and/or question list.
8720 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8721 mDNSexport
void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
8723 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
8725 mDNSBool revalidate
= mDNSfalse
;
8726 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
8727 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
8728 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
8729 if (m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) revalidate
= mDNStrue
;
8733 // Find this record in our list
8734 while (*p
&& *p
!= set
) p
=&(*p
)->next
;
8735 if (!*p
) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m
); return; }
8737 mDNS_DeactivateNetWake_internal(m
, set
);
8739 // Unlink this record from our list
8741 set
->next
= mDNSNULL
;
8743 if (!set
->InterfaceActive
)
8745 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
8746 NetworkInterfaceInfo
*intf
;
8747 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8748 if (intf
->InterfaceActive
&& intf
->InterfaceID
== set
->InterfaceID
)
8749 UpdateInterfaceProtocols(m
, intf
);
8753 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, set
->InterfaceID
);
8756 LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
8757 " making it active", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8758 if (intf
->InterfaceActive
)
8759 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set
->ifname
, &set
->ip
);
8760 intf
->InterfaceActive
= mDNStrue
;
8761 UpdateInterfaceProtocols(m
, intf
);
8763 if (intf
->NetWake
) mDNS_ActivateNetWake_internal(m
, intf
);
8765 // See if another representative *of the same type* exists. If not, we mave have gone from
8766 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
8767 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
8768 if (intf
->InterfaceID
== set
->InterfaceID
&& intf
->ip
.type
== set
->ip
.type
)
8770 if (!intf
) revalidate
= mDNStrue
;
8780 LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
8781 " marking questions etc. dormant", set
->InterfaceID
, set
->ifname
, &set
->ip
);
8784 LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)",
8785 set
->ifname
, &set
->ip
);
8787 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
8788 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
8789 for (q
= m
->Questions
; q
; q
=q
->next
)
8791 if (q
->InterfaceID
== set
->InterfaceID
) q
->ThisQInterval
= 0;
8792 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
)
8794 q
->FlappingInterface2
= q
->FlappingInterface1
;
8795 q
->FlappingInterface1
= set
->InterfaceID
; // Keep history of the last two interfaces to go away
8799 // 2. Flush any cache records received on this interface
8800 revalidate
= mDNSfalse
; // Don't revalidate if we're flushing the records
8801 FORALL_CACHERECORDS(slot
, cg
, rr
)
8802 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8804 // If this interface is deemed flapping,
8805 // postpone deleting the cache records in case the interface comes back again
8806 if (!flapping
) mDNS_PurgeCacheResourceRecord(m
, rr
);
8809 // We want these record to go away in 30 seconds
8810 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
8811 // if the interface does come back, any relevant questions will be reactivated anyway
8812 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8813 rr
->UnansweredQueries
= MaxUnansweredQueries
;
8817 // 3. Any DNS servers specific to this interface are now unusable
8818 for (s
= m
->DNSServers
; s
; s
= s
->next
)
8819 if (s
->interface
== set
->InterfaceID
)
8821 s
->interface
= mDNSInterface_Any
;
8822 s
->teststate
= DNSServer_Disabled
;
8827 // If we were advertising on this interface, deregister those address and reverse-lookup records now
8828 if (set
->Advertise
) DeadvertiseInterface(m
, set
);
8830 // If we have any cache records received on this interface that went away, then re-verify them.
8831 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8832 // giving the false impression that there's an active representative of this interface when there really isn't.
8833 // Don't need to do this when shutting down, because *all* interfaces are about to go away
8834 if (revalidate
&& !m
->ShutdownTime
)
8839 m
->NextCacheCheck
= m
->timenow
;
8840 FORALL_CACHERECORDS(slot
, cg
, rr
)
8841 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
8842 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
8848 mDNSlocal
void ServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8850 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8851 (void)m
; // Unused parameter
8855 char *msg
= "Unknown result";
8856 if (result
== mStatus_NoError
) msg
= "Name Registered";
8857 else if (result
== mStatus_NameConflict
) msg
= "Name Conflict";
8858 else if (result
== mStatus_MemFree
) msg
= "Memory Free";
8859 debugf("ServiceCallback: %##s (%s) %s (%d)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
8863 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
8864 if (result
== mStatus_NoError
&& rr
!= &sr
->RR_SRV
) return;
8866 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
8867 if (result
== mStatus_NameConflict
)
8869 sr
->Conflict
= mDNStrue
; // Record that this service set had a conflict
8870 mDNS_DeregisterService(m
, sr
); // Unlink the records from our list
8874 if (result
== mStatus_MemFree
)
8876 // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
8877 // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
8878 // every record is finished cleaning up.
8880 if (sr
->RR_SRV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8881 if (sr
->RR_TXT
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8882 if (sr
->RR_PTR
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8883 if (sr
->RR_ADV
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8884 for (i
=0; i
<sr
->NumSubTypes
; i
++) if (sr
->SubTypes
[i
].resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
8886 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
8887 // then we can now report the NameConflict to the client
8888 if (sr
->Conflict
) result
= mStatus_NameConflict
;
8892 LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m
, &sr
->RR_SRV
));
8893 CancelGetZoneData(m
, sr
->srs_nta
);
8894 sr
->srs_nta
= mDNSNULL
;
8898 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
8899 // function is allowed to do anything, including deregistering this service and freeing its memory.
8900 if (sr
->ServiceCallback
)
8901 sr
->ServiceCallback(m
, sr
, result
);
8904 mDNSlocal
void NSSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
8906 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
8907 if (sr
->ServiceCallback
)
8908 sr
->ServiceCallback(m
, sr
, result
);
8911 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8912 mDNSlocal mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
8915 ServiceRecordSet
**p
= &m
->ServiceRegistrations
;
8916 while (*p
&& *p
!= srs
) p
=&(*p
)->uDNS_next
;
8917 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
->c
); return(mStatus_AlreadyRegistered
); }
8919 srs
->uDNS_next
= mDNSNULL
;
8922 srs
->RR_SRV
.resrec
.rroriginalttl
= kHostNameTTL
;
8923 srs
->RR_TXT
.resrec
.rroriginalttl
= kStandardTTL
;
8924 srs
->RR_PTR
.resrec
.rroriginalttl
= kStandardTTL
;
8925 for (i
= 0; i
< srs
->NumSubTypes
;i
++) srs
->SubTypes
[i
].resrec
.rroriginalttl
= kStandardTTL
;
8927 srs
->srs_uselease
= mDNStrue
;
8929 if (srs
->RR_SRV
.AutoTarget
)
8931 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
8932 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
8933 // with the port number in our advertised SRV record automatically tracking the external mapped port.
8934 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
8935 if (!AuthInfo
|| !AuthInfo
->AutoTunnel
) srs
->RR_SRV
.AutoTarget
= Target_AutoHostAndNATMAP
;
8938 if (!GetServiceTarget(m
, &srs
->RR_SRV
))
8940 // defer registration until we've got a target
8941 LogInfo("uDNS_RegisterService - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
8942 srs
->state
= regState_NoTarget
;
8943 return mStatus_NoError
;
8946 ActivateUnicastRegistration(m
, &srs
->RR_SRV
);
8947 srs
->state
= regState_FetchingZoneData
;
8948 return mStatus_NoError
;
8953 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
8954 // Type is service type (e.g. "_ipp._tcp.")
8955 // Domain is fully qualified domain name (i.e. ending with a null label)
8956 // We always register a TXT, even if it is empty (so that clients are not
8957 // left waiting forever looking for a nonexistent record.)
8958 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
8959 // then the default host name (m->MulticastHostname) is automatically used
8960 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
8961 mDNSexport mStatus
mDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*sr
,
8962 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
8963 const domainname
*const host
, mDNSIPPort port
, const mDNSu8 txtinfo
[], mDNSu16 txtlen
,
8964 AuthRecord
*SubTypes
, mDNSu32 NumSubTypes
,
8965 const mDNSInterfaceID InterfaceID
, mDNSServiceCallback Callback
, void *Context
)
8970 sr
->state
= regState_Zero
;
8971 sr
->srs_uselease
= 0;
8972 sr
->TestForSelfConflict
= 0;
8976 sr
->SRSUpdateServer
= zeroAddr
;
8977 sr
->SRSUpdatePort
= zeroIPPort
;
8978 mDNSPlatformMemZero(&sr
->NATinfo
, sizeof(sr
->NATinfo
));
8979 sr
->NATinfo
.IntPort
= port
; // Record originally-requested port
8980 sr
->ClientCallbackDeferred
= 0;
8981 sr
->DeferredStatus
= 0;
8982 sr
->SRVUpdateDeferred
= 0;
8986 sr
->ServiceCallback
= Callback
;
8987 sr
->ServiceContext
= Context
;
8988 sr
->Conflict
= mDNSfalse
;
8990 sr
->Extras
= mDNSNULL
;
8991 sr
->NumSubTypes
= NumSubTypes
;
8992 sr
->SubTypes
= SubTypes
;
8994 // Initialize the AuthRecord objects to sane values
8995 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
8996 mDNS_SetupResourceRecord(&sr
->RR_ADV
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeAdvisory
, ServiceCallback
, sr
);
8997 mDNS_SetupResourceRecord(&sr
->RR_PTR
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
8998 mDNS_SetupResourceRecord(&sr
->RR_SRV
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
8999 mDNS_SetupResourceRecord(&sr
->RR_TXT
, mDNSNULL
, InterfaceID
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
9001 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
9002 if (mDNSIPPortIsZero(port
))
9003 return(mDNS_RegisterNoSuchService(m
, &sr
->RR_SRV
, name
, type
, domain
, mDNSNULL
, mDNSInterface_Any
, NSSCallback
, sr
));
9005 // If the client is registering an oversized TXT record,
9006 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
9007 if (sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
< txtlen
)
9008 sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
= txtlen
;
9010 // Set up the record names
9011 // For now we only create an advisory record for the main type, not for subtypes
9012 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
9013 if (ConstructServiceName(&sr
->RR_ADV
.namestorage
, (const domainlabel
*)"\x09_services", (const domainname
*)"\x07_dns-sd\x04_udp", domain
) == mDNSNULL
)
9014 return(mStatus_BadParamErr
);
9015 if (ConstructServiceName(&sr
->RR_PTR
.namestorage
, mDNSNULL
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
9016 if (ConstructServiceName(&sr
->RR_SRV
.namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
9017 AssignDomainName(&sr
->RR_TXT
.namestorage
, sr
->RR_SRV
.resrec
.name
);
9019 // 1. Set up the ADV record rdata to advertise our service type
9020 AssignDomainName(&sr
->RR_ADV
.resrec
.rdata
->u
.name
, sr
->RR_PTR
.resrec
.name
);
9022 // 2. Set up the PTR record rdata to point to our service name
9023 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
9024 AssignDomainName(&sr
->RR_PTR
.resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
9025 sr
->RR_PTR
.Additional1
= &sr
->RR_SRV
;
9026 sr
->RR_PTR
.Additional2
= &sr
->RR_TXT
;
9028 // 2a. Set up any subtype PTRs to point to our service name
9029 // If the client is using subtypes, it is the client's responsibility to have
9030 // already set the first label of the record name to the subtype being registered
9031 for (i
=0; i
<NumSubTypes
; i
++)
9034 AssignDomainName(&st
, sr
->SubTypes
[i
].resrec
.name
);
9035 st
.c
[1+st
.c
[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
9036 AppendDomainName(&st
, type
);
9037 mDNS_SetupResourceRecord(&sr
->SubTypes
[i
], mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
9038 if (ConstructServiceName(&sr
->SubTypes
[i
].namestorage
, mDNSNULL
, &st
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
9039 AssignDomainName(&sr
->SubTypes
[i
].resrec
.rdata
->u
.name
, &sr
->RR_SRV
.namestorage
);
9040 sr
->SubTypes
[i
].Additional1
= &sr
->RR_SRV
;
9041 sr
->SubTypes
[i
].Additional2
= &sr
->RR_TXT
;
9044 // 3. Set up the SRV record rdata.
9045 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.priority
= 0;
9046 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.weight
= 0;
9047 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= port
;
9049 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
9050 if (host
&& host
->c
[0]) AssignDomainName(&sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, host
);
9051 else { sr
->RR_SRV
.AutoTarget
= Target_AutoHost
; sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0'; }
9053 // 4. Set up the TXT record rdata,
9054 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
9055 if (txtinfo
== mDNSNULL
) sr
->RR_TXT
.resrec
.rdlength
= 0;
9056 else if (txtinfo
!= sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
)
9058 sr
->RR_TXT
.resrec
.rdlength
= txtlen
;
9059 if (sr
->RR_TXT
.resrec
.rdlength
> sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
) return(mStatus_BadParamErr
);
9060 mDNSPlatformMemCopy(sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, txtinfo
, txtlen
);
9062 sr
->RR_TXT
.DependentOn
= &sr
->RR_SRV
;
9064 sr
->srs_nta
= mDNSNULL
;
9066 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9067 // If the client has specified an explicit InterfaceID,
9068 // then we do a multicast registration on that interface, even for unicast domains.
9069 if (!(InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&sr
->RR_SRV
.namestorage
)))
9073 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
9074 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
9075 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
9076 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
9077 if (!sr
->RR_TXT
.resrec
.rdlength
) { sr
->RR_TXT
.resrec
.rdlength
= 1; sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
[0] = 0; }
9079 status
= uDNS_RegisterService(m
, sr
);
9086 err
= mDNS_Register_internal(m
, &sr
->RR_SRV
);
9087 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_TXT
);
9088 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
9089 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
9090 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
9091 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
9092 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
9093 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_ADV
);
9094 for (i
=0; i
<NumSubTypes
; i
++) if (!err
) err
= mDNS_Register_internal(m
, &sr
->SubTypes
[i
]);
9095 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_PTR
);
9099 if (err
) mDNS_DeregisterService(m
, sr
);
9103 mDNSlocal
void DummyCallback(mDNS
*const m
, AuthRecord
*rr
, mStatus result
)
9107 (void)result
; // Unused
9108 LogInfo("DummyCallback %d %s", result
, ARDisplayString(m
, rr
));
9111 mDNSexport mStatus
mDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
,
9112 ExtraResourceRecord
*extra
, RData
*rdata
, mDNSu32 ttl
)
9114 ExtraResourceRecord
**e
;
9117 extra
->next
= mDNSNULL
;
9118 mDNS_SetupResourceRecord(&extra
->r
, rdata
, sr
->RR_PTR
.resrec
.InterfaceID
,
9119 extra
->r
.resrec
.rrtype
, ttl
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
9120 AssignDomainName(&extra
->r
.namestorage
, sr
->RR_SRV
.resrec
.name
);
9124 while (*e
) e
= &(*e
)->next
;
9126 if (ttl
== 0) ttl
= kStandardTTL
;
9128 extra
->r
.DependentOn
= &sr
->RR_SRV
;
9130 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
9131 extra
->r
.resrec
.name
->c
, DNSTypeName(extra
->r
.resrec
.rrtype
), extra
->r
.resrec
.rdlength
);
9133 status
= mDNS_Register_internal(m
, &extra
->r
);
9134 if (status
== mStatus_NoError
)
9137 #ifndef UNICAST_DISABLED
9138 if (AuthRecord_uDNS(&sr
->RR_SRV
))
9140 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name (???)
9141 extra
->r
.RecordCallback
= DummyCallback
; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
9142 if (sr
->state
!= regState_Registered
&& sr
->state
!= regState_Refresh
) extra
->r
.state
= regState_ExtraQueued
;
9151 mDNSexport mStatus
mDNS_RemoveRecordFromService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
,
9152 mDNSRecordCallback MemFreeCallback
, void *Context
)
9154 ExtraResourceRecord
**e
;
9159 while (*e
&& *e
!= extra
) e
= &(*e
)->next
;
9162 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra
->r
.resrec
.name
->c
);
9163 status
= mStatus_BadReferenceErr
;
9167 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra
->r
.resrec
.name
->c
);
9168 extra
->r
.RecordCallback
= MemFreeCallback
;
9169 extra
->r
.RecordContext
= Context
;
9171 status
= mDNS_Deregister_internal(m
, &extra
->r
, mDNS_Dereg_normal
);
9177 mDNSexport mStatus
mDNS_RenameAndReregisterService(mDNS
*const m
, ServiceRecordSet
*const sr
, const domainlabel
*newname
)
9179 // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
9180 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
9181 domainlabel name1
, name2
;
9182 domainname type
, domain
;
9183 const domainname
*host
= sr
->RR_SRV
.AutoTarget
? mDNSNULL
: &sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
9184 ExtraResourceRecord
*extras
= sr
->Extras
;
9187 DeconstructServiceName(sr
->RR_SRV
.resrec
.name
, &name1
, &type
, &domain
);
9191 IncrementLabelSuffix(&name2
, mDNStrue
);
9195 if (SameDomainName(&domain
, &localdomain
))
9196 debugf("%##s service renamed from \"%#s\" to \"%#s\"", type
.c
, name1
.c
, newname
->c
);
9197 else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type
.c
, domain
.c
, name1
.c
, newname
->c
);
9199 err
= mDNS_RegisterService(m
, sr
, newname
, &type
, &domain
,
9200 host
, sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
, sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, sr
->RR_TXT
.resrec
.rdlength
,
9201 sr
->SubTypes
, sr
->NumSubTypes
,
9202 sr
->RR_PTR
.resrec
.InterfaceID
, sr
->ServiceCallback
, sr
->ServiceContext
);
9204 // mDNS_RegisterService() just reset sr->Extras to NULL.
9205 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
9206 // through the old list of extra records, and re-add them to our freshly created service registration
9207 while (!err
&& extras
)
9209 ExtraResourceRecord
*e
= extras
;
9210 extras
= extras
->next
;
9211 err
= mDNS_AddRecordToService(m
, sr
, e
, e
->r
.resrec
.rdata
, e
->r
.resrec
.rroriginalttl
);
9217 // Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
9218 // which may change the record list and/or question list.
9219 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
9220 mDNSexport mStatus
mDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*sr
)
9222 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
9223 if (mDNSIPPortIsZero(sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
)) return(mDNS_DeregisterNoSuchService(m
, &sr
->RR_SRV
));
9225 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9226 if (!(sr
->RR_SRV
.resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(sr
->RR_SRV
.resrec
.name
)))
9230 status
= uDNS_DeregisterService(m
, sr
);
9235 if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
9237 debugf("Service set for %##s already deregistered", sr
->RR_SRV
.resrec
.name
->c
);
9238 return(mStatus_BadReferenceErr
);
9240 else if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeDeregistering
)
9242 debugf("Service set for %##s already in the process of deregistering", sr
->RR_SRV
.resrec
.name
->c
);
9243 // Avoid race condition:
9244 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
9245 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
9246 // If the client happens to deregister the service in the middle of that process, then
9247 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
9248 // instead of incorrectly promoting it to mStatus_NameConflict.
9249 // This race condition is exposed particularly when the conformance test generates
9250 // a whole batch of simultaneous conflicts across a range of services all advertised
9251 // using the same system default name, and if we don't take this precaution then
9252 // we end up incrementing m->nicelabel multiple times instead of just once.
9253 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
9254 sr
->Conflict
= mDNSfalse
;
9255 return(mStatus_NoError
);
9261 ExtraResourceRecord
*e
;
9265 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
9266 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
9267 mDNS_Deregister_internal(m
, &sr
->RR_SRV
, mDNS_Dereg_repeat
);
9268 mDNS_Deregister_internal(m
, &sr
->RR_TXT
, mDNS_Dereg_repeat
);
9270 mDNS_Deregister_internal(m
, &sr
->RR_ADV
, mDNS_Dereg_normal
);
9272 // We deregister all of the extra records, but we leave the sr->Extras list intact
9273 // in case the client wants to do a RenameAndReregister and reinstate the registration
9276 mDNS_Deregister_internal(m
, &e
->r
, mDNS_Dereg_repeat
);
9280 for (i
=0; i
<sr
->NumSubTypes
; i
++)
9281 mDNS_Deregister_internal(m
, &sr
->SubTypes
[i
], mDNS_Dereg_normal
);
9283 // Be sure to deregister the PTR last!
9284 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
9285 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
9286 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
9287 // we've deregistered all our records and done any other necessary cleanup before that happens.
9288 status
= mDNS_Deregister_internal(m
, &sr
->RR_PTR
, mDNS_Dereg_normal
);
9294 // Create a registration that asserts that no such service exists with this name.
9295 // This can be useful where there is a given function is available through several protocols.
9296 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
9297 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
9298 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
9299 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
9300 mDNSexport mStatus
mDNS_RegisterNoSuchService(mDNS
*const m
, AuthRecord
*const rr
,
9301 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
9302 const domainname
*const host
,
9303 const mDNSInterfaceID InterfaceID
, mDNSRecordCallback Callback
, void *Context
)
9305 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, Callback
, Context
);
9306 if (ConstructServiceName(&rr
->namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
9307 rr
->resrec
.rdata
->u
.srv
.priority
= 0;
9308 rr
->resrec
.rdata
->u
.srv
.weight
= 0;
9309 rr
->resrec
.rdata
->u
.srv
.port
= zeroIPPort
;
9310 if (host
&& host
->c
[0]) AssignDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, host
);
9311 else rr
->AutoTarget
= Target_AutoHost
;
9312 return(mDNS_Register(m
, rr
));
9315 mDNSexport mStatus
mDNS_AdvertiseDomains(mDNS
*const m
, AuthRecord
*rr
,
9316 mDNS_DomainType DomainType
, const mDNSInterfaceID InterfaceID
, char *domname
)
9318 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
9319 if (!MakeDomainNameFromDNSNameString(&rr
->namestorage
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
9320 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.rdata
->u
.name
, domname
)) return(mStatus_BadParamErr
);
9321 return(mDNS_Register(m
, rr
));
9324 mDNSexport mDNSOpaque16
mDNS_NewMessageID(mDNS
* const m
)
9328 for (i
=0; i
<10; i
++)
9332 id
= mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
9333 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (mDNSSameOpaque16(id
, r
->updateid
)) continue;
9334 for (q
= m
->Questions
; q
; q
=q
->next
) if (mDNSSameOpaque16(id
, q
->TargetQID
)) continue;
9337 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id
));
9341 // ***************************************************************************
9342 #if COMPILER_LIKES_PRAGMA_MARK
9344 #pragma mark - Sleep Proxy Server
9347 mDNSlocal
void RestartARPProbing(mDNS
*const m
, AuthRecord
*const rr
)
9349 // If we see an ARP from a machine we think is sleeping, then either
9350 // (i) the machine has woken, or
9351 // (ii) it's just a stray old packet from before the machine slept
9352 // To handle the second case, we reset ProbeCount, so we'll suppress our own answers for a while, to avoid
9353 // generating ARP conflicts with a waking machine, and set rr->LastAPTime so we'll start probing again in 10 seconds.
9354 // If the machine has just woken then we'll discard our records when we see the first new mDNS probe from that machine.
9355 // If it was a stray old packet, then after 10 seconds we'll probe again and then start answering ARPs again. In this case we *do*
9356 // need to send new ARP Announcements, because the owner's ARP broadcasts will have updated neighboring ARP caches, so we need to
9357 // re-assert our (temporary) ownership of that IP address in order to receive subsequent packets addressed to that IPv4 address.
9359 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
9360 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
;
9362 // If we haven't started announcing yet (and we're not already in ten-second-delay mode) the machine is probably
9363 // still going to sleep, so we just reset rr->ProbeCount so we'll continue probing until it stops responding.
9364 // If we *have* started announcing, the machine is probably in the process of waking back up, so in that case
9365 // we're more cautious and we wait ten seconds before probing it again. We do this because while waking from
9366 // sleep, some network interfaces tend to lose or delay inbound packets, and without this delay, if the waking machine
9367 // didn't answer our three probes within three seconds then we'd announce and cause it an unnecessary address conflict.
9368 if (rr
->AnnounceCount
== InitialAnnounceCount
&& m
->timenow
- rr
->LastAPTime
>= 0)
9369 InitializeLastAPTime(m
, rr
);
9372 rr
->AnnounceCount
= InitialAnnounceCount
;
9373 rr
->ThisAPInterval
= mDNSPlatformOneSecond
;
9374 rr
->LastAPTime
= m
->timenow
+ mDNSPlatformOneSecond
* 9; // Send first packet at rr->LastAPTime + rr->ThisAPInterval, i.e. 10 seconds from now
9375 SetNextAnnounceProbeTime(m
, rr
);
9379 mDNSexport
void mDNSCoreReceiveRawPacket(mDNS
*const m
, const mDNSu8
*const p
, const mDNSu8
*const end
, const mDNSInterfaceID InterfaceID
)
9381 static const mDNSOpaque16 Ethertype_IP
= { { 0x08, 0x00 } };
9382 static const mDNSOpaque32 ARP_EthIP_h0
= { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
9383 static const mDNSOpaque32 ARP_EthIP_h1
= { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen
9384 static const mDNSOpaque16 ARP_op_request
= { { 0, 1 } };
9385 const EthernetHeader
*const eth
= (const EthernetHeader
*)p
;
9386 const ARP_EthIP
*const arp
= (const ARP_EthIP
*)(eth
+1);
9387 const IPv4Header
*const v4
= (const IPv4Header
*)(eth
+1);
9388 const IPv6Header
*const v6
= (const IPv6Header
*)(eth
+1);
9389 if (end
>= p
+42 && *(mDNSu32
*)(p
+12) == ARP_EthIP_h0
.NotAnInteger
&& *(mDNSu32
*)(p
+16) == ARP_EthIP_h1
.NotAnInteger
)
9392 NetworkInterfaceInfo
*intf
= FirstInterfaceForID(m
, InterfaceID
);
9395 debugf("Got ARP from %.4a/%.6a for %.4a", &arp
->spa
, &arp
->sha
, &arp
->tpa
);
9400 // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
9401 // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry)
9402 // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
9403 // The times we might need to react to an ARP Announcement are:
9404 // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or
9405 // (ii) if it's a conflicting Announcement from another host
9406 // -- and we check for these in Pass 2 below.
9407 if (mDNSSameOpaque16(arp
->op
, ARP_op_request
) && !mDNSSameIPv4Address(arp
->spa
, arp
->tpa
))
9408 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9409 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->tpa
))
9411 char *ifname
= InterfaceNameForID(m
, InterfaceID
);
9412 if (!ifname
) ifname
= "<NULL InterfaceID>";
9413 static const char msg1
[] = "ARP Req from owner -- re-probing";
9414 static const char msg2
[] = "Ignoring ARP Request from ";
9415 static const char msg3
[] = "Creating Local ARP Cache entry ";
9416 static const char msg4
[] = "Answering ARP Request from ";
9417 const char *const msg
= mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
) ? msg1
:
9418 (rr
->AnnounceCount
== InitialAnnounceCount
) ? msg2
:
9419 mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
) ? msg3
: msg4
;
9420 LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
9421 ifname
, msg
, &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9422 if (msg
== msg1
) RestartARPProbing(m
, rr
);
9423 else if (msg
== msg3
) mDNSPlatformSetLocalARP(&arp
->tpa
, &rr
->WakeUp
.IMAC
, InterfaceID
);
9424 else if (msg
== msg4
) SendARP(m
, 2, rr
, arp
->tpa
.b
, arp
->sha
.b
, arp
->spa
.b
, arp
->sha
.b
);
9428 // 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.
9429 // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
9430 // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
9431 // 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.
9432 // If we see an apparently conflicting ARP, we check the sender hardware address:
9433 // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
9434 // 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.
9435 if (mDNSSameEthAddress(&arp
->sha
, &intf
->MAC
))
9436 debugf("ARP from self for %.4a", &arp
->tpa
);
9439 if (!mDNSSameIPv4Address(arp
->spa
, zerov4Addr
))
9440 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9441 if (rr
->resrec
.InterfaceID
== InterfaceID
&& rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, arp
->spa
))
9443 char *ifname
= InterfaceNameForID(m
, InterfaceID
);
9444 if (!ifname
) ifname
= "<NULL InterfaceID>";
9446 RestartARPProbing(m
, rr
);
9447 if (mDNSSameEthAddress(&arp
->sha
, &rr
->WakeUp
.IMAC
))
9448 LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
9450 mDNSSameIPv4Address(arp
->spa
, arp
->tpa
) ? "Announcement" : mDNSSameOpaque16(arp
->op
, ARP_op_request
) ? "Request " : "Response ",
9451 &arp
->sha
, &arp
->spa
, &arp
->tpa
, ARDisplayString(m
, rr
));
9454 LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
9455 ifname
, &arp
->sha
, &arp
->spa
, &arp
->tpa
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, rr
));
9456 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9463 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9465 const mDNSu8
*const trans
= p
+ 14 + (v4
->vlen
& 0xF) * 4;
9466 const mDNSu8
*const required
= trans
+ (v4
->protocol
== 1 ? 4 : v4
->protocol
== 6 ? 20 : v4
->protocol
== 17 ? 8 : 0);
9467 debugf("Got IPv4 from %.4a to %.4a", &v4
->src
, &v4
->dst
);
9468 if (end
>= required
)
9470 #define SSH_AsNumber 22
9471 #define ARD_AsNumber 3283
9472 static const mDNSIPPort SSH
= { { SSH_AsNumber
>> 8, SSH_AsNumber
& 0xFF } };
9473 static const mDNSIPPort ARD
= { { ARD_AsNumber
>> 8, ARD_AsNumber
& 0xFF } };
9475 mDNSBool wake
= mDNSfalse
;
9476 mDNSIPPort port
= zeroIPPort
;
9478 switch (v4
->protocol
)
9480 #define XX wake ? "Received" : "Ignoring", end-p
9481 case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX
, &v4
->src
, &v4
->dst
);
9485 const TCPHeader
*const tcp
= (const TCPHeader
*)trans
;
9489 // (a) RST is not set, AND
9490 // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
9491 wake
= (!(tcp
->flags
& 4) && (tcp
->flags
& 3) != 1);
9493 // For now, to reduce spurious wakeups, we wake only for TCP SYN,
9494 // except for ssh connections, where we'll wake for plain data packets too
9495 if (!mDNSSameIPPort(port
, SSH
) && !(tcp
->flags
& 2)) wake
= mDNSfalse
;
9497 LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX
,
9498 &v4
->src
, mDNSVal16(tcp
->src
), &v4
->dst
, mDNSVal16(port
),
9499 (tcp
->flags
& 2) ? " SYN" : "",
9500 (tcp
->flags
& 1) ? " FIN" : "",
9501 (tcp
->flags
& 4) ? " RST" : "");
9506 const UDPHeader
*const udp
= (const UDPHeader
*)trans
;
9507 const mDNSu16 udplen
= (mDNSu16
)((mDNSu16
)trans
[4] << 8 | trans
[5]); // Length *including* 8-byte UDP header
9508 if (udplen
>= sizeof(UDPHeader
))
9510 const mDNSu16 datalen
= udplen
- sizeof(UDPHeader
);
9514 // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling
9515 if (mDNSSameIPPort(port
, IPSECPort
))
9517 // Specifically ignore NAT keepalive packets
9518 if (datalen
== 1 && end
>= trans
+ 9 && trans
[8] == 0xFF) wake
= mDNSfalse
;
9521 // Skip over the Non-ESP Marker if present
9522 const mDNSBool NonESP
= (end
>= trans
+ 12 && trans
[8] == 0 && trans
[9] == 0 && trans
[10] == 0 && trans
[11] == 0);
9523 const IKEHeader
*const ike
= (IKEHeader
*)(trans
+ (NonESP
? 12 : 8));
9524 const mDNSu16 ikelen
= datalen
- (NonESP
? 4 : 0);
9525 if (ikelen
>= sizeof(IKEHeader
) && end
>= ((mDNSu8
*)ike
) + sizeof(IKEHeader
))
9526 if ((ike
->Version
& 0x10) == 0x10)
9528 // ExchangeType == 5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt>
9529 // ExchangeType == 34 means 'IKE_SA_INIT' <http://www.iana.org/assignments/ikev2-parameters>
9530 if (ike
->ExchangeType
== 5 || ike
->ExchangeType
== 34) wake
= mDNSfalse
;
9531 LogSPS("%s %d-byte IKE ExchangeType %d", XX
, ike
->ExchangeType
);
9536 // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
9537 // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
9538 // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
9539 // UDP header (8 bytes)
9540 // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total
9541 if (mDNSSameIPPort(port
, ARD
)) wake
= (datalen
>= 110 && end
>= trans
+10 && trans
[8] == 0x13 && trans
[9] == 0x88);
9543 LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX
, &v4
->src
, mDNSVal16(udp
->src
), &v4
->dst
, mDNSVal16(port
));
9548 default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX
, v4
->protocol
, &v4
->src
, &v4
->dst
);
9554 AuthRecord
*rr
, *r2
;
9557 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
9558 if (rr
->resrec
.InterfaceID
== InterfaceID
&&
9559 rr
->AddressProxy
.type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->AddressProxy
.ip
.v4
, v4
->dst
))
9561 const mDNSu8
*const tp
= (v4
->protocol
== 6) ? (const mDNSu8
*)"\x4_tcp" : (const mDNSu8
*)"\x4_udp";
9562 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
9563 if (r2
->resrec
.InterfaceID
== InterfaceID
&& mDNSSameEthAddress(&r2
->WakeUp
.HMAC
, &rr
->WakeUp
.HMAC
) &&
9564 r2
->resrec
.rrtype
== kDNSType_SRV
&& mDNSSameIPPort(r2
->resrec
.rdata
->u
.srv
.port
, port
) &&
9565 SameDomainLabel(ThirdLabel(r2
->resrec
.name
)->c
, tp
))
9567 if (!r2
&& mDNSSameIPPort(port
, IPSECPort
)) r2
= rr
; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
9568 char *ifname
= InterfaceNameForID(m
, rr
->resrec
.InterfaceID
);
9569 if (!ifname
) ifname
= "<NULL InterfaceID>";
9572 rr
->AnnounceCount
= 0;
9573 LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
9574 ifname
, &v4
->dst
, &rr
->WakeUp
.HMAC
, &rr
->WakeUp
.IMAC
, ARDisplayString(m
, r2
));
9575 SendWakeup(m
, rr
->resrec
.InterfaceID
, &rr
->WakeUp
.IMAC
, &rr
->WakeUp
.password
);
9578 LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
9579 ifname
, &v4
->dst
, &rr
->WakeUp
.HMAC
, tp
, mDNSVal16(port
));
9585 else if (end
>= p
+34 && mDNSSameOpaque16(eth
->ethertype
, Ethertype_IP
) && (v4
->flagsfrags
.b
[0] & 0x1F) == 0 && v4
->flagsfrags
.b
[1] == 0)
9587 debugf("Got IPv6 from %.16a to %.16a", &v4
->src
, &v6
->dst
);
9592 mDNSlocal
void ConstructSleepProxyServerName(mDNS
*const m
, domainlabel
*name
)
9594 name
->c
[0] = mDNS_snprintf((char*)name
->c
+1, 62, "%d-%d-%d-%d %#s",
9595 m
->SPSType
, m
->SPSPortability
, m
->SPSMarginalPower
, m
->SPSTotalPower
, &m
->nicelabel
);
9598 mDNSlocal
void SleepProxyServerCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
9600 if (result
== mStatus_NameConflict
)
9601 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
9602 else if (result
== mStatus_MemFree
)
9608 m
->SPSState
= (m
->SPSSocket
!= mDNSNULL
);
9612 ConstructSleepProxyServerName(m
, &name
);
9613 mDNS_RegisterService(m
, srs
,
9614 &name
, &SleepProxyServiceType
, &localdomain
,
9615 mDNSNULL
, m
->SPSSocket
->port
, // Host, port
9616 (mDNSu8
*)"", 1, // TXT data, length
9617 mDNSNULL
, 0, // Subtypes (none)
9618 mDNSInterface_Any
, // Interface ID
9619 SleepProxyServerCallback
, mDNSNULL
); // Callback and context
9621 LogSPS("Sleep Proxy Server %#s %s", srs
->RR_SRV
.resrec
.name
->c
, m
->SPSState
? "started" : "stopped");
9626 mDNSexport
void mDNSCoreBeSleepProxyServer(mDNS
*const m
, mDNSu8 sps
, mDNSu8 port
, mDNSu8 marginalpower
, mDNSu8 totpower
)
9628 // If turning off SPS, close our socket
9629 // (Do this first, BEFORE calling mDNS_DeregisterService below)
9630 if (!sps
&& m
->SPSSocket
) { mDNSPlatformUDPClose(m
->SPSSocket
); m
->SPSSocket
= mDNSNULL
; }
9632 // If turning off, or changing type, deregister old name
9633 if (m
->SPSState
== 1 && sps
!= m
->SPSType
)
9634 { m
->SPSState
= 2; mDNS_DeregisterService(m
, &m
->SPSRecords
); }
9636 // Record our new SPS parameters
9638 m
->SPSPortability
= port
;
9639 m
->SPSMarginalPower
= marginalpower
;
9640 m
->SPSTotalPower
= totpower
;
9642 // If turning on, open socket and advertise service
9647 m
->SPSSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
9648 if (!m
->SPSSocket
) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
9650 if (m
->SPSState
== 0) SleepProxyServerCallback(m
, &m
->SPSRecords
, mStatus_MemFree
);
9654 // ***************************************************************************
9655 #if COMPILER_LIKES_PRAGMA_MARK
9657 #pragma mark - Startup and Shutdown
9660 mDNSlocal
void mDNS_GrowCache_internal(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9662 if (storage
&& numrecords
)
9665 debugf("Adding cache storage for %d more records (%d bytes)", numrecords
, numrecords
*sizeof(CacheEntity
));
9666 for (i
=0; i
<numrecords
; i
++) storage
[i
].next
= &storage
[i
+1];
9667 storage
[numrecords
-1].next
= m
->rrcache_free
;
9668 m
->rrcache_free
= storage
;
9669 m
->rrcache_size
+= numrecords
;
9673 mDNSexport
void mDNS_GrowCache(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
9676 mDNS_GrowCache_internal(m
, storage
, numrecords
);
9680 mDNSexport mStatus
mDNS_Init(mDNS
*const m
, mDNS_PlatformSupport
*const p
,
9681 CacheEntity
*rrcachestorage
, mDNSu32 rrcachesize
,
9682 mDNSBool AdvertiseLocalAddresses
, mDNSCallback
*Callback
, void *Context
)
9688 if (!rrcachestorage
) rrcachesize
= 0;
9692 m
->CanReceiveUnicastOn5353
= mDNSfalse
; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
9693 m
->AdvertiseLocalAddresses
= AdvertiseLocalAddresses
;
9694 m
->DivertMulticastAdvertisements
= mDNSfalse
;
9695 m
->mDNSPlatformStatus
= mStatus_Waiting
;
9696 m
->UnicastPort4
= zeroIPPort
;
9697 m
->UnicastPort6
= zeroIPPort
;
9698 m
->PrimaryMAC
= zeroEthAddr
;
9699 m
->MainCallback
= Callback
;
9700 m
->MainContext
= Context
;
9701 m
->rec
.r
.resrec
.RecordType
= 0;
9703 // For debugging: To catch and report locking failures
9705 m
->mDNS_reentrancy
= 0;
9706 m
->ShutdownTime
= 0;
9707 m
->lock_rrcache
= 0;
9708 m
->lock_Questions
= 0;
9709 m
->lock_Records
= 0;
9711 // Task Scheduling variables
9712 result
= mDNSPlatformTimeInit();
9713 if (result
!= mStatus_NoError
) return(result
);
9714 m
->timenow_adjust
= (mDNSs32
)mDNSRandom(0xFFFFFFFF);
9715 timenow
= mDNS_TimeNow_NoLock(m
);
9717 m
->timenow
= 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
9718 m
->timenow_last
= timenow
;
9719 m
->NextScheduledEvent
= timenow
;
9720 m
->SuppressSending
= timenow
;
9721 m
->NextCacheCheck
= timenow
+ 0x78000000;
9722 m
->NextScheduledQuery
= timenow
+ 0x78000000;
9723 m
->NextScheduledProbe
= timenow
+ 0x78000000;
9724 m
->NextScheduledResponse
= timenow
+ 0x78000000;
9725 m
->NextScheduledNATOp
= timenow
+ 0x78000000;
9726 m
->NextScheduledSPS
= timenow
+ 0x78000000;
9727 m
->RandomQueryDelay
= 0;
9728 m
->RandomReconfirmDelay
= 0;
9730 m
->SleepState
= SleepState_Awake
;
9732 m
->SystemWakeOnLANEnabled
= mDNSfalse
;
9733 m
->SentSleepProxyRegistration
= mDNSfalse
;
9734 m
->AnnounceOwner
= 0;
9738 // These fields only required for mDNS Searcher...
9739 m
->Questions
= mDNSNULL
;
9740 m
->NewQuestions
= mDNSNULL
;
9741 m
->CurrentQuestion
= mDNSNULL
;
9742 m
->LocalOnlyQuestions
= mDNSNULL
;
9743 m
->NewLocalOnlyQuestions
= mDNSNULL
;
9744 m
->rrcache_size
= 0;
9745 m
->rrcache_totalused
= 0;
9746 m
->rrcache_active
= 0;
9747 m
->rrcache_report
= 10;
9748 m
->rrcache_free
= mDNSNULL
;
9750 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++) m
->rrcache_hash
[slot
] = mDNSNULL
;
9752 mDNS_GrowCache_internal(m
, rrcachestorage
, rrcachesize
);
9754 // Fields below only required for mDNS Responder...
9755 m
->hostlabel
.c
[0] = 0;
9756 m
->nicelabel
.c
[0] = 0;
9757 m
->MulticastHostname
.c
[0] = 0;
9758 m
->HIHardware
.c
[0] = 0;
9759 m
->HISoftware
.c
[0] = 0;
9760 m
->ResourceRecords
= mDNSNULL
;
9761 m
->DuplicateRecords
= mDNSNULL
;
9762 m
->NewLocalRecords
= mDNSNULL
;
9763 m
->CurrentRecord
= mDNSNULL
;
9764 m
->HostInterfaces
= mDNSNULL
;
9765 m
->ProbeFailTime
= 0;
9766 m
->NumFailedProbes
= 0;
9767 m
->SuppressProbes
= 0;
9769 #ifndef UNICAST_DISABLED
9770 m
->NextuDNSEvent
= timenow
+ 0x78000000;
9771 m
->NextSRVUpdate
= timenow
+ 0x78000000;
9772 m
->SuppressStdPort53Queries
= 0;
9774 m
->ServiceRegistrations
= mDNSNULL
;
9775 m
->DNSServers
= mDNSNULL
;
9777 m
->Router
= zeroAddr
;
9778 m
->AdvertisedV4
= zeroAddr
;
9779 m
->AdvertisedV6
= zeroAddr
;
9781 m
->AuthInfoList
= mDNSNULL
;
9783 m
->ReverseMap
.ThisQInterval
= -1;
9784 m
->StaticHostname
.c
[0] = 0;
9786 m
->Hostnames
= mDNSNULL
;
9787 m
->AutoTunnelHostAddr
.b
[0] = 0;
9788 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
9789 m
->AutoTunnelLabel
.c
[0] = 0;
9791 m
->RegisterSearchDomains
= mDNSfalse
;
9793 // NAT traversal fields
9794 m
->NATTraversals
= mDNSNULL
;
9795 m
->CurrentNATTraversal
= mDNSNULL
;
9796 m
->retryIntervalGetAddr
= 0; // delta between time sent and retry
9797 m
->retryGetAddr
= timenow
+ 0x78000000; // absolute time when we retry
9798 m
->ExternalAddress
= zerov4Addr
;
9800 m
->NATMcastRecvskt
= mDNSNULL
;
9801 m
->LastNATupseconds
= 0;
9802 m
->LastNATReplyLocalTime
= timenow
;
9803 m
->LastNATMapResultCode
= NATErr_None
;
9805 m
->UPnPInterfaceID
= 0;
9806 m
->SSDPSocket
= mDNSNULL
;
9807 m
->SSDPWANPPPConnection
= mDNSfalse
;
9808 m
->UPnPRouterPort
= zeroIPPort
;
9809 m
->UPnPSOAPPort
= zeroIPPort
;
9810 m
->UPnPRouterURL
= mDNSNULL
;
9811 m
->UPnPWANPPPConnection
= mDNSfalse
;
9812 m
->UPnPSOAPURL
= mDNSNULL
;
9813 m
->UPnPRouterAddressString
= mDNSNULL
;
9814 m
->UPnPSOAPAddressString
= mDNSNULL
;
9816 m
->SPSPortability
= 0;
9817 m
->SPSMarginalPower
= 0;
9818 m
->SPSTotalPower
= 0;
9820 m
->SPSProxyListChanged
= mDNSNULL
;
9821 m
->SPSSocket
= mDNSNULL
;
9822 m
->SPSBrowseCallback
= mDNSNULL
;
9823 m
->ProxyRecords
= 0;
9827 #if APPLE_OSX_mDNSResponder
9828 m
->TunnelClients
= mDNSNULL
;
9831 result
= mDNSPlatformInit(m
);
9833 #ifndef UNICAST_DISABLED
9834 // It's better to do this *after* the platform layer has set up the
9835 // interface list and security credentials
9836 uDNS_SetupDNSConfig(m
); // Get initial DNS configuration
9842 mDNSexport
void mDNS_ConfigChanged(mDNS
*const m
)
9844 if (m
->SPSState
== 1)
9846 domainlabel name
, newname
;
9847 domainname type
, domain
;
9848 DeconstructServiceName(m
->SPSRecords
.RR_SRV
.resrec
.name
, &name
, &type
, &domain
);
9849 ConstructSleepProxyServerName(m
, &newname
);
9850 if (!SameDomainLabelCS(name
.c
, newname
.c
))
9852 LogSPS("Renaming SPS from “%#s” to “%#s”", name
.c
, newname
.c
);
9853 // When SleepProxyServerCallback gets the mStatus_MemFree message,
9854 // it will reregister the service under the new name
9856 mDNS_DeregisterService(m
, &m
->SPSRecords
);
9860 if (m
->MainCallback
)
9861 m
->MainCallback(m
, mStatus_ConfigChanged
);
9864 mDNSlocal
void DynDNSHostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
9867 debugf("NameStatusCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
9868 mDNSPlatformDynDNSHostNameStatusChanged(rr
->resrec
.name
, result
);
9871 mDNSlocal
void PurgeOrReconfirmCacheRecord(mDNS
*const m
, CacheRecord
*cr
, const DNSServer
* const ptr
, mDNSBool lameduck
)
9873 mDNSBool purge
= cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
||
9874 cr
->resrec
.rrtype
== kDNSType_A
||
9875 cr
->resrec
.rrtype
== kDNSType_AAAA
||
9876 cr
->resrec
.rrtype
== kDNSType_SRV
;
9880 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
));
9882 if (purge
) mDNS_PurgeCacheResourceRecord(m
, cr
);
9883 else mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
9886 mDNSexport mStatus
uDNS_SetupDNSConfig(mDNS
*const m
)
9894 DNSServer
*ptr
, **p
= &m
->DNSServers
;
9895 const DNSServer
*oldServers
= m
->DNSServers
;
9898 debugf("uDNS_SetupDNSConfig: entry");
9900 if (m
->RegisterSearchDomains
) uDNS_RegisterSearchDomains(m
);
9904 // Let the platform layer get the current DNS information
9905 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
9906 // (no need to hit the network with domain enumeration queries until we actually need that information).
9907 for (ptr
= m
->DNSServers
; ptr
; ptr
= ptr
->next
)
9909 ptr
->penaltyTime
= 0;
9910 ptr
->flags
|= DNSServer_FlagDelete
;
9913 mDNSPlatformSetDNSConfig(m
, mDNStrue
, mDNSfalse
, &fqdn
, mDNSNULL
, mDNSNULL
);
9915 // Update our qDNSServer pointers before we go and free the DNSServer object memory
9916 for (q
= m
->Questions
; q
; q
=q
->next
)
9917 if (!mDNSOpaque16IsZero(q
->TargetQID
))
9919 DNSServer
*s
= GetServerForName(m
, &q
->qname
, mDNSNULL
);
9920 DNSServer
*t
= q
->qDNSServer
;
9923 // If DNS Server for this question has changed, reactivate it
9924 debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
9925 t
, t
? &t
->addr
: mDNSNULL
, mDNSVal16(t
? t
->port
: zeroIPPort
), t
? t
->domain
.c
: (mDNSu8
*)"",
9926 s
, s
? &s
->addr
: mDNSNULL
, mDNSVal16(s
? s
->port
: zeroIPPort
), s
? s
->domain
.c
: (mDNSu8
*)"",
9927 q
->qname
.c
, DNSTypeName(q
->qtype
));
9929 q
->unansweredQueries
= 0;
9931 // Change the query ID so that we won't cache responses to any in-flight queries
9932 q
->TargetQID
= mDNS_NewMessageID(m
);
9934 ActivateUnicastQuery(m
, q
, mDNStrue
);
9938 // Flush all records that match a new resolver
9939 FORALL_CACHERECORDS(slot
, cg
, cr
)
9941 if (cr
->resrec
.InterfaceID
) continue;
9942 ptr
= GetServerForName(m
, cr
->resrec
.name
, mDNSNULL
);
9943 if (ptr
&& (ptr
->flags
& DNSServer_FlagNew
))
9944 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNSfalse
);
9949 if (((*p
)->flags
& DNSServer_FlagDelete
) != 0)
9951 // Scan our cache, looking for uDNS records that we would have queried this server for.
9952 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
9953 // different DNS servers can give different answers to the same question.
9955 ptr
->flags
&= ~DNSServer_FlagDelete
; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
9956 FORALL_CACHERECORDS(slot
, cg
, cr
)
9957 if (!cr
->resrec
.InterfaceID
&& GetServerForName(m
, cr
->resrec
.name
, mDNSNULL
) == ptr
)
9958 PurgeOrReconfirmCacheRecord(m
, cr
, ptr
, mDNStrue
);
9960 debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr
, &ptr
->addr
, mDNSVal16(ptr
->port
), ptr
->domain
.c
);
9961 mDNSPlatformMemFree(ptr
);
9965 (*p
)->flags
&= ~DNSServer_FlagNew
;
9970 // 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).
9971 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
9972 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
9973 // 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.
9974 if ((m
->DNSServers
!= mDNSNULL
) != (oldServers
!= mDNSNULL
))
9977 FORALL_CACHERECORDS(slot
, cg
, cr
) if (!cr
->resrec
.InterfaceID
) { mDNS_PurgeCacheResourceRecord(m
, cr
); count
++; }
9978 LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
9979 m
->DNSServers
? "DNS server became" : "No DNS servers", count
);
9981 // Force anything that needs to get zone data to get that information again
9982 RestartRecordGetZoneData(m
);
9985 // Did our FQDN change?
9986 if (!SameDomainName(&fqdn
, &m
->FQDN
))
9988 if (m
->FQDN
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &m
->FQDN
);
9990 AssignDomainName(&m
->FQDN
, &fqdn
);
9994 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
9995 mDNS_AddDynDNSHostName(m
, &m
->FQDN
, DynDNSHostNameCallback
, mDNSNULL
);
10001 // handle router and primary interface changes
10002 v4
= v6
= r
= zeroAddr
;
10003 v4
.type
= r
.type
= mDNSAddrType_IPv4
;
10005 if (mDNSPlatformGetPrimaryInterface(m
, &v4
, &v6
, &r
) == mStatus_NoError
&& !mDNSv4AddressIsLinkLocal(&v4
.ip
.v4
))
10007 mDNS_SetPrimaryInterfaceInfo(m
,
10008 !mDNSIPv4AddressIsZero(v4
.ip
.v4
) ? &v4
: mDNSNULL
,
10009 !mDNSIPv6AddressIsZero(v6
.ip
.v6
) ? &v6
: mDNSNULL
,
10010 !mDNSIPv4AddressIsZero(r
.ip
.v4
) ? &r
: mDNSNULL
);
10014 mDNS_SetPrimaryInterfaceInfo(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
10015 if (m
->FQDN
.c
[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1); // Set status to 1 to indicate temporary failure
10018 return mStatus_NoError
;
10021 mDNSexport
void mDNSCoreInitComplete(mDNS
*const m
, mStatus result
)
10023 m
->mDNSPlatformStatus
= result
;
10024 if (m
->MainCallback
)
10027 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
10028 m
->MainCallback(m
, mStatus_NoError
);
10029 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
10034 extern ServiceRecordSet
*CurrentServiceRecordSet
;
10036 mDNSlocal
void DeregLoop(mDNS
*const m
, AuthRecord
*const start
)
10038 m
->CurrentRecord
= start
;
10039 while (m
->CurrentRecord
)
10041 AuthRecord
*rr
= m
->CurrentRecord
;
10042 if (rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
10044 LogInfo("DeregLoop: Deregistering %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
10045 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
10047 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
10048 // the list may have been changed in that call.
10049 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not advanced for us, do it now
10050 m
->CurrentRecord
= rr
->next
;
10054 mDNSexport
void mDNS_StartExit(mDNS
*const m
)
10056 NetworkInterfaceInfo
*intf
;
10061 m
->ShutdownTime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
10063 mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
10064 mDNSCoreBeSleepProxyServer(m
, 0, 0, 0, 0);
10065 mDNS_ReclaimLockAfterCallback();
10067 #ifndef UNICAST_DISABLED
10071 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
10072 // because we deregister all records and services later in this routine
10073 while (m
->Hostnames
) mDNS_RemoveDynDNSHostName(m
, &m
->Hostnames
->fqdn
);
10075 // For each member of our SearchList, deregister any records it may have created, and cut them from the list.
10076 // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
10077 // and we may crash because the list still contains dangling pointers.
10078 for (s
= SearchList
; s
; s
= s
->next
)
10079 while (s
->AuthRecs
)
10081 ARListElem
*dereg
= s
->AuthRecs
;
10082 s
->AuthRecs
= s
->AuthRecs
->next
;
10083 mDNS_Deregister_internal(m
, &dereg
->ar
, mDNS_Dereg_normal
); // Memory will be freed in the FreeARElemCallback
10088 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
10089 if (intf
->Advertise
)
10090 DeadvertiseInterface(m
, intf
);
10092 // Shut down all our active NAT Traversals
10093 while (m
->NATTraversals
)
10095 NATTraversalInfo
*t
= m
->NATTraversals
;
10096 mDNS_StopNATOperation_internal(m
, t
); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
10098 // After stopping the NAT Traversal, we zero out the fields.
10099 // This has particularly important implications for our AutoTunnel records --
10100 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
10101 // handlers to just turn around and attempt to re-register those same records.
10102 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
10103 t
->ExternalAddress
= zerov4Addr
;
10104 t
->ExternalPort
= zeroIPPort
;
10106 t
->Result
= mStatus_NoError
;
10109 // Make sure there are nothing but deregistering records remaining in the list
10110 if (m
->CurrentRecord
)
10111 LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
10113 // We're in the process of shutting down, so queries, etc. are no longer available.
10114 // Consequently, determining certain information, e.g. the uDNS update server's IP
10115 // address, will not be possible. The records on the main list are more likely to
10116 // already contain such information, so we deregister the duplicate records first.
10117 LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
10118 DeregLoop(m
, m
->DuplicateRecords
);
10119 LogInfo("mDNS_StartExit: Deregistering resource records");
10120 DeregLoop(m
, m
->ResourceRecords
);
10122 // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
10123 // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
10124 if (m
->NextScheduledResponse
- m
->timenow
< mDNSPlatformOneSecond
)
10126 m
->NextScheduledResponse
= m
->timenow
;
10127 m
->SuppressSending
= 0;
10130 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
10131 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
10132 while (CurrentServiceRecordSet
)
10134 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
10135 LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs
->RR_SRV
.resrec
.name
->c
);
10136 uDNS_DeregisterService(m
, srs
);
10137 if (CurrentServiceRecordSet
== srs
)
10138 CurrentServiceRecordSet
= srs
->uDNS_next
;
10142 if (m
->ResourceRecords
) LogInfo("mDNS_StartExit: Sending final record deregistrations");
10143 else LogInfo("mDNS_StartExit: No deregistering records remain");
10145 if (m
->ServiceRegistrations
) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
10146 else LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
10148 for (rr
= m
->DuplicateRecords
; rr
; rr
= rr
->next
)
10149 LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
10151 // If any deregistering records remain, send their deregistration announcements before we exit
10152 if (m
->mDNSPlatformStatus
!= mStatus_NoError
) DiscardDeregistrations(m
);
10156 LogInfo("mDNS_StartExit: done");
10159 mDNSexport
void mDNS_FinalExit(mDNS
*const m
)
10161 mDNSu32 rrcache_active
= 0;
10162 mDNSu32 rrcache_totalused
= 0;
10165 ServiceRecordSet
*srs
;
10167 LogInfo("mDNS_FinalExit: mDNSPlatformClose");
10168 mDNSPlatformClose(m
);
10170 rrcache_totalused
= m
->rrcache_totalused
;
10171 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
10173 while (m
->rrcache_hash
[slot
])
10175 CacheGroup
*cg
= m
->rrcache_hash
[slot
];
10176 while (cg
->members
)
10178 CacheRecord
*cr
= cg
->members
;
10179 cg
->members
= cg
->members
->next
;
10180 if (cr
->CRActiveQuestion
) rrcache_active
++;
10181 ReleaseCacheRecord(m
, cr
);
10183 cg
->rrcache_tail
= &cg
->members
;
10184 ReleaseCacheGroup(m
, &m
->rrcache_hash
[slot
]);
10187 debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused
, rrcache_active
);
10188 if (rrcache_active
!= m
->rrcache_active
)
10189 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active
, m
->rrcache_active
);
10191 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
10192 LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr
, rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
10194 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
10195 LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs
, srs
->RR_SRV
.resrec
.name
->c
);
10197 LogInfo("mDNS_FinalExit: done");