]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/mDNS.c
mDNSResponder-214.tar.gz
[apple/mdnsresponder.git] / mDNSCore / mDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here.
19 *
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform).
24
25 * Formatting notes:
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37
38 Change History (most recent first):
39
40 $Log: mDNS.c,v $
41 Revision 1.970.2.1 2009/07/23 23:36:04 cheshire
42 <rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
43
44 Revision 1.970 2009/07/11 01:59:27 cheshire
45 <rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
46 When going to sleep, try calling ActivateLocalProxy before registering with remote sleep proxy
47
48 Revision 1.969 2009/06/30 21:18:19 cheshire
49 <rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
50 Additional fixes:
51 1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
52 2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
53
54 Revision 1.968 2009/06/29 23:51:09 cheshire
55 <rdar://problem/6690034> Can't bind to Active Directory
56
57 Revision 1.967 2009/06/27 00:25:27 cheshire
58 <rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
59 Removed overly-complicate and ineffective multi-packet known-answer snooping code
60 (Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
61
62 Revision 1.966 2009/06/26 01:55:55 cheshire
63 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
64 Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
65 add additional NSEC records only when there's space to do that without having to generate an additional packet
66
67 Revision 1.965 2009/06/24 22:14:21 cheshire
68 <rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
69
70 Revision 1.964 2009/06/03 23:07:13 cheshire
71 <rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
72 Large records were not being added in cases where an NSEC record was also required
73
74 Revision 1.963 2009/05/28 00:39:19 cheshire
75 <rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
76 After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
77
78 Revision 1.962 2009/05/19 23:40:37 cheshire
79 <rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
80 Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
81
82 Revision 1.961 2009/05/19 23:00:43 cheshire
83 Improved comments and debugging messages
84
85 Revision 1.960 2009/05/13 17:25:33 mkrochma
86 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
87 Sleep proxy client should only look for services being advertised via Multicast
88
89 Revision 1.959 2009/05/12 23:10:31 cheshire
90 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
91 Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
92
93 Revision 1.958 2009/05/12 19:19:20 cheshire
94 <rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
95
96 Revision 1.957 2009/05/07 23:56:25 cheshire
97 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
98 To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
99
100 Revision 1.956 2009/05/07 23:46:27 cheshire
101 <rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
102
103 Revision 1.955 2009/05/07 23:40:54 cheshire
104 Minor code rearrangement in preparation for upcoming changes
105
106 Revision 1.954 2009/05/01 21:28:34 cheshire
107 <rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
108 No longer suspend network operations after we've acknowledged that the machine is going to sleep,
109 because other software may not have yet acknowledged the sleep event, and may be still trying
110 to do unicast DNS queries or other Bonjour operations.
111
112 Revision 1.953 2009/05/01 19:17:35 cheshire
113 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
114
115 Revision 1.952 2009/05/01 19:16:45 mcguire
116 <rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
117
118 Revision 1.951 2009/04/28 23:48:19 jessic2
119 <rdar://problem/6830541> regservice_callback: instance->request is NULL 0
120
121 Revision 1.950 2009/04/25 01:17:10 mcguire
122 Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
123
124 Revision 1.949 2009/04/25 01:11:02 mcguire
125 Refactor: create separate function: RestartRecordGetZoneData
126
127 Revision 1.948 2009/04/24 21:25:16 cheshire
128 <rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
129
130 Revision 1.947 2009/04/24 19:41:12 mcguire
131 <rdar://problem/6791775> 4 second delay in DNS response
132
133 Revision 1.946 2009/04/24 19:28:39 mcguire
134 <rdar://problem/6791775> 4 second delay in DNS response
135
136 Revision 1.945 2009/04/24 00:30:30 cheshire
137 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
138 Added code to generate and process NSEC records
139
140 Revision 1.944 2009/04/23 22:06:29 cheshire
141 Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
142 <rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
143
144 Revision 1.943 2009/04/22 01:19:56 jessic2
145 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
146
147 Revision 1.942 2009/04/21 02:13:29 cheshire
148 <rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
149 Made code less susceptible to being tricked by stale packets echoed back from the network.
150
151 Revision 1.941 2009/04/15 22:22:23 mcguire
152 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
153 Additional fix: protect against deref of NULL
154
155 Revision 1.940 2009/04/15 20:42:51 mcguire
156 <rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
157
158 Revision 1.939 2009/04/11 00:19:32 jessic2
159 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
160
161 Revision 1.938 2009/04/06 23:44:57 cheshire
162 <rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
163
164 Revision 1.937 2009/04/04 00:14:49 mcguire
165 fix logging in BeginSleepProcessing
166
167 Revision 1.936 2009/04/04 00:10:59 mcguire
168 don't ignore m->SystemWakeOnLANEnabled when going to sleep
169
170 Revision 1.935 2009/04/01 17:50:11 mcguire
171 cleanup mDNSRandom
172
173 Revision 1.934 2009/03/27 17:17:58 cheshire
174 Improved "Ignoring suspect uDNS response" debugging message
175
176 Revision 1.933 2009/03/21 02:40:21 cheshire
177 <rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
178
179 Revision 1.932 2009/03/20 23:53:03 jessic2
180 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
181
182 Revision 1.931 2009/03/18 19:08:15 cheshire
183 Show old/new sleep sequence numbers in logical order
184
185 Revision 1.930 2009/03/17 23:40:45 cheshire
186 For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
187
188 Revision 1.929 2009/03/17 21:55:56 cheshire
189 Fixed mistake in logic for decided when we're ready to go to sleep
190
191 Revision 1.928 2009/03/17 19:48:12 cheshire
192 <rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
193
194 Revision 1.927 2009/03/17 01:22:56 cheshire
195 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
196 Initial support for resolving up to three Sleep Proxies in parallel
197
198 Revision 1.926 2009/03/17 01:05:07 mcguire
199 <rdar://problem/6657640> Reachability fixes on DNS config change
200
201 Revision 1.925 2009/03/13 01:35:36 mcguire
202 <rdar://problem/6657640> Reachability fixes on DNS config change
203
204 Revision 1.924 2009/03/10 23:45:20 cheshire
205 Added comments explaining usage of SetSPSProxyListChanged()
206
207 Revision 1.923 2009/03/09 21:53:02 cheshire
208 <rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
209
210 Revision 1.922 2009/03/09 21:30:17 cheshire
211 Improved some LogSPS messages; made RestartProbing() subroutine
212
213 Revision 1.921 2009/03/06 22:53:31 cheshire
214 Don't bother registering with Sleep Proxy if we have no advertised services
215
216 Revision 1.920 2009/03/06 20:08:55 cheshire
217 <rdar://problem/6601429> Sleep Proxy: Return error responses to clients
218
219 Revision 1.919 2009/03/05 21:54:43 cheshire
220 Improved "Sleep Proxy Server started / stopped" message
221
222 Revision 1.918 2009/03/04 01:37:14 cheshire
223 <rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
224
225 Revision 1.917 2009/03/03 23:14:25 cheshire
226 Got rid of code duplication by making subroutine "SetupOwnerOpt"
227
228 Revision 1.916 2009/03/03 23:04:43 cheshire
229 For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
230
231 Revision 1.915 2009/03/03 22:51:53 cheshire
232 <rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
233
234 Revision 1.914 2009/03/03 00:46:09 cheshire
235 Additional debugging information in ResolveSimultaneousProbe
236
237 Revision 1.913 2009/02/27 03:08:47 cheshire
238 <rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
239
240 Revision 1.912 2009/02/27 02:31:28 cheshire
241 Improved "Record not found in list" debugging message
242
243 Revision 1.911 2009/02/21 01:42:11 cheshire
244 Updated log messages
245
246 Revision 1.910 2009/02/19 01:50:53 cheshire
247 Converted some LogInfo messages to LogSPS
248
249 Revision 1.909 2009/02/14 00:04:59 cheshire
250 Left-justify interface names
251
252 Revision 1.908 2009/02/13 19:40:07 cheshire
253 Improved alignment of LogSPS messages
254
255 Revision 1.907 2009/02/13 18:16:05 cheshire
256 Fixed some compile warnings
257
258 Revision 1.906 2009/02/13 06:10:17 cheshire
259 Convert LogOperation messages to LogInfo
260
261 Revision 1.905 2009/02/12 20:57:24 cheshire
262 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
263
264 Revision 1.904 2009/02/11 02:37:29 cheshire
265 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
266 Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
267 so that it happens correctly even when we delay re-sleep due to a very short wakeup.
268
269 Revision 1.903 2009/02/09 23:34:31 cheshire
270 Additional logging for debugging unknown packets
271
272 Revision 1.902 2009/02/07 05:57:01 cheshire
273 Fixed debugging log message
274
275 Revision 1.901 2009/02/07 02:57:31 cheshire
276 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
277
278 Revision 1.900 2009/02/02 21:29:24 cheshire
279 <rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
280 If Negative response for our special Microsoft Active Directory "local SOA" check has no
281 SOA record in the authority section, assume we should cache the negative result for 24 hours
282
283 Revision 1.899 2009/01/31 00:37:50 cheshire
284 When marking cache records for deletion in response to a uDNS response,
285 make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
286
287 Revision 1.898 2009/01/30 23:49:20 cheshire
288 Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
289
290 Revision 1.897 2009/01/30 22:04:49 cheshire
291 Workaround to reduce load on root name servers when caching the SOA record for "."
292
293 Revision 1.896 2009/01/30 22:00:05 cheshire
294 Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
295
296 Revision 1.895 2009/01/30 17:46:39 cheshire
297 Improved debugging messages for working out why spurious name conflicts are happening
298
299 Revision 1.894 2009/01/30 00:22:09 cheshire
300 <rdar://problem/6540743> No announcement after probing & no conflict notice
301
302 Revision 1.893 2009/01/29 22:27:03 mcguire
303 <rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
304
305 Revision 1.892 2009/01/24 01:38:23 cheshire
306 Fixed error in logic for targeted queries
307
308 Revision 1.891 2009/01/22 02:14:25 cheshire
309 <rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
310
311 Revision 1.890 2009/01/22 00:45:02 cheshire
312 Improved SPS debugging log messages; we are eligible to start answering ARP requests
313 after we send our first announcement, not after we send our last probe
314
315 Revision 1.889 2009/01/21 03:43:56 mcguire
316 <rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
317
318 Revision 1.888 2009/01/20 00:27:43 mcguire
319 <rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
320
321 Revision 1.887 2009/01/17 05:14:37 cheshire
322 Convert SendQueries Probe messages to LogSPS messages
323
324 Revision 1.886 2009/01/17 03:43:09 cheshire
325 Added SPSLogging switch to facilitate Sleep Proxy Server debugging
326
327 Revision 1.885 2009/01/16 22:44:18 cheshire
328 <rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
329
330 Revision 1.884 2009/01/16 21:43:52 cheshire
331 Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
332
333 Revision 1.883 2009/01/16 21:11:18 cheshire
334 When purging expired Sleep Proxy records, need to check DuplicateRecords list too
335
336 Revision 1.882 2009/01/16 19:54:28 cheshire
337 Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
338
339 Revision 1.881 2009/01/14 01:38:38 mcguire
340 <rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
341
342 Revision 1.880 2009/01/10 01:51:19 cheshire
343 q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
344
345 Revision 1.879 2009/01/10 01:43:52 cheshire
346 Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
347
348 Revision 1.878 2009/01/10 01:38:10 cheshire
349 Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
350
351 Revision 1.877 2009/01/10 01:36:08 cheshire
352 Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
353
354 Revision 1.876 2009/01/09 22:56:06 cheshire
355 Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
356
357 Revision 1.875 2009/01/09 22:54:46 cheshire
358 When tranferring record from DuplicateRecords list to ResourceRecords list,
359 need to copy across state of 'Answered Local-Only-Questions' flag
360
361 Revision 1.874 2009/01/07 23:07:24 cheshire
362 <rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
363
364 Revision 1.873 2008/12/17 00:18:59 mkrochma
365 Change some LogMsg to LogOperation before submitting
366
367 Revision 1.872 2008/12/12 01:30:40 cheshire
368 Update platform-layer BPF filters when we add or remove AddressProxy records
369
370 Revision 1.871 2008/12/10 02:25:31 cheshire
371 Minor fixes to use of LogClientOperations symbol
372
373 Revision 1.870 2008/12/10 02:11:41 cheshire
374 ARMv5 compiler doesn't like uncommented stuff after #endif
375
376 Revision 1.869 2008/12/05 02:35:24 mcguire
377 <rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
378
379 Revision 1.868 2008/12/04 21:08:51 mcguire
380 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
381
382 Revision 1.867 2008/11/26 21:19:36 cheshire
383 <rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
384
385 Revision 1.866 2008/11/26 20:32:46 cheshire
386 <rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
387 Update advertised name when Sleep Proxy "intent" metric changes
388
389 Revision 1.865 2008/11/26 19:49:25 cheshire
390 Record originally-requested port in sr->NATinfo.IntPort
391
392 Revision 1.864 2008/11/26 19:02:37 cheshire
393 Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
394
395 Revision 1.863 2008/11/26 03:59:03 cheshire
396 Wait 30 seconds before starting ARP Announcements
397
398 Revision 1.862 2008/11/25 23:43:07 cheshire
399 <rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
400 Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
401
402 Revision 1.861 2008/11/25 22:46:30 cheshire
403 For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
404
405 Revision 1.860 2008/11/25 05:07:15 cheshire
406 <rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
407
408 Revision 1.859 2008/11/20 02:07:56 cheshire
409 <rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
410
411 Revision 1.858 2008/11/20 01:38:36 cheshire
412 For consistency with other parts of the code, changed code to only check
413 that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
414
415 Revision 1.857 2008/11/14 22:55:18 cheshire
416 Fixed log messages
417
418 Revision 1.856 2008/11/14 21:08:28 cheshire
419 Only put owner option in query packet if we have a non-zero MAC address to put
420 Only process owner options in received query packets if the MAC address in the option is non-zero
421
422 Revision 1.855 2008/11/14 02:29:54 cheshire
423 If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
424
425 Revision 1.854 2008/11/14 00:00:53 cheshire
426 After client machine wakes up, Sleep Proxy machine need to remove any records
427 it was temporarily holding as proxy for that client
428
429 Revision 1.853 2008/11/13 19:07:30 cheshire
430 Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
431
432 Revision 1.852 2008/11/12 23:23:11 cheshire
433 Before waking a host, check to see if it has an SRV record advertising
434 a service on the port in question, and if not, don't bother waking it.
435
436 Revision 1.851 2008/11/12 01:54:15 cheshire
437 <rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
438 It turns out it is beneficial to have the domain on the end, because it allows better name compression
439
440 Revision 1.850 2008/11/11 01:56:57 cheshire
441 Improved name conflict log messages
442
443 Revision 1.849 2008/11/06 23:50:43 cheshire
444 Allow plain (non-SYN) ssh data packets to wake sleeping host
445
446 Revision 1.848 2008/11/05 02:40:28 mkrochma
447 Change mDNS_SetFQDN syslog mesage to debugf
448
449 Revision 1.847 2008/11/04 23:06:50 cheshire
450 Split RDataBody union definition into RDataBody and RDataBody2, and removed
451 SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
452
453 Revision 1.846 2008/11/04 22:21:44 cheshire
454 Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
455
456 Revision 1.845 2008/11/03 23:52:05 cheshire
457 Improved ARP debugging messages to differentiate ARP Announcements from Requests
458
459 Revision 1.844 2008/10/31 23:43:51 cheshire
460 Fixed compile error in Posix build
461
462 Revision 1.843 2008/10/31 22:55:04 cheshire
463 Initial support for structured SPS names
464
465 Revision 1.842 2008/10/30 00:12:07 cheshire
466 Fixed spin when PutSPSRec fails to put a record because it's too big to fit
467
468 Revision 1.841 2008/10/29 23:23:38 cheshire
469 Refined cache size reporting to go in steps of 1000 when number is above 1000
470
471 Revision 1.840 2008/10/29 21:34:10 cheshire
472 Removed some old debugging messages
473
474 Revision 1.839 2008/10/29 21:31:32 cheshire
475 Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
476
477 Revision 1.838 2008/10/28 18:30:37 cheshire
478 Added debugging message in mDNSCoreReceiveRawPacket
479
480 Revision 1.837 2008/10/24 23:58:05 cheshire
481 Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
482
483 Revision 1.836 2008/10/24 23:18:18 cheshire
484 If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
485
486 Revision 1.835 2008/10/24 23:07:59 cheshire
487 Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
488
489 Revision 1.834 2008/10/24 23:03:24 cheshire
490 Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
491
492 Revision 1.833 2008/10/24 23:01:26 cheshire
493 To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
494
495 Revision 1.832 2008/10/24 22:58:24 cheshire
496 For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
497
498 Revision 1.831 2008/10/24 22:50:41 cheshire
499 When waking SPS client, include interface name in syslog message
500
501 Revision 1.830 2008/10/24 20:50:34 cheshire
502 Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
503
504 Revision 1.829 2008/10/23 23:55:57 cheshire
505 Fixed some missing "const" declarations
506
507 Revision 1.828 2008/10/23 22:25:56 cheshire
508 Renamed field "id" to more descriptive "updateid"
509
510 Revision 1.827 2008/10/23 03:06:25 cheshire
511 Fixed "Waking host" log message
512
513 Revision 1.826 2008/10/22 23:21:30 cheshire
514 Make sure we have enough bytes before reading into the transport-level header
515
516 Revision 1.825 2008/10/22 22:31:53 cheshire
517 Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
518
519 Revision 1.824 2008/10/22 20:00:31 cheshire
520 If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
521
522 Revision 1.823 2008/10/22 19:55:35 cheshire
523 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
524
525 Revision 1.822 2008/10/22 01:41:39 cheshire
526 Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
527
528 Revision 1.821 2008/10/22 01:12:53 cheshire
529 Answer ARP Requests for any IP address we're proxying for
530
531 Revision 1.820 2008/10/21 01:11:11 cheshire
532 Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
533
534 Revision 1.819 2008/10/20 22:16:27 cheshire
535 Updated comments; increased cache shedding threshold from 3000 to 4000
536
537 Revision 1.818 2008/10/16 22:01:54 cheshire
538 Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
539
540 Revision 1.817 2008/10/16 21:40:49 cheshire
541 Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
542
543 Revision 1.816 2008/10/15 23:12:36 cheshire
544 On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
545
546 Revision 1.815 2008/10/15 20:46:38 cheshire
547 When transferring records to SPS, include Lease Option
548
549 Revision 1.814 2008/10/15 19:51:27 cheshire
550 Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
551
552 Revision 1.813 2008/10/15 00:09:23 cheshire
553 When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
554
555 Revision 1.812 2008/10/15 00:01:40 cheshire
556 When going to sleep, discover and resolve SPS, and if successful, transfer records to it
557
558 Revision 1.811 2008/10/14 23:51:57 cheshire
559 Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
560
561 Revision 1.810 2008/10/14 21:37:55 cheshire
562 Removed unnecessary m->BeSleepProxyServer variable
563
564 Revision 1.809 2008/10/10 23:45:48 cheshire
565 For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
566 not a wide-area unicast hostname
567
568 Revision 1.808 2008/10/09 18:59:19 cheshire
569 Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
570
571 Revision 1.807 2008/10/07 15:56:58 cheshire
572 Fixed "unused variable" warnings in non-debug builds
573
574 Revision 1.806 2008/10/04 00:53:37 cheshire
575 On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
576
577 Revision 1.805 2008/10/03 18:17:28 cheshire
578 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
579 Update advertised Sleep Proxy Server name if user changes computer name
580
581 Revision 1.804 2008/10/03 01:26:06 mcguire
582 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
583 Put back Duplicate Record check
584
585 Revision 1.803 2008/10/02 23:38:56 mcguire
586 <rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
587
588 Revision 1.802 2008/10/02 23:13:48 cheshire
589 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
590 Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
591
592 Revision 1.801 2008/10/02 22:51:04 cheshire
593 <rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
594 Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
595
596 Revision 1.800 2008/10/02 22:13:15 cheshire
597 <rdar://problem/6230680> 100ms delay on shutdown
598 Additional refinement: Also need to clear m->SuppressSending
599
600 Revision 1.799 2008/09/29 20:12:37 cheshire
601 Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
602
603 Revision 1.798 2008/09/26 19:53:14 cheshire
604 Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
605
606 Revision 1.797 2008/09/25 20:40:59 cheshire
607 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
608 In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
609
610 Revision 1.796 2008/09/25 20:17:10 cheshire
611 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
612 Added defensive code to make sure *all* records of a ServiceRecordSet have
613 completed deregistering before we pass on the mStatus_MemFree message
614
615 Revision 1.795 2008/09/25 00:30:11 cheshire
616 <rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
617
618 Revision 1.794 2008/09/24 23:48:05 cheshire
619 Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
620 it only needs to access the embedded SRV member of the set
621
622 Revision 1.793 2008/09/23 04:11:53 cheshire
623 <rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
624
625 Revision 1.792 2008/09/23 02:30:07 cheshire
626 Get rid of PutResourceRecordCappedTTL()
627
628 Revision 1.791 2008/09/20 00:34:21 mcguire
629 <rdar://problem/6129039> BTMM: Add support for WANPPPConnection
630
631 Revision 1.790 2008/09/18 22:46:34 cheshire
632 <rdar://problem/6230680> 100ms delay on shutdown
633
634 Revision 1.789 2008/09/18 06:15:06 mkrochma
635 <rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
636
637 Revision 1.788 2008/09/16 21:11:41 cheshire
638 <rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
639
640 Revision 1.787 2008/09/05 22:53:24 cheshire
641 Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
642
643 Revision 1.786 2008/09/05 22:23:28 cheshire
644 Moved initialization of "question->LocalSocket" to more logical place
645
646 Revision 1.785 2008/08/14 19:20:55 cheshire
647 <rdar://problem/6143846> Negative responses over TCP incorrectly rejected
648
649 Revision 1.784 2008/08/13 00:47:53 mcguire
650 Handle failures when packet logging
651
652 Revision 1.783 2008/07/25 07:09:51 mcguire
653 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
654
655 Revision 1.782 2008/07/24 20:23:03 cheshire
656 <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
657
658 Revision 1.781 2008/07/18 21:37:35 mcguire
659 <rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
660
661 Revision 1.780 2008/07/18 02:24:36 cheshire
662 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
663 Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
664 we're still on our first or second query after an interface registration or wake from sleep).
665
666 Revision 1.779 2008/07/18 01:05:23 cheshire
667 <rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
668
669 Revision 1.778 2008/06/26 17:24:11 mkrochma
670 <rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
671
672 Revision 1.777 2008/06/19 01:20:48 mcguire
673 <rdar://problem/4206534> Use all configured DNS servers
674
675 Revision 1.776 2008/04/17 20:14:14 cheshire
676 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
677
678 Revision 1.775 2008/03/26 01:53:34 mcguire
679 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
680
681 Revision 1.774 2008/03/17 17:46:08 mcguire
682 When activating an LLQ, reset all the important state and destroy any tcp connection,
683 so that everything will be restarted as if the question had just been asked.
684 Also reset servPort, so that the SOA query will be re-issued.
685
686 Revision 1.773 2008/03/14 22:52:36 mcguire
687 <rdar://problem/5321824> write status to the DS
688 Update status when any unicast LLQ is started
689
690 Revision 1.772 2008/03/06 02:48:34 mcguire
691 <rdar://problem/5321824> write status to the DS
692
693 Revision 1.771 2008/02/26 22:04:44 cheshire
694 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
695 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
696 question while it's still in our 'm->NewQuestions' section of the list
697
698 Revision 1.770 2008/02/22 23:09:02 cheshire
699 <rdar://problem/5338420> BTMM: Not processing additional records
700 Refinements:
701 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
702 2. Once we decide a record is acceptable, we can break out of the loop
703
704 Revision 1.769 2008/02/22 00:00:19 cheshire
705 <rdar://problem/5338420> BTMM: Not processing additional records
706
707 Revision 1.768 2008/02/19 23:26:50 cheshire
708 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
709
710 Revision 1.767 2007/12/22 02:25:29 cheshire
711 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
712
713 Revision 1.766 2007/12/15 01:12:27 cheshire
714 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
715
716 Revision 1.765 2007/12/15 00:18:51 cheshire
717 Renamed question->origLease to question->ReqLease
718
719 Revision 1.764 2007/12/14 00:49:53 cheshire
720 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
721 the CurrentServiceRecordSet mechanism to guard against services being deleted,
722 just like the record deregistration loop uses m->CurrentRecord.
723
724 Revision 1.763 2007/12/13 20:20:17 cheshire
725 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
726 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
727 inline a function defined in a different compilation unit) and therefore optimized better.
728
729 Revision 1.762 2007/12/13 00:13:03 cheshire
730 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
731
732 Revision 1.761 2007/12/13 00:03:31 cheshire
733 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
734
735 Revision 1.760 2007/12/08 00:36:19 cheshire
736 <rdar://problem/5636422> Updating TXT records is too slow
737 Remove unnecessary delays on announcing record updates, and on processing them on reception
738
739 Revision 1.759 2007/12/07 22:41:29 cheshire
740 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
741 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
742
743 Revision 1.758 2007/12/07 00:45:57 cheshire
744 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
745
746 Revision 1.757 2007/12/06 00:22:27 mcguire
747 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
748
749 Revision 1.756 2007/12/05 01:52:30 cheshire
750 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
751 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
752
753 Revision 1.755 2007/12/03 23:36:45 cheshire
754 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
755 Need to check GetServerForName() result is non-null before dereferencing pointer
756
757 Revision 1.754 2007/12/01 01:21:27 jgraessley
758 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
759
760 Revision 1.753 2007/12/01 00:44:15 cheshire
761 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
762
763 Revision 1.752 2007/11/14 01:10:51 cheshire
764 Fixed LogOperation() message wording
765
766 Revision 1.751 2007/10/30 23:49:41 cheshire
767 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
768 LLQ state was not being transferred properly between duplicate questions
769
770 Revision 1.750 2007/10/29 23:58:52 cheshire
771 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
772 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
773
774 Revision 1.749 2007/10/29 21:28:36 cheshire
775 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
776
777 Revision 1.748 2007/10/29 20:02:50 cheshire
778 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
779
780 Revision 1.747 2007/10/26 22:53:50 cheshire
781 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
782 instead of replicating the logic in both places
783
784 Revision 1.746 2007/10/25 22:48:50 cheshire
785 Added LogOperation message saying when we restart GetZoneData for record and service registrations
786
787 Revision 1.745 2007/10/25 20:48:47 cheshire
788 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
789
790 Revision 1.744 2007/10/25 20:06:14 cheshire
791 Don't try to do SOA queries using private DNS (TLS over TCP) queries
792
793 Revision 1.743 2007/10/25 00:12:46 cheshire
794 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
795 Retrigger service registrations whenever a new network interface is added
796
797 Revision 1.742 2007/10/24 22:40:06 cheshire
798 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
799 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
800
801 Revision 1.741 2007/10/24 00:50:29 cheshire
802 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
803 Retrigger record registrations whenever a new network interface is added
804
805 Revision 1.740 2007/10/23 00:38:03 cheshire
806 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
807 or code will spin sending the same cache expiration query repeatedly
808
809 Revision 1.739 2007/10/22 23:46:41 cheshire
810 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
811 Need to clear question->nta pointer after calling CancelGetZoneData()
812
813 Revision 1.738 2007/10/19 22:08:49 cheshire
814 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
815 Additional fixes and refinements
816
817 Revision 1.737 2007/10/18 23:06:42 cheshire
818 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
819 Additional fixes and refinements
820
821 Revision 1.736 2007/10/18 20:23:17 cheshire
822 Moved SuspendLLQs into mDNS.c, since it's only called from one place
823
824 Revision 1.735 2007/10/18 00:12:34 cheshire
825 Fixed "unused variable" compiler warning
826
827 Revision 1.734 2007/10/17 22:49:54 cheshire
828 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
829
830 Revision 1.733 2007/10/17 22:37:23 cheshire
831 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
832
833 Revision 1.732 2007/10/17 21:53:51 cheshire
834 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
835
836 Revision 1.731 2007/10/17 18:37:50 cheshire
837 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
838 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
839
840 Revision 1.730 2007/10/16 21:16:07 cheshire
841 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
842
843 Revision 1.729 2007/10/05 17:56:10 cheshire
844 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
845
846 Revision 1.728 2007/10/04 23:18:14 cheshire
847 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
848
849 Revision 1.727 2007/10/04 22:51:57 cheshire
850 Added debugging LogOperation message to show when we're sending cache expiration queries
851
852 Revision 1.726 2007/10/03 00:14:24 cheshire
853 Removed write to null to generate stack trace for SetNextQueryTime locking failure
854
855 Revision 1.725 2007/10/02 21:11:08 cheshire
856 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
857
858 Revision 1.724 2007/10/02 20:10:23 cheshire
859 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
860
861 Revision 1.723 2007/10/02 19:56:54 cheshire
862 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
863
864 Revision 1.722 2007/10/01 22:59:46 cheshire
865 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
866 Need to shut down NATTraversals on exit
867
868 Revision 1.721 2007/10/01 18:42:07 cheshire
869 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
870
871 Revision 1.720 2007/09/29 20:40:19 cheshire
872 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
873
874 Revision 1.719 2007/09/27 22:23:56 cheshire
875 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
876 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
877
878 Revision 1.718 2007/09/27 22:02:33 cheshire
879 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
880
881 Revision 1.717 2007/09/27 21:21:39 cheshire
882 Export CompleteDeregistration so it's callable from other files
883
884 Revision 1.716 2007/09/27 02:12:21 cheshire
885 Updated GrantCacheExtensions degugging message to show new record lifetime
886
887 Revision 1.715 2007/09/27 01:20:06 cheshire
888 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
889
890 Revision 1.714 2007/09/27 00:37:01 cheshire
891 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
892
893 Revision 1.713 2007/09/27 00:25:39 cheshire
894 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
895 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
896
897 Revision 1.712 2007/09/26 23:16:58 cheshire
898 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
899
900 Revision 1.711 2007/09/26 22:06:02 cheshire
901 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
902
903 Revision 1.710 2007/09/26 00:49:46 cheshire
904 Improve packet logging to show sent and received packets,
905 transport protocol (UDP/TCP/TLS) and source/destination address:port
906
907 Revision 1.709 2007/09/21 21:12:36 cheshire
908 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
909
910 Revision 1.708 2007/09/20 23:13:37 cheshire
911 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
912 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
913
914 Revision 1.707 2007/09/20 02:29:37 cheshire
915 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
916
917 Revision 1.706 2007/09/20 01:13:19 cheshire
918 Export CacheGroupForName so it's callable from other files
919
920 Revision 1.705 2007/09/20 01:12:06 cheshire
921 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
922
923 Revision 1.704 2007/09/19 22:47:25 cheshire
924 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
925
926 Revision 1.703 2007/09/14 01:46:59 cheshire
927 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
928
929 Revision 1.702 2007/09/13 22:06:46 cheshire
930 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
931 Need to accept DNS responses where the query ID field matches, even if the source address does not
932
933 Revision 1.701 2007/09/12 23:22:32 cheshire
934 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
935
936 Revision 1.700 2007/09/12 23:03:08 cheshire
937 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
938
939 Revision 1.699 2007/09/12 22:19:28 cheshire
940 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
941
942 Revision 1.698 2007/09/12 22:13:27 cheshire
943 Remove DynDNSHostNames cleanly on shutdown
944
945 Revision 1.697 2007/09/12 01:44:47 cheshire
946 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
947
948 Revision 1.696 2007/09/12 01:26:08 cheshire
949 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
950
951 Revision 1.695 2007/09/11 19:19:16 cheshire
952 Correct capitalization of "uPNP" to "UPnP"
953
954 Revision 1.694 2007/09/10 22:06:51 cheshire
955 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
956
957 Revision 1.693 2007/09/07 22:24:36 vazquez
958 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
959
960 Revision 1.692 2007/09/07 00:12:09 cheshire
961 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
962
963 Revision 1.691 2007/09/05 22:25:01 vazquez
964 <rdar://problem/5400521> update_record mDNSResponder leak
965
966 Revision 1.690 2007/09/05 21:48:01 cheshire
967 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
968 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
969 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
970 otherwise those records will expire and vanish from the cache.
971
972 Revision 1.689 2007/09/05 02:29:06 cheshire
973 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
974 Additional fixes to code implementing "NoAnswer" logic
975
976 Revision 1.688 2007/08/31 22:56:39 cheshire
977 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
978
979 Revision 1.687 2007/08/31 19:53:14 cheshire
980 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
981 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
982
983 Revision 1.686 2007/08/30 00:01:56 cheshire
984 Added comment about SetTargetToHostName()
985
986 Revision 1.685 2007/08/29 01:19:24 cheshire
987 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
988 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
989
990 Revision 1.684 2007/08/28 23:58:42 cheshire
991 Rename HostTarget -> AutoTarget
992
993 Revision 1.683 2007/08/28 23:53:21 cheshire
994 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
995
996 Revision 1.682 2007/08/27 20:28:19 cheshire
997 Improve "suspect uDNS response" log message
998
999 Revision 1.681 2007/08/24 23:37:23 cheshire
1000 Added debugging message to show when ExtraResourceRecord callback gets invoked
1001
1002 Revision 1.680 2007/08/24 00:15:19 cheshire
1003 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
1004
1005 Revision 1.679 2007/08/23 21:47:09 vazquez
1006 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
1007 make sure we clean up port mappings on base stations by sending a lease value of 0,
1008 and only send NAT-PMP packets on private networks; also save some memory by
1009 not using packet structs in NATTraversals.
1010
1011 Revision 1.678 2007/08/01 16:09:13 cheshire
1012 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
1013
1014 Revision 1.677 2007/08/01 01:58:24 cheshire
1015 Added RecordType sanity check in mDNS_Register_internal
1016
1017 Revision 1.676 2007/08/01 00:04:13 cheshire
1018 <rdar://problem/5261696> Crash in tcpKQSocketCallback
1019 Half-open TCP connections were not being cancelled properly
1020
1021 Revision 1.675 2007/07/31 02:28:35 vazquez
1022 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
1023
1024 Revision 1.674 2007/07/31 01:57:23 cheshire
1025 Adding code to respect TTL received in uDNS responses turned out to
1026 expose other problems; backing out change for now.
1027
1028 Revision 1.673 2007/07/30 23:31:26 cheshire
1029 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
1030
1031 Revision 1.672 2007/07/28 01:25:56 cheshire
1032 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
1033
1034 Revision 1.671 2007/07/27 22:32:54 cheshire
1035 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
1036 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
1037
1038 Revision 1.670 2007/07/27 20:54:43 cheshire
1039 Fixed code to respect real record TTL received in uDNS responses
1040
1041 Revision 1.669 2007/07/27 20:09:32 cheshire
1042 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
1043
1044 Revision 1.668 2007/07/27 19:58:47 cheshire
1045 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
1046
1047 Revision 1.667 2007/07/27 19:52:10 cheshire
1048 Don't increment m->rrcache_active for no-cache add events
1049
1050 Revision 1.666 2007/07/27 19:30:39 cheshire
1051 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
1052 to properly reflect tri-state nature of the possible responses
1053
1054 Revision 1.665 2007/07/27 18:44:01 cheshire
1055 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
1056
1057 Revision 1.664 2007/07/27 18:38:56 cheshire
1058 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
1059
1060 Revision 1.663 2007/07/25 03:05:02 vazquez
1061 Fixes for:
1062 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
1063 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
1064 and a myriad of other security problems
1065
1066 Revision 1.662 2007/07/24 20:22:46 cheshire
1067 Make sure all fields of main mDNS object are initialized correctly
1068
1069 Revision 1.661 2007/07/21 00:54:45 cheshire
1070 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
1071
1072 Revision 1.660 2007/07/20 20:00:45 cheshire
1073 "Legacy Browse" is better called "Automatic Browse"
1074
1075 Revision 1.659 2007/07/20 00:54:18 cheshire
1076 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
1077
1078 Revision 1.658 2007/07/18 02:28:57 cheshire
1079 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
1080
1081 Revision 1.657 2007/07/18 00:57:10 cheshire
1082 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1083 Only need to call AddNewClientTunnel() for IPv6 addresses
1084
1085 Revision 1.656 2007/07/16 23:54:48 cheshire
1086 <rdar://problem/5338850> Crash when removing or changing DNS keys
1087
1088 Revision 1.655 2007/07/16 20:11:37 vazquez
1089 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
1090 Init LNT stuff and handle SSDP packets
1091
1092 Revision 1.654 2007/07/12 23:30:23 cheshire
1093 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
1094
1095 Revision 1.653 2007/07/12 02:51:27 cheshire
1096 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1097
1098 Revision 1.652 2007/07/11 23:43:42 cheshire
1099 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
1100
1101 Revision 1.651 2007/07/11 22:44:40 cheshire
1102 <rdar://problem/5328801> SIGHUP should purge the cache
1103
1104 Revision 1.650 2007/07/11 21:34:09 cheshire
1105 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
1106 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
1107
1108 Revision 1.649 2007/07/11 02:52:52 cheshire
1109 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
1110 In uDNS_RegisterService, set HostTarget for AutoTunnel services
1111
1112 Revision 1.648 2007/07/09 23:48:12 cheshire
1113 Add parentheses around bitwise operation for clarity
1114
1115 Revision 1.647 2007/07/06 21:17:55 cheshire
1116 Initialize m->retryGetAddr to timenow + 0x78000000;
1117
1118 Revision 1.646 2007/07/06 18:55:49 cheshire
1119 Initialize m->NextScheduledNATOp
1120
1121 Revision 1.645 2007/06/29 22:55:54 cheshire
1122 Move declaration of DNSServer *s; Fixed incomplete comment.
1123
1124 Revision 1.644 2007/06/29 00:07:29 vazquez
1125 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
1126
1127 Revision 1.643 2007/06/20 01:10:12 cheshire
1128 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
1129
1130 Revision 1.642 2007/06/15 21:54:50 cheshire
1131 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
1132
1133 Revision 1.641 2007/05/25 00:30:24 cheshire
1134 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
1135 status matches. This is particularly important when doing a private query for an SOA record,
1136 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
1137 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
1138
1139 Revision 1.640 2007/05/25 00:25:44 cheshire
1140 <rdar://problem/5227737> Need to enhance putRData to output all current known types
1141
1142 Revision 1.639 2007/05/23 00:51:33 cheshire
1143 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
1144 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
1145 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
1146
1147 Revision 1.638 2007/05/23 00:43:16 cheshire
1148 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
1149
1150 Revision 1.637 2007/05/14 23:53:00 cheshire
1151 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
1152
1153 Revision 1.636 2007/05/10 23:27:15 cheshire
1154 Update mDNS_Deregister_internal debugging messages
1155
1156 Revision 1.635 2007/05/07 20:43:45 cheshire
1157 <rdar://problem/4241419> Reduce the number of queries and announcements
1158
1159 Revision 1.634 2007/05/04 22:09:08 cheshire
1160 Only do "restarting exponential backoff sequence" for mDNS questions
1161 In mDNS_RegisterInterface, only retrigger mDNS questions
1162 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
1163
1164 Revision 1.633 2007/05/04 21:45:12 cheshire
1165 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
1166
1167 Revision 1.632 2007/05/04 20:20:50 cheshire
1168 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1169 Need to set srs->nta = mDNSNULL; when regState_NoTarget
1170
1171 Revision 1.631 2007/05/04 00:39:42 cheshire
1172 <rdar://problem/4410011> Eliminate looping SOA lookups
1173 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
1174 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
1175
1176 Revision 1.630 2007/05/03 22:40:38 cheshire
1177 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
1178
1179 Revision 1.629 2007/05/03 00:15:51 cheshire
1180 <rdar://problem/4410011> Eliminate looping SOA lookups
1181
1182 Revision 1.628 2007/05/02 22:21:33 cheshire
1183 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1184
1185 Revision 1.627 2007/04/30 19:29:13 cheshire
1186 Fix display of port number in "Updating DNS Server" message
1187
1188 Revision 1.626 2007/04/30 04:21:13 cheshire
1189 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
1190
1191 Revision 1.625 2007/04/28 01:34:21 cheshire
1192 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
1193 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
1194
1195 Revision 1.624 2007/04/27 21:04:30 cheshire
1196 On network configuration change, need to call uDNS_RegisterSearchDomains
1197
1198 Revision 1.623 2007/04/27 19:28:01 cheshire
1199 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
1200 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
1201 -- it would start a query and then quickly cancel it, and then when
1202 StartGetZoneData completed, it had a dangling pointer and crashed.)
1203
1204 Revision 1.622 2007/04/26 16:09:22 cheshire
1205 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
1206
1207 Revision 1.621 2007/04/26 15:43:22 cheshire
1208 Make sure DNSServer *s is non-null before using value in LogOperation
1209
1210 Revision 1.620 2007/04/26 13:11:05 cheshire
1211 Fixed crash when logging out of VPN
1212
1213 Revision 1.619 2007/04/26 00:35:15 cheshire
1214 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
1215 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
1216 inside the firewall may give answers where a public one gives none, and vice versa.)
1217
1218 Revision 1.618 2007/04/25 19:26:01 cheshire
1219 m->NextScheduledQuery was getting set too early in SendQueries()
1220 Improved "SendQueries didn't send all its queries" debugging message
1221
1222 Revision 1.617 2007/04/25 17:48:22 cheshire
1223 Update debugging message
1224
1225 Revision 1.616 2007/04/25 16:38:32 cheshire
1226 If negative cache entry already exists, reactivate it instead of creating a new one
1227
1228 Revision 1.615 2007/04/25 02:14:38 cheshire
1229 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
1230 Additional fixes to make LLQs work properly
1231
1232 Revision 1.614 2007/04/23 21:52:45 cheshire
1233 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
1234
1235 Revision 1.613 2007/04/23 04:58:20 cheshire
1236 <rdar://problem/5072548> Crash when setting extremely large TXT records
1237
1238 Revision 1.612 2007/04/22 20:39:38 cheshire
1239 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
1240
1241 Revision 1.611 2007/04/22 18:16:29 cheshire
1242 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
1243
1244 Revision 1.610 2007/04/22 06:02:02 cheshire
1245 <rdar://problem/4615977> Query should immediately return failure when no server
1246
1247 Revision 1.609 2007/04/20 21:17:24 cheshire
1248 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
1249
1250 Revision 1.608 2007/04/20 19:45:31 cheshire
1251 In LogClientOperations mode, dump out unknown DNS packets in their entirety
1252
1253 Revision 1.607 2007/04/19 23:56:25 cheshire
1254 Don't do cache-flush processing for LLQ answers
1255
1256 Revision 1.606 2007/04/19 22:50:53 cheshire
1257 <rdar://problem/4246187> Identical client queries should reference a single shared core query
1258
1259 Revision 1.605 2007/04/19 20:06:41 cheshire
1260 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
1261
1262 Revision 1.604 2007/04/19 18:03:04 cheshire
1263 Add "const" declaration
1264
1265 Revision 1.603 2007/04/06 21:00:25 cheshire
1266 Fix log message typo
1267
1268 Revision 1.602 2007/04/05 22:55:35 cheshire
1269 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1270
1271 Revision 1.601 2007/04/04 21:48:52 cheshire
1272 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1273
1274 Revision 1.600 2007/04/04 01:31:33 cheshire
1275 Improve debugging message
1276
1277 Revision 1.599 2007/04/04 00:03:26 cheshire
1278 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
1279
1280 Revision 1.598 2007/04/03 19:43:16 cheshire
1281 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1282
1283 Revision 1.597 2007/03/31 00:32:32 cheshire
1284 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
1285
1286 Revision 1.596 2007/03/28 20:59:26 cheshire
1287 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1288
1289 Revision 1.595 2007/03/26 23:48:16 cheshire
1290 <rdar://problem/4848295> Advertise model information via Bonjour
1291 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
1292
1293 Revision 1.594 2007/03/26 23:05:05 cheshire
1294 <rdar://problem/5089257> Don't cache TSIG records
1295
1296 Revision 1.593 2007/03/23 17:40:08 cheshire
1297 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
1298
1299 Revision 1.592 2007/03/22 18:31:48 cheshire
1300 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1301
1302 Revision 1.591 2007/03/22 00:49:19 cheshire
1303 <rdar://problem/4848295> Advertise model information via Bonjour
1304
1305 Revision 1.590 2007/03/21 23:05:59 cheshire
1306 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1307
1308 Revision 1.589 2007/03/20 15:37:19 cheshire
1309 Delete unnecessary log message
1310
1311 Revision 1.588 2007/03/20 00:24:44 cheshire
1312 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
1313
1314 Revision 1.587 2007/03/16 22:10:56 cheshire
1315 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
1316
1317 Revision 1.586 2007/03/10 03:26:44 cheshire
1318 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1319
1320 Revision 1.585 2007/03/10 02:02:58 cheshire
1321 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1322 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1323
1324 Revision 1.584 2007/02/28 01:51:27 cheshire
1325 Added comment about reverse-order IP address
1326
1327 Revision 1.583 2007/01/27 03:19:33 cheshire
1328 Need to initialize question->sock
1329
1330 Revision 1.582 2007/01/25 00:40:16 cheshire
1331 Unified CNAME-following functionality into cache management code (which means CNAME-following
1332 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1333
1334 Revision 1.581 2007/01/23 02:56:11 cheshire
1335 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1336
1337 Revision 1.580 2007/01/19 21:17:33 cheshire
1338 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1339
1340 Revision 1.579 2007/01/19 18:39:10 cheshire
1341 Fix a bunch of parameters that should have been declared "const"
1342
1343 Revision 1.578 2007/01/10 22:51:57 cheshire
1344 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1345
1346 Revision 1.577 2007/01/10 02:05:21 cheshire
1347 Delay uDNS_SetupDNSConfig() until *after* the platform layer
1348 has set up the interface list and security credentials
1349
1350 Revision 1.576 2007/01/09 02:40:57 cheshire
1351 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1352 moved it to mDNS_Init() in mDNS.c (core code)
1353
1354 Revision 1.575 2007/01/09 00:17:25 cheshire
1355 Improve "ERROR m->CurrentRecord already set" debugging messages
1356
1357 Revision 1.574 2007/01/05 08:30:41 cheshire
1358 Trim excessive "$Log" checkin history from before 2006
1359 (checkin history still available via "cvs log ..." of course)
1360
1361 Revision 1.573 2007/01/05 06:34:03 cheshire
1362 Improve "ERROR m->CurrentQuestion already set" debugging messages
1363
1364 Revision 1.572 2007/01/04 23:11:11 cheshire
1365 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1366 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1367
1368 Revision 1.571 2007/01/04 21:45:20 cheshire
1369 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1370 to do additional lock sanity checking around callback invocations
1371
1372 Revision 1.570 2007/01/04 20:57:47 cheshire
1373 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
1374
1375 Revision 1.569 2007/01/04 20:27:27 cheshire
1376 Change a LogMsg() to debugf()
1377
1378 Revision 1.568 2007/01/04 02:39:53 cheshire
1379 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1380
1381 Revision 1.567 2006/12/21 00:01:37 cheshire
1382 Tidy up code alignment
1383
1384 Revision 1.566 2006/12/20 04:07:34 cheshire
1385 Remove uDNS_info substructure from AuthRecord_struct
1386
1387 Revision 1.565 2006/12/19 22:49:23 cheshire
1388 Remove uDNS_info substructure from ServiceRecordSet_struct
1389
1390 Revision 1.564 2006/12/19 02:38:20 cheshire
1391 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1392
1393 Revision 1.563 2006/12/19 02:18:48 cheshire
1394 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1395
1396 Revision 1.562 2006/12/16 01:58:31 cheshire
1397 <rdar://problem/4720673> uDNS: Need to start caching unicast records
1398
1399 Revision 1.561 2006/12/01 07:38:53 herscher
1400 Only perform cache workaround fix if query is wide-area
1401
1402 Revision 1.560 2006/11/30 23:07:56 herscher
1403 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1404
1405 Revision 1.559 2006/11/27 08:20:57 cheshire
1406 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
1407
1408 Revision 1.558 2006/11/10 07:44:03 herscher
1409 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1410
1411 Revision 1.557 2006/11/10 01:12:51 cheshire
1412 <rdar://problem/4829718> Incorrect TTL corrections
1413
1414 Revision 1.556 2006/11/10 00:54:14 cheshire
1415 <rdar://problem/4816598> Changing case of Computer Name doesn't work
1416
1417 Revision 1.555 2006/10/30 20:03:37 cheshire
1418 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
1419
1420 Revision 1.554 2006/10/20 05:35:04 herscher
1421 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1422
1423 Revision 1.553 2006/10/05 03:42:43 herscher
1424 Remove embedded uDNS_info struct in DNSQuestion_struct
1425
1426 Revision 1.552 2006/09/15 21:20:15 cheshire
1427 Remove uDNS_info substructure from mDNS_struct
1428
1429 Revision 1.551 2006/08/14 23:24:22 cheshire
1430 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1431
1432 Revision 1.550 2006/07/27 17:58:34 cheshire
1433 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
1434
1435 Revision 1.549 2006/07/20 22:07:31 mkrochma
1436 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
1437 More fixes for uninitialized variables
1438
1439 Revision 1.548 2006/07/20 19:30:19 mkrochma
1440 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
1441
1442 Revision 1.547 2006/07/15 02:31:30 cheshire
1443 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
1444
1445 Revision 1.546 2006/07/07 01:09:09 cheshire
1446 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
1447 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
1448
1449 Revision 1.545 2006/07/05 23:10:30 cheshire
1450 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1451 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
1452
1453 Revision 1.544 2006/06/29 07:42:14 cheshire
1454 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
1455
1456 Revision 1.543 2006/06/29 01:38:43 cheshire
1457 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
1458
1459 Revision 1.542 2006/06/27 23:40:29 cheshire
1460 Fix typo in comment: mis-spelled "compile"
1461
1462 Revision 1.541 2006/06/27 19:46:24 cheshire
1463 Updated comments and debugging messages
1464
1465 Revision 1.540 2006/06/15 21:35:16 cheshire
1466 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
1467 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
1468
1469 Revision 1.539 2006/06/08 23:45:46 cheshire
1470 Change SimultaneousProbe messages from debugf() to LogOperation()
1471
1472 Revision 1.538 2006/03/19 17:13:06 cheshire
1473 <rdar://problem/4483117> Need faster purging of stale records
1474 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
1475 and reconfirm whole chain of antecedents ot once
1476
1477 Revision 1.537 2006/03/19 02:00:07 cheshire
1478 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1479
1480 Revision 1.536 2006/03/08 23:29:53 cheshire
1481 <rdar://problem/4468716> Improve "Service Renamed" log message
1482
1483 Revision 1.535 2006/03/02 20:41:17 cheshire
1484 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1485 Minor code tidying and comments to reduce the risk of similar programming errors in future
1486
1487 Revision 1.534 2006/03/02 03:25:46 cheshire
1488 <rdar://problem/4111464> After record update, old record sometimes remains in cache
1489 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
1490
1491 Revision 1.533 2006/02/26 00:54:41 cheshire
1492 Fixes to avoid code generation warning/error on FreeBSD 7
1493
1494 */
1495
1496 #include "DNSCommon.h" // Defines general DNS untility routines
1497 #include "uDNS.h" // Defines entry points into unicast-specific routines
1498
1499 // Disable certain benign warnings with Microsoft compilers
1500 #if(defined(_MSC_VER))
1501 // Disable "conditional expression is constant" warning for debug macros.
1502 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1503 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1504 #pragma warning(disable:4127)
1505
1506 // Disable "assignment within conditional expression".
1507 // Other compilers understand the convention that if you place the assignment expression within an extra pair
1508 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1509 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1510 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1511 #pragma warning(disable:4706)
1512 #endif
1513
1514 // Forward declarations
1515 mDNSlocal void BeginSleepProcessing(mDNS *const m);
1516 mDNSlocal void RetrySPSRegistrations(mDNS *const m);
1517
1518 // ***************************************************************************
1519 #if COMPILER_LIKES_PRAGMA_MARK
1520 #pragma mark - Program Constants
1521 #endif
1522
1523 #define NO_HINFO 1
1524
1525 mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
1526
1527 // Any records bigger than this are considered 'large' records
1528 #define SmallRecordLimit 1024
1529
1530 #define kMaxUpdateCredits 10
1531 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1532
1533 mDNSexport const char *const mDNS_DomainTypeNames[] =
1534 {
1535 "b._dns-sd._udp.", // Browse
1536 "db._dns-sd._udp.", // Default Browse
1537 "lb._dns-sd._udp.", // Automatic Browse
1538 "r._dns-sd._udp.", // Registration
1539 "dr._dns-sd._udp." // Default Registration
1540 };
1541
1542 #ifdef UNICAST_DISABLED
1543 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1544 #endif
1545
1546 // ***************************************************************************
1547 #if COMPILER_LIKES_PRAGMA_MARK
1548 #pragma mark -
1549 #pragma mark - General Utility Functions
1550 #endif
1551
1552 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
1553 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
1554
1555 mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
1556 {
1557 if (m->mDNS_busy != m->mDNS_reentrancy+1)
1558 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1559
1560 #if ForceAlerts
1561 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0;
1562 #endif
1563
1564 if (ActiveQuestion(q))
1565 {
1566 mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
1567
1568 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
1569 if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
1570 sendtime = m->SuppressStdPort53Queries;
1571
1572 if (m->NextScheduledQuery - sendtime > 0)
1573 m->NextScheduledQuery = sendtime;
1574 }
1575 }
1576
1577 mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
1578 {
1579 CacheGroup *cg;
1580 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1581 if (cg->namehash == namehash && SameDomainName(cg->name, name))
1582 break;
1583 return(cg);
1584 }
1585
1586 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
1587 {
1588 return(CacheGroupForName(m, slot, rr->namehash, rr->name));
1589 }
1590
1591 mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
1592 {
1593 NetworkInterfaceInfo *intf;
1594
1595 if (addr->type == mDNSAddrType_IPv4)
1596 {
1597 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
1598 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
1599 for (intf = m->HostInterfaces; intf; intf = intf->next)
1600 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
1601 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
1602 return(mDNStrue);
1603 }
1604
1605 if (addr->type == mDNSAddrType_IPv6)
1606 {
1607 if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
1608 for (intf = m->HostInterfaces; intf; intf = intf->next)
1609 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
1610 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
1611 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
1612 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
1613 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
1614 return(mDNStrue);
1615 }
1616
1617 return(mDNSfalse);
1618 }
1619
1620 mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
1621 {
1622 NetworkInterfaceInfo *intf = m->HostInterfaces;
1623 while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
1624 return(intf);
1625 }
1626
1627 mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
1628 {
1629 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
1630 return(intf ? intf->ifname : "<NULL InterfaceID>");
1631 }
1632
1633 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1634 // Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
1635 mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
1636 {
1637 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1638 if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
1639 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1640 if (q->QuestionCallback && !q->NoAnswer)
1641 {
1642 q->CurrentAnswers += AddRecord ? 1 : -1;
1643 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
1644 }
1645 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1646 }
1647
1648 // When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
1649 // all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
1650 // stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1651 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1652 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1653 mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
1654 {
1655 if (m->CurrentQuestion)
1656 LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
1657
1658 m->CurrentQuestion = m->LocalOnlyQuestions;
1659 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
1660 {
1661 DNSQuestion *q = m->CurrentQuestion;
1662 m->CurrentQuestion = q->next;
1663 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1664 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
1665 }
1666
1667 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1668 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
1669 {
1670 m->CurrentQuestion = m->Questions;
1671 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
1672 {
1673 DNSQuestion *q = m->CurrentQuestion;
1674 m->CurrentQuestion = q->next;
1675 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1676 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
1677 }
1678 }
1679
1680 m->CurrentQuestion = mDNSNULL;
1681 }
1682
1683 // ***************************************************************************
1684 #if COMPILER_LIKES_PRAGMA_MARK
1685 #pragma mark -
1686 #pragma mark - Resource Record Utility Functions
1687 #endif
1688
1689 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1690
1691 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1692 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1693 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1694 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1695
1696 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1697 (ResourceRecordIsValidAnswer(RR) && \
1698 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1699
1700 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1701 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1702
1703 #define InitialAnnounceCount ((mDNSu8)8)
1704
1705 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1706 // This means that because the announce interval is doubled after sending the first packet, the first
1707 // observed on-the-wire inter-packet interval between announcements is actually one second.
1708 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1709 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1710 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1711 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1712
1713 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1714 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1715 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1716
1717 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1718 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1719 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1720 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1721
1722 #define MaxUnansweredQueries 4
1723
1724 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1725 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1726 // TTL and rdata may differ.
1727 // This is used for cache flush management:
1728 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1729 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1730
1731 // SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
1732
1733 #define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
1734
1735 mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2)
1736 {
1737 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
1738 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
1739 if (r1->resrec.InterfaceID &&
1740 r2->resrec.InterfaceID &&
1741 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
1742 return(mDNSBool)(
1743 r1->resrec.rrclass == r2->resrec.rrclass &&
1744 r1->resrec.namehash == r2->resrec.namehash &&
1745 SameDomainName(r1->resrec.name, r2->resrec.name));
1746 }
1747
1748 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1749 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1750 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1751 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1752 // so a response of any type should match, even if it is not actually the type the client plans to use.
1753
1754 // For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
1755 // and require the rrtypes to match for the rdata to be considered potentially conflicting
1756 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
1757 {
1758 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
1759 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
1760 if (pktrr->resrec.InterfaceID &&
1761 authrr->resrec.InterfaceID &&
1762 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
1763 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
1764 if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
1765 return(mDNSBool)(
1766 pktrr->resrec.rrclass == authrr->resrec.rrclass &&
1767 pktrr->resrec.namehash == authrr->resrec.namehash &&
1768 SameDomainName(pktrr->resrec.name, authrr->resrec.name));
1769 }
1770
1771 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1772 // This is the information that the requester believes to be correct.
1773 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1774 // This is the information that we believe to be correct.
1775 // We've already determined that we plan to give this answer on this interface
1776 // (either the record is non-specific, or it is specific to this interface)
1777 // so now we just need to check the name, type, class, rdata and TTL.
1778 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
1779 {
1780 // If RR signature is different, or data is different, then don't suppress our answer
1781 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
1782
1783 // If the requester's indicated TTL is less than half the real TTL,
1784 // we need to give our answer before the requester's copy expires.
1785 // If the requester's indicated TTL is at least half the real TTL,
1786 // then we can suppress our answer this time.
1787 // If the requester's indicated TTL is greater than the TTL we believe,
1788 // then that's okay, and we don't need to do anything about it.
1789 // (If two responders on the network are offering the same information,
1790 // that's okay, and if they are offering the information with different TTLs,
1791 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1792 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
1793 }
1794
1795 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
1796 {
1797 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1798 {
1799 //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1800 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1801 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
1802 }
1803 else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
1804 {
1805 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1806 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
1807 }
1808 }
1809
1810 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
1811 {
1812 // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1813 rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
1814
1815 // To allow us to aggregate probes when a group of services are registered together,
1816 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1817 // 1/4 second wait; probe
1818 // 1/4 second wait; probe
1819 // 1/4 second wait; probe
1820 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1821
1822 if (rr->ProbeCount)
1823 {
1824 // If we have no probe suppression time set, or it is in the past, set it now
1825 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
1826 {
1827 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
1828 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1829 if (m->SuppressProbes - m->NextScheduledProbe >= 0)
1830 m->SuppressProbes = m->NextScheduledProbe;
1831 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1832 if (m->SuppressProbes - m->NextScheduledQuery >= 0)
1833 m->SuppressProbes = m->NextScheduledQuery;
1834 }
1835 }
1836
1837 rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
1838 // Set LastMCTime to now, to inhibit multicast responses
1839 // (no need to send additional multicast responses when we're announcing anyway)
1840 rr->LastMCTime = m->timenow;
1841 rr->LastMCInterface = mDNSInterfaceMark;
1842
1843 // If this is a record type that's not going to probe, then delay its first announcement so that
1844 // it will go out synchronized with the first announcement for the other records that *are* probing.
1845 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1846 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1847 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1848 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1849 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1850 if (rr->resrec.RecordType != kDNSRecordTypeUnique)
1851 rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
1852
1853 // The exception is unique records that have already been verified and are just being updated
1854 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1855 if (rr->resrec.RecordType == kDNSRecordTypeVerified)
1856 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1857
1858 // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1859 // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1860 // After three probes one second apart with no answer, we conclude the client is now sleeping
1861 // and we can begin broadcasting our announcements to take over ownership of that IP address.
1862 // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1863 // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1864 if (rr->AddressProxy.type) rr->LastAPTime = m->timenow;
1865
1866 // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
1867 if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
1868 rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
1869
1870 SetNextAnnounceProbeTime(m, rr);
1871 }
1872
1873 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1874 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1875 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
1876 {
1877 domainname *const target = GetRRDomainNameTarget(&rr->resrec);
1878 const domainname *newname = &m->MulticastHostname;
1879
1880 if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
1881
1882 if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage)))
1883 {
1884 const domainname *const n = GetServiceTarget(m, rr);
1885 if (n) newname = n;
1886 }
1887
1888 if (target && SameDomainName(target, newname))
1889 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
1890
1891 if (target && !SameDomainName(target, newname))
1892 {
1893 AssignDomainName(target, newname);
1894 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
1895
1896 // If we're in the middle of probing this record, we need to start again,
1897 // because changing its rdata may change the outcome of the tie-breaker.
1898 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1899 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1900
1901 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1902 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1903 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1904 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
1905 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1906 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1907
1908 rr->AnnounceCount = InitialAnnounceCount;
1909 rr->RequireGoodbye = mDNSfalse;
1910 InitializeLastAPTime(m, rr);
1911 }
1912 }
1913
1914 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
1915 {
1916 if (rr->RecordCallback)
1917 {
1918 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1919 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1920 rr->Acknowledged = mDNStrue;
1921 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1922 rr->RecordCallback(m, rr, mStatus_NoError);
1923 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1924 }
1925 }
1926
1927 mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
1928 {
1929 rr->ProbeCount = 0;
1930 rr->AnnounceCount = 0;
1931 rr->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds
1932 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1933 rr->state = regState_FetchingZoneData;
1934 rr->uselease = mDNStrue;
1935 }
1936
1937 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1938 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1939 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1940 #define RecordIsLocalDuplicate(A,B) \
1941 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1942
1943 // Exported so uDNS.c can call this
1944 mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
1945 {
1946 domainname *target = GetRRDomainNameTarget(&rr->resrec);
1947 AuthRecord *r;
1948 AuthRecord **p = &m->ResourceRecords;
1949 AuthRecord **d = &m->DuplicateRecords;
1950
1951 if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
1952 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1953
1954 if (!rr->resrec.RecordType)
1955 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1956
1957 if (m->ShutdownTime)
1958 { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); }
1959
1960 if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
1961 {
1962 mDNSInterfaceID previousID = rr->resrec.InterfaceID;
1963 if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1964 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1965 {
1966 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
1967 if (intf && !intf->Advertise) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1968 }
1969 if (rr->resrec.InterfaceID != previousID)
1970 LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr));
1971 }
1972
1973 while (*p && *p != rr) p=&(*p)->next;
1974 while (*d && *d != rr) d=&(*d)->next;
1975 if (*d || *p)
1976 {
1977 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1978 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1979 return(mStatus_AlreadyRegistered);
1980 }
1981
1982 if (rr->DependentOn)
1983 {
1984 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1985 rr->resrec.RecordType = kDNSRecordTypeVerified;
1986 else
1987 {
1988 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1989 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1990 return(mStatus_Invalid);
1991 }
1992 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
1993 {
1994 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1995 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
1996 return(mStatus_Invalid);
1997 }
1998 }
1999
2000 // If this resource record is referencing a specific interface, make sure it exists
2001 if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
2002 {
2003 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
2004 if (!intf)
2005 {
2006 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
2007 return(mStatus_BadReferenceErr);
2008 }
2009 }
2010
2011 rr->next = mDNSNULL;
2012
2013 // Field Group 1: The actual information pertaining to this resource record
2014 // Set up by client prior to call
2015
2016 // Field Group 2: Persistent metadata for Authoritative Records
2017 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2018 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2019 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2020 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2021 // rr->Callback = already set in mDNS_SetupResourceRecord
2022 // rr->Context = already set in mDNS_SetupResourceRecord
2023 // rr->RecordType = already set in mDNS_SetupResourceRecord
2024 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2025 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2026 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
2027 if (rr->AutoTarget && target) target->c[0] = 0;
2028
2029 // Field Group 3: Transient state for Authoritative Records
2030 rr->Acknowledged = mDNSfalse;
2031 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2032 rr->AnnounceCount = InitialAnnounceCount;
2033 rr->RequireGoodbye = mDNSfalse;
2034 rr->AnsweredLocalQ = mDNSfalse;
2035 rr->IncludeInProbe = mDNSfalse;
2036 rr->ImmedUnicast = mDNSfalse;
2037 rr->SendNSECNow = mDNSNULL;
2038 rr->ImmedAnswer = mDNSNULL;
2039 rr->ImmedAdditional = mDNSNULL;
2040 rr->SendRNow = mDNSNULL;
2041 rr->v4Requester = zerov4Addr;
2042 rr->v6Requester = zerov6Addr;
2043 rr->NextResponse = mDNSNULL;
2044 rr->NR_AnswerTo = mDNSNULL;
2045 rr->NR_AdditionalTo = mDNSNULL;
2046 if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
2047 // rr->LastAPTime = Set for us in InitializeLastAPTime()
2048 // rr->LastMCTime = Set for us in InitializeLastAPTime()
2049 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
2050 rr->NewRData = mDNSNULL;
2051 rr->newrdlength = 0;
2052 rr->UpdateCallback = mDNSNULL;
2053 rr->UpdateCredits = kMaxUpdateCredits;
2054 rr->NextUpdateCredit = 0;
2055 rr->UpdateBlocked = 0;
2056
2057 // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
2058 if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2;
2059
2060 // Field Group 4: Transient uDNS state for Authoritative Records
2061 rr->state = regState_Zero;
2062 rr->uselease = 0;
2063 rr->expire = 0;
2064 rr->Private = 0;
2065 rr->updateid = zeroID;
2066 rr->zone = rr->resrec.name;
2067 rr->UpdateServer = zeroAddr;
2068 rr->UpdatePort = zeroIPPort;
2069 rr->nta = mDNSNULL;
2070 rr->tcp = mDNSNULL;
2071 rr->OrigRData = 0;
2072 rr->OrigRDLen = 0;
2073 rr->InFlightRData = 0;
2074 rr->InFlightRDLen = 0;
2075 rr->QueuedRData = 0;
2076 rr->QueuedRDLen = 0;
2077
2078 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
2079 // rr->resrec.name->c = MUST be set by client
2080 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
2081 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
2082 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
2083 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2084
2085 if (rr->AutoTarget)
2086 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2087 else
2088 {
2089 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
2090 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2091 }
2092
2093 if (!ValidateDomainName(rr->resrec.name))
2094 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2095
2096 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2097 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2098 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2099 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
2100
2101 // Don't do this until *after* we've set rr->resrec.rdlength
2102 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2103 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2104
2105 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
2106 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
2107
2108 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2109 {
2110 // If this is supposed to be unique, make sure we don't have any name conflicts
2111 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2112 {
2113 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
2114 for (r = m->ResourceRecords; r; r=r->next)
2115 {
2116 const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
2117 if (s1 != s2 && SameResourceRecordSignature(r, rr) && !IdenticalSameNameRecord(&r->resrec, &rr->resrec))
2118 break;
2119 }
2120 if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2121 {
2122 debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2123 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2124 rr->resrec.rroriginalttl = 0;
2125 rr->ImmedAnswer = mDNSInterfaceMark;
2126 m->NextScheduledResponse = m->timenow;
2127 }
2128 }
2129 }
2130
2131 // Now that we've finished building our new record, make sure it's not identical to one we already have
2132 for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
2133
2134 if (r)
2135 {
2136 debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
2137 *d = rr;
2138 // If the previous copy of this record is already verified unique,
2139 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2140 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
2141 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2142 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
2143 rr->ProbeCount = 0;
2144 }
2145 else
2146 {
2147 debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
2148 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
2149 *p = rr;
2150 }
2151
2152 if (!AuthRecord_uDNS(rr))
2153 {
2154 // For records that are not going to probe, acknowledge them right away
2155 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
2156 AcknowledgeRecord(m, rr);
2157 }
2158 #ifndef UNICAST_DISABLED
2159 else
2160 {
2161 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
2162 ActivateUnicastRegistration(m, rr);
2163 }
2164 #endif
2165
2166 return(mStatus_NoError);
2167 }
2168
2169 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
2170 {
2171 m->ProbeFailTime = m->timenow;
2172 m->NumFailedProbes++;
2173 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2174 // If a bunch of hosts have all been configured with the same name, then they'll all
2175 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2176 // up to name-10. After that they'll start adding random increments in the range 1-100,
2177 // so they're more likely to branch out in the available namespace and settle on a set of
2178 // unique names quickly. If after five more tries the host is still conflicting, then we
2179 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
2180 if (m->NumFailedProbes >= 15)
2181 {
2182 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
2183 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2184 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2185 }
2186 }
2187
2188 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
2189 {
2190 RData *OldRData = rr->resrec.rdata;
2191 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
2192 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
2193 if (rr->UpdateCallback)
2194 rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
2195 }
2196
2197 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2198 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2199 // Exported so uDNS.c can call this
2200 mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
2201 {
2202 AuthRecord *r2;
2203 mDNSu8 RecordType = rr->resrec.RecordType;
2204 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
2205
2206 while (*p && *p != rr) p=&(*p)->next;
2207
2208 if (*p)
2209 {
2210 // We found our record on the main list. See if there are any duplicates that need special handling.
2211 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment
2212 {
2213 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2214 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2215 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
2216 }
2217 else
2218 {
2219 // Before we delete the record (and potentially send a goodbye packet)
2220 // first see if we have a record on the duplicate list ready to take over from it.
2221 AuthRecord **d = &m->DuplicateRecords;
2222 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
2223 if (*d)
2224 {
2225 AuthRecord *dup = *d;
2226 debugf("Duplicate record %p taking over from %p %##s (%s)",
2227 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2228 *d = dup->next; // Cut replacement record from DuplicateRecords list
2229 dup->next = rr->next; // And then...
2230 rr->next = dup; // ... splice it in right after the record we're about to delete
2231 dup->resrec.RecordType = rr->resrec.RecordType;
2232 dup->ProbeCount = rr->ProbeCount;
2233 dup->AnnounceCount = rr->AnnounceCount;
2234 dup->RequireGoodbye = rr->RequireGoodbye;
2235 dup->AnsweredLocalQ = rr->AnsweredLocalQ;
2236 dup->ImmedAnswer = rr->ImmedAnswer;
2237 dup->ImmedUnicast = rr->ImmedUnicast;
2238 dup->ImmedAdditional = rr->ImmedAdditional;
2239 dup->v4Requester = rr->v4Requester;
2240 dup->v6Requester = rr->v6Requester;
2241 dup->ThisAPInterval = rr->ThisAPInterval;
2242 dup->LastAPTime = rr->LastAPTime;
2243 dup->LastMCTime = rr->LastMCTime;
2244 dup->LastMCInterface = rr->LastMCInterface;
2245 dup->UpdateServer = rr->UpdateServer;
2246 dup->UpdatePort = rr->UpdatePort;
2247 dup->Private = rr->Private;
2248 dup->state = rr->state;
2249 rr->RequireGoodbye = mDNSfalse;
2250 rr->AnsweredLocalQ = mDNSfalse;
2251 }
2252 }
2253 }
2254 else
2255 {
2256 // We didn't find our record on the main list; try the DuplicateRecords list instead.
2257 p = &m->DuplicateRecords;
2258 while (*p && *p != rr) p=&(*p)->next;
2259 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2260 if (*p) rr->RequireGoodbye = mDNSfalse;
2261 if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2262 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2263 }
2264
2265 if (!*p)
2266 {
2267 // No need to log an error message if we already know this is a potentially repeated deregistration
2268 if (drt != mDNS_Dereg_repeat)
2269 LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr));
2270 return(mStatus_BadReferenceErr);
2271 }
2272
2273 // If this is a shared record and we've announced it at least once,
2274 // we need to retract that announcement before we delete the record
2275
2276 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2277 // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
2278 // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2279 // mechanism to cope with the client callback modifying the question list while that's happening.
2280 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2281 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2282 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2283 // records, thereby invoking yet more callbacks, without limit.
2284 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2285 // actual goodbye packets.
2286
2287 #ifndef UNICAST_DISABLED
2288 if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
2289 {
2290 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
2291 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2292 uDNS_DeregisterRecord(m, rr);
2293 // At this point unconditionally we bail out
2294 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2295 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2296 // process and will complete asynchronously. Either way we don't need to do anything more here.
2297 return(mStatus_NoError);
2298 }
2299 #endif // UNICAST_DISABLED
2300
2301 if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
2302 {
2303 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
2304 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
2305 rr->resrec.rroriginalttl = 0;
2306 rr->ImmedAnswer = mDNSInterfaceMark;
2307 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2308 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2309 }
2310 else
2311 {
2312 *p = rr->next; // Cut this record from the list
2313 // If someone is about to look at this, bump the pointer forward
2314 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
2315 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2316 rr->next = mDNSNULL;
2317
2318 if (RecordType == kDNSRecordTypeUnregistered)
2319 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
2320 else if (RecordType == kDNSRecordTypeDeregistering)
2321 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
2322 else
2323 {
2324 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
2325 rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2326 }
2327
2328 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2329 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2330 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2331
2332 // If we have an update queued up which never executed, give the client a chance to free that memory
2333 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
2334
2335 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
2336 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
2337
2338 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2339 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2340 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
2341 // so any attempt to touch rr after this is likely to lead to a crash.
2342 if (drt != mDNS_Dereg_conflict)
2343 {
2344 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2345 if (rr->RecordCallback)
2346 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
2347 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2348 }
2349 else
2350 {
2351 RecordProbeFailure(m, rr);
2352 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
2353 if (rr->RecordCallback)
2354 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
2355 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2356 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2357 // Note that with all the client callbacks going on, by the time we get here all the
2358 // records we marked may have been explicitly deregistered by the client anyway.
2359 r2 = m->DuplicateRecords;
2360 while (r2)
2361 {
2362 if (r2->ProbeCount != 0xFF) r2 = r2->next;
2363 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
2364 }
2365 }
2366 }
2367 return(mStatus_NoError);
2368 }
2369
2370 // ***************************************************************************
2371 #if COMPILER_LIKES_PRAGMA_MARK
2372 #pragma mark -
2373 #pragma mark - Packet Sending Functions
2374 #endif
2375
2376 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2377 {
2378 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2379 {
2380 **nrpp = rr;
2381 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2382 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2383 // The referenced record will definitely be acceptable (by recursive application of this rule)
2384 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2385 rr->NR_AdditionalTo = add;
2386 *nrpp = &rr->NextResponse;
2387 }
2388 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2389 }
2390
2391 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2392 {
2393 AuthRecord *rr, *rr2;
2394 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put
2395 {
2396 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
2397 // later in the "for" loop, and we will follow further "additional" links then.)
2398 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2399 AddRecordToResponseList(nrpp, rr->Additional1, rr);
2400
2401 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2402 AddRecordToResponseList(nrpp, rr->Additional2, rr);
2403
2404 // For SRV records, automatically add the Address record(s) for the target host
2405 if (rr->resrec.rrtype == kDNSType_SRV)
2406 {
2407 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
2408 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
2409 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
2410 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
2411 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2412 AddRecordToResponseList(nrpp, rr2, rr);
2413 }
2414 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional
2415 {
2416 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
2417 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
2418 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
2419 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name
2420 SameDomainName(rr->resrec.name, rr2->resrec.name))
2421 AddRecordToResponseList(nrpp, rr2, rr);
2422 }
2423 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record
2424 {
2425 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
2426 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
2427 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
2428 }
2429 }
2430 }
2431
2432 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2433 {
2434 AuthRecord *rr;
2435 AuthRecord *ResponseRecords = mDNSNULL;
2436 AuthRecord **nrp = &ResponseRecords;
2437
2438 // Make a list of all our records that need to be unicast to this destination
2439 for (rr = m->ResourceRecords; rr; rr=rr->next)
2440 {
2441 // If we find we can no longer unicast this answer, clear ImmedUnicast
2442 if (rr->ImmedAnswer == mDNSInterfaceMark ||
2443 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2444 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) )
2445 rr->ImmedUnicast = mDNSfalse;
2446
2447 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2448 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2449 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2450 {
2451 rr->ImmedAnswer = mDNSNULL; // Clear the state fields
2452 rr->ImmedUnicast = mDNSfalse;
2453 rr->v4Requester = zerov4Addr;
2454 rr->v6Requester = zerov6Addr;
2455 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo
2456 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
2457 }
2458 }
2459
2460 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2461
2462 while (ResponseRecords)
2463 {
2464 mDNSu8 *responseptr = m->omsg.data;
2465 mDNSu8 *newptr;
2466 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2467
2468 // Put answers in the packet
2469 while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2470 {
2471 rr = ResponseRecords;
2472 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2473 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2474 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2475 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2476 if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now
2477 if (newptr) responseptr = newptr;
2478 ResponseRecords = rr->NextResponse;
2479 rr->NextResponse = mDNSNULL;
2480 rr->NR_AnswerTo = mDNSNULL;
2481 rr->NR_AdditionalTo = mDNSNULL;
2482 rr->RequireGoodbye = mDNStrue;
2483 }
2484
2485 // Add additionals, if there's space
2486 while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2487 {
2488 rr = ResponseRecords;
2489 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2490 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2491 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2492 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2493
2494 if (newptr) responseptr = newptr;
2495 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2496 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2497 ResponseRecords = rr->NextResponse;
2498 rr->NextResponse = mDNSNULL;
2499 rr->NR_AnswerTo = mDNSNULL;
2500 rr->NR_AdditionalTo = mDNSNULL;
2501 }
2502
2503 if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
2504 }
2505 }
2506
2507 mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2508 {
2509 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2510 // it should go ahead and immediately dispose of this registration
2511 rr->resrec.RecordType = kDNSRecordTypeShared;
2512 rr->RequireGoodbye = mDNSfalse;
2513 if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
2514 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
2515 }
2516
2517 // Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2518 // the record list and/or question list.
2519 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2520 mDNSlocal void DiscardDeregistrations(mDNS *const m)
2521 {
2522 if (m->CurrentRecord)
2523 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
2524 m->CurrentRecord = m->ResourceRecords;
2525
2526 while (m->CurrentRecord)
2527 {
2528 AuthRecord *rr = m->CurrentRecord;
2529 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2530 CompleteDeregistration(m, rr); // Don't touch rr after this
2531 else
2532 m->CurrentRecord = rr->next;
2533 }
2534 }
2535
2536 mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
2537 {
2538 int i, val = 0;
2539 if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid);
2540 for (i=1; i<=src[0]; i++)
2541 {
2542 if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid);
2543 val = val * 10 + src[i] - '0';
2544 }
2545 if (val > 255) return(mStatus_Invalid);
2546 *dst = val;
2547 return(mStatus_NoError);
2548 }
2549
2550 mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name)
2551 {
2552 int skip = CountLabels(name) - 6;
2553 if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; }
2554 if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) ||
2555 GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) ||
2556 GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) ||
2557 GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid;
2558 a->type = mDNSAddrType_IPv4;
2559 return(mStatus_NoError);
2560 }
2561
2562 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
2563 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
2564 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2565
2566 mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name)
2567 {
2568 int i, h, l;
2569 const domainname *n;
2570
2571 int skip = CountLabels(name) - 34;
2572 if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; }
2573
2574 n = SkipLeadingLabels(name, skip);
2575 for (i=0; i<16; i++)
2576 {
2577 if (n->c[0] != 1) return mStatus_Invalid;
2578 l = HexVal(n->c[1]);
2579 n = (const domainname *)(n->c + 2);
2580
2581 if (n->c[0] != 1) return mStatus_Invalid;
2582 h = HexVal(n->c[1]);
2583 n = (const domainname *)(n->c + 2);
2584
2585 if (l<0 || h<0) return mStatus_Invalid;
2586 a->ip.v6.b[15-i] = (h << 4) | l;
2587 }
2588
2589 a->type = mDNSAddrType_IPv6;
2590 return(mStatus_NoError);
2591 }
2592
2593 mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name)
2594 {
2595 int skip = CountLabels(name) - 2;
2596 if (skip >= 0)
2597 {
2598 const domainname *suffix = SkipLeadingLabels(name, skip);
2599 if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4;
2600 if (SameDomainName(suffix, (const domainname*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6;
2601 }
2602 return(mDNSAddrType_None);
2603 }
2604
2605 mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr,
2606 const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst)
2607 {
2608 int i;
2609 mDNSu8 *ptr = m->omsg.data;
2610 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
2611 if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
2612
2613 // 0x00 Destination address
2614 for (i=0; i<6; i++) *ptr++ = dst[i];
2615
2616 // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
2617 for (i=0; i<6; i++) *ptr++ = 0x0;
2618
2619 // 0x0C ARP Ethertype (0x0806)
2620 *ptr++ = 0x08; *ptr++ = 0x06;
2621
2622 // 0x0E ARP header
2623 *ptr++ = 0x00; *ptr++ = 0x01; // Hardware address space; Ethernet = 1
2624 *ptr++ = 0x08; *ptr++ = 0x00; // Protocol address space; IP = 0x0800
2625 *ptr++ = 6; // Hardware address length
2626 *ptr++ = 4; // Protocol address length
2627 *ptr++ = 0x00; *ptr++ = op; // opcode; Request = 1, Response = 2
2628
2629 // 0x16 Sender hardware address (our MAC address)
2630 for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i];
2631
2632 // 0x1C Sender protocol address
2633 for (i=0; i<4; i++) *ptr++ = spa[i];
2634
2635 // 0x20 Target hardware address
2636 for (i=0; i<6; i++) *ptr++ = tha[i];
2637
2638 // 0x26 Target protocol address
2639 for (i=0; i<4; i++) *ptr++ = tpa[i];
2640
2641 // 0x2A Total ARP Packet length 42 bytes
2642 mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
2643 }
2644
2645 mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner)
2646 {
2647 owner->u.owner.vers = 0;
2648 owner->u.owner.seq = m->SleepSeqNum;
2649 owner->u.owner.HMAC = m->PrimaryMAC;
2650 owner->u.owner.IMAC = intf->MAC;
2651 owner->u.owner.password = zeroEthAddr;
2652
2653 // Don't try to compute the optlen until *after* we've set up the data fields
2654 owner->opt = kDNSOpt_Owner;
2655 owner->optlen = DNSOpt_Owner_Space(owner) - 4;
2656 }
2657
2658 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
2659 {
2660 if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
2661 else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
2662 }
2663
2664 // Note about acceleration of announcements to facilitate automatic coalescing of
2665 // multiple independent threads of announcements into a single synchronized thread:
2666 // The announcements in the packet may be at different stages of maturity;
2667 // One-second interval, two-second interval, four-second interval, and so on.
2668 // After we've put in all the announcements that are due, we then consider
2669 // whether there are other nearly-due announcements that are worth accelerating.
2670 // To be eligible for acceleration, a record MUST NOT be older (further along
2671 // its timeline) than the most mature record we've already put in the packet.
2672 // In other words, younger records can have their timelines accelerated to catch up
2673 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
2674 // Older records cannot have their timelines accelerated; this would just widen
2675 // the gap between them and their younger bretheren and get them even more out of sync.
2676
2677 // Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
2678 // the record list and/or question list.
2679 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2680 mDNSlocal void SendResponses(mDNS *const m)
2681 {
2682 int pktcount = 0;
2683 AuthRecord *rr, *r2;
2684 mDNSs32 maxExistingAnnounceInterval = 0;
2685 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
2686
2687 m->NextScheduledResponse = m->timenow + 0x78000000;
2688
2689 if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m);
2690
2691 for (rr = m->ResourceRecords; rr; rr=rr->next)
2692 if (rr->ImmedUnicast)
2693 {
2694 mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
2695 mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
2696 v4.ip.v4 = rr->v4Requester;
2697 v6.ip.v6 = rr->v6Requester;
2698 if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
2699 if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
2700 if (rr->ImmedUnicast)
2701 {
2702 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
2703 rr->ImmedUnicast = mDNSfalse;
2704 }
2705 }
2706
2707 // ***
2708 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
2709 // ***
2710
2711 // Run through our list of records, and decide which ones we're going to announce on all interfaces
2712 for (rr = m->ResourceRecords; rr; rr=rr->next)
2713 {
2714 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
2715 if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
2716 {
2717 if (rr->AddressProxy.type)
2718 {
2719 rr->AnnounceCount--;
2720 rr->ThisAPInterval *= 2;
2721 rr->LastAPTime = m->timenow;
2722 if (rr->AddressProxy.type == mDNSAddrType_IPv4)
2723 {
2724 LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
2725 SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2726 }
2727 else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
2728 {
2729 //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
2730 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2731 }
2732 }
2733 else
2734 {
2735 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
2736 if (maxExistingAnnounceInterval < rr->ThisAPInterval)
2737 maxExistingAnnounceInterval = rr->ThisAPInterval;
2738 if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
2739 }
2740 }
2741 }
2742
2743 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
2744 // Eligible records that are more than half-way to their announcement time are accelerated
2745 for (rr = m->ResourceRecords; rr; rr=rr->next)
2746 if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
2747 (rr->ThisAPInterval <= maxExistingAnnounceInterval &&
2748 TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
2749 !rr->AddressProxy.type && // Don't include ARP Annoucements when considering which records to accelerate
2750 ResourceRecordIsValidAnswer(rr)))
2751 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
2752
2753 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
2754 // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
2755 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
2756 // then all that means is that it won't get sent -- which would not be the end of the world.
2757 for (rr = m->ResourceRecords; rr; rr=rr->next)
2758 {
2759 if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
2760 for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records
2761 if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ...
2762 ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ...
2763 rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ...
2764 rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target
2765 SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
2766 (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
2767 r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too
2768 // We also make sure we send the DeviceInfo TXT record too, if necessary
2769 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
2770 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
2771 if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR)
2772 if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
2773 {
2774 if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer;
2775 else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark;
2776 }
2777 }
2778
2779 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
2780 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
2781 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
2782 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
2783 // -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface
2784 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
2785 for (rr = m->ResourceRecords; rr; rr=rr->next)
2786 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2787 {
2788 if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked
2789 {
2790 for (r2 = m->ResourceRecords; r2; r2=r2->next)
2791 if (ResourceRecordIsValidAnswer(r2))
2792 if (r2->ImmedAnswer != mDNSInterfaceMark &&
2793 r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
2794 r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark;
2795 }
2796 else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked
2797 {
2798 for (r2 = m->ResourceRecords; r2; r2=r2->next)
2799 if (ResourceRecordIsValidAnswer(r2))
2800 if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
2801 r2->ImmedAdditional = rr->ImmedAdditional;
2802 }
2803 }
2804
2805 // Now set SendRNow state appropriately
2806 for (rr = m->ResourceRecords; rr; rr=rr->next)
2807 {
2808 if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces
2809 {
2810 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
2811 rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer
2812 rr->LastMCTime = m->timenow;
2813 rr->LastMCInterface = rr->ImmedAnswer;
2814 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
2815 if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
2816 {
2817 rr->AnnounceCount--;
2818 rr->ThisAPInterval *= 2;
2819 rr->LastAPTime = m->timenow;
2820 debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
2821 }
2822 }
2823 else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface:
2824 {
2825 rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface
2826 rr->ImmedAdditional = mDNSNULL; // No need to send as additional too
2827 rr->LastMCTime = m->timenow;
2828 rr->LastMCInterface = rr->ImmedAnswer;
2829 }
2830 SetNextAnnounceProbeTime(m, rr);
2831 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2832 }
2833
2834 // ***
2835 // *** 2. Loop through interface list, sending records as appropriate
2836 // ***
2837
2838 while (intf)
2839 {
2840 int numDereg = 0;
2841 int numAnnounce = 0;
2842 int numAnswer = 0;
2843 mDNSu8 *responseptr = m->omsg.data;
2844 mDNSu8 *newptr;
2845 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2846
2847 // First Pass. Look for:
2848 // 1. Deregistering records that need to send their goodbye packet
2849 // 2. Updated records that need to retract their old data
2850 // 3. Answers and announcements we need to send
2851 for (rr = m->ResourceRecords; rr; rr=rr->next)
2852 {
2853 if (rr->SendRNow == intf->InterfaceID)
2854 {
2855 newptr = mDNSNULL;
2856 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2857 {
2858 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2859 if (newptr) { responseptr = newptr; numDereg++; }
2860 }
2861 else if (rr->NewRData && !m->SleepState) // If we have new data for this record
2862 {
2863 RData *OldRData = rr->resrec.rdata;
2864 mDNSu16 oldrdlength = rr->resrec.rdlength;
2865 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2866 if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
2867 {
2868 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2869 if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
2870 }
2871 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2872 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
2873 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2874 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2875 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2876 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2877 if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
2878 SetNewRData(&rr->resrec, OldRData, oldrdlength);
2879 }
2880 else
2881 {
2882 mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type);
2883 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2884 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2885 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
2886 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2887 if (newptr)
2888 {
2889 responseptr = newptr;
2890 rr->RequireGoodbye = active;
2891 if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
2892 }
2893
2894 // The first time through (pktcount==0), if this record is verified unique
2895 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2896 if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
2897 }
2898
2899 if (newptr) // If succeeded in sending, advance to next interface
2900 {
2901 // If sending on all interfaces, go to next interface; else we're finished now
2902 if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
2903 rr->SendRNow = GetNextActiveInterfaceID(intf);
2904 else
2905 rr->SendRNow = mDNSNULL;
2906 }
2907 }
2908 }
2909
2910 // Second Pass. Add additional records, if there's space.
2911 newptr = responseptr;
2912 for (rr = m->ResourceRecords; rr; rr=rr->next)
2913 if (rr->ImmedAdditional == intf->InterfaceID)
2914 if (ResourceRecordIsValidAnswer(rr))
2915 {
2916 // If we have at least one answer already in the packet, then plan to add additionals too
2917 mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
2918
2919 // If we're not planning to send any additionals, but this record is a unique one, then
2920 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2921 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2922 if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
2923 {
2924 const AuthRecord *a;
2925 for (a = m->ResourceRecords; a; a=a->next)
2926 if (a->LastMCTime == m->timenow &&
2927 a->LastMCInterface == intf->InterfaceID &&
2928 SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; }
2929 }
2930 if (!SendAdditional) // If we don't want to send this after all,
2931 rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field
2932 else if (newptr) // Else, try to add it if we can
2933 {
2934 // The first time through (pktcount==0), if this record is verified unique
2935 // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2936 if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
2937
2938 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2939 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2940 newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
2941 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2942 if (newptr)
2943 {
2944 responseptr = newptr;
2945 rr->ImmedAdditional = mDNSNULL;
2946 rr->RequireGoodbye = mDNStrue;
2947 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2948 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2949 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2950 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2951 rr->LastMCTime = m->timenow;
2952 rr->LastMCInterface = intf->InterfaceID;
2953 }
2954 }
2955 }
2956
2957 // Third Pass. Add NSEC records, if there's space.
2958 for (rr = m->ResourceRecords; rr; rr=rr->next)
2959 if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID)
2960 {
2961 AuthRecord nsec;
2962 mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
2963 nsec.resrec.rrclass |= kDNSClass_UniqueRRSet;
2964 AssignDomainName(&nsec.namestorage, rr->resrec.name);
2965 mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap));
2966 for (r2 = m->ResourceRecords; r2; r2=r2->next)
2967 if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr))
2968 {
2969 if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; }
2970 else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7);
2971 }
2972 newptr = responseptr;
2973 if (!r2) // If we successfully built our NSEC record, add it to the packet now
2974 {
2975 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
2976 if (newptr) responseptr = newptr;
2977 }
2978
2979 // If we successfully put the NSEC record, clear the SendNSECNow flag
2980 // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
2981 if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1)
2982 {
2983 rr->SendNSECNow = mDNSNULL;
2984 // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
2985 for (r2 = rr->next; r2; r2=r2->next)
2986 if (SameResourceRecordNameClassInterface(r2, rr))
2987 if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID)
2988 r2->SendNSECNow = mDNSNULL;
2989 }
2990 }
2991
2992 if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
2993 {
2994 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2995 numDereg, numDereg == 1 ? "" : "s",
2996 numAnnounce, numAnnounce == 1 ? "" : "s",
2997 numAnswer, numAnswer == 1 ? "" : "s",
2998 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
2999 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
3000 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
3001 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3002 if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
3003 // There might be more things to send on this interface, so go around one more time and try again.
3004 }
3005 else // Nothing more to send on this interface; go to next
3006 {
3007 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3008 #if MDNS_DEBUGMSGS && 0
3009 const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3010 debugf(msg, intf, next);
3011 #endif
3012 intf = next;
3013 pktcount = 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
3014 }
3015 }
3016
3017 // ***
3018 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3019 // ***
3020
3021 if (m->CurrentRecord)
3022 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3023 m->CurrentRecord = m->ResourceRecords;
3024 while (m->CurrentRecord)
3025 {
3026 rr = m->CurrentRecord;
3027 m->CurrentRecord = rr->next;
3028
3029 if (rr->SendRNow)
3030 {
3031 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
3032 LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
3033 rr->SendRNow = mDNSNULL;
3034 }
3035
3036 if (rr->ImmedAnswer)
3037 {
3038 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
3039
3040 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3041 CompleteDeregistration(m, rr); // Don't touch rr after this
3042 else
3043 {
3044 rr->ImmedAnswer = mDNSNULL;
3045 rr->ImmedUnicast = mDNSfalse;
3046 rr->v4Requester = zerov4Addr;
3047 rr->v6Requester = zerov6Addr;
3048 }
3049 }
3050 }
3051 verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
3052 }
3053
3054 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3055 // so we want to be lazy about how frequently we do it.
3056 // 1. If a cache record is currently referenced by *no* active questions,
3057 // then we don't mind expiring it up to a minute late (who will know?)
3058 // 2. Else, if a cache record is due for some of its final expiration queries,
3059 // we'll allow them to be late by up to 2% of the TTL
3060 // 3. Else, if a cache record has completed all its final expiration queries without success,
3061 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3062 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3063 // so allow at most 1/10 second lateness
3064 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
3065 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
3066 #define CacheCheckGracePeriod(RR) ( \
3067 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
3068 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
3069 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
3070 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
3071 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
3072
3073 // Note: MUST call SetNextCacheCheckTime any time we change:
3074 // rr->TimeRcvd
3075 // rr->resrec.rroriginalttl
3076 // rr->UnansweredQueries
3077 // rr->CRActiveQuestion
3078 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3079 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3080 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
3081 {
3082 rr->NextRequiredQuery = RRExpireTime(rr);
3083
3084 // If we have an active question, then see if we want to schedule a refresher query for this record.
3085 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3086 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3087 {
3088 rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
3089 rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
3090 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3091 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
3092 (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
3093 }
3094
3095 if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
3096 m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
3097
3098 if (rr->DelayDelivery)
3099 if (m->NextCacheCheck - rr->DelayDelivery > 0)
3100 m->NextCacheCheck = rr->DelayDelivery;
3101 }
3102
3103 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
3104 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
3105 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
3106 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3107
3108 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
3109 {
3110 if (interval < kMinimumReconfirmTime)
3111 interval = kMinimumReconfirmTime;
3112 if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
3113 interval = 0x10000000;
3114
3115 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3116 if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
3117 {
3118 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3119 // For all the reconfirmations in a given batch, we want to use the same random value
3120 // so that the reconfirmation questions can be grouped into a single query packet
3121 if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
3122 interval += m->RandomReconfirmDelay % ((interval/3) + 1);
3123 rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
3124 rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
3125 SetNextCacheCheckTime(m, rr);
3126 }
3127 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
3128 RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
3129 return(mStatus_NoError);
3130 }
3131
3132 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
3133
3134 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3135 // It also appends to the list of known answer records that need to be included,
3136 // and updates the forcast for the size of the known answer section.
3137 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
3138 CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
3139 {
3140 mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
3141 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3142 const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
3143 mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
3144 if (!newptr)
3145 {
3146 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3147 return(mDNSfalse);
3148 }
3149 else if (newptr + *answerforecast >= limit)
3150 {
3151 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3152 q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
3153 query->h.numQuestions--;
3154 return(mDNSfalse);
3155 }
3156 else
3157 {
3158 mDNSu32 forecast = *answerforecast;
3159 const mDNSu32 slot = HashSlot(&q->qname);
3160 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3161 CacheRecord *rr;
3162 CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
3163
3164 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
3165 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
3166 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
3167 rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
3168 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
3169 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
3170 mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
3171 {
3172 *ka = rr; // Link this record into our known answer chain
3173 ka = &rr->NextInKAList;
3174 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3175 forecast += 12 + rr->resrec.rdestimate;
3176 // If we're trying to put more than one question in this packet, and it doesn't fit
3177 // then undo that last question and try again next time
3178 if (query->h.numQuestions > 1 && newptr + forecast >= limit)
3179 {
3180 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3181 q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
3182 query->h.numQuestions--;
3183 ka = *kalistptrptr; // Go back to where we started and retract these answer records
3184 while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; }
3185 return(mDNSfalse); // Return false, so we'll try again in the next packet
3186 }
3187 }
3188
3189 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3190 *queryptr = newptr; // Update the packet pointer
3191 *answerforecast = forecast; // Update the forecast
3192 *kalistptrptr = ka; // Update the known answer list pointer
3193 if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
3194
3195 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
3196 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
3197 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
3198 SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
3199 {
3200 rr->UnansweredQueries++; // indicate that we're expecting a response
3201 rr->LastUnansweredTime = m->timenow;
3202 SetNextCacheCheckTime(m, rr);
3203 }
3204
3205 return(mDNStrue);
3206 }
3207 }
3208
3209 // When we have a query looking for a specified name, but there appear to be no answers with
3210 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
3211 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
3212 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
3213 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
3214 // A typical reconfirmation scenario might go like this:
3215 // Depth 0: Name "myhost.local" has no address records
3216 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
3217 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
3218 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
3219 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
3220 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
3221 mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth)
3222 {
3223 mDNSu32 slot;
3224 CacheGroup *cg;
3225 CacheRecord *cr;
3226 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c);
3227 FORALL_CACHERECORDS(slot, cg, cr)
3228 {
3229 domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
3230 if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
3231 {
3232 LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
3233 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
3234 if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1);
3235 }
3236 }
3237 }
3238
3239 // If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
3240 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
3241 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
3242 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
3243 mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
3244 {
3245 CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name);
3246 const CacheRecord *cr = cg ? cg->members : mDNSNULL;
3247 while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next;
3248 return(cr);
3249 }
3250
3251 mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1)
3252 {
3253 CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname);
3254 const CacheRecord *cr, *bestcr = mDNSNULL;
3255 mDNSu32 bestmetric = 1000000;
3256 for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
3257 if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6) // If record is PTR type, with long enough name,
3258 if (cr != c0 && cr != c1) // that's not one we've seen before,
3259 if (SameNameRecordAnswersQuestion(&cr->resrec, q)) // and answers our browse query,
3260 if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec)) // and is not our own advertised service...
3261 {
3262 mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c);
3263 if (bestmetric > metric) { bestmetric = metric; bestcr = cr; }
3264 }
3265 return(bestcr);
3266 }
3267
3268 // Finds the three best Sleep Proxies we currently have in our cache
3269 mDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3])
3270 {
3271 sps[0] = FindSPSInCache1(m, q, mDNSNULL, mDNSNULL);
3272 sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], mDNSNULL);
3273 sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], sps[1]);
3274 }
3275
3276 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3277 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
3278 {
3279 int i;
3280 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3281 }
3282
3283 mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
3284 {
3285 int i;
3286 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3287 }
3288
3289 mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
3290 {
3291 int i;
3292 mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3293 mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3294 for (i=0; i<DupSuppressInfoSize; i++)
3295 if (ds[i].InterfaceID == intf->InterfaceID)
3296 {
3297 if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
3298 else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
3299 if (v4 && v6) return(mDNStrue);
3300 }
3301 return(mDNSfalse);
3302 }
3303
3304 mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
3305 {
3306 int i, j;
3307
3308 // See if we have this one in our list somewhere already
3309 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
3310
3311 // If not, find a slot we can re-use
3312 if (i >= DupSuppressInfoSize)
3313 {
3314 i = 0;
3315 for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
3316 if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
3317 i = j;
3318 }
3319
3320 // Record the info about this query we saw
3321 ds[i].Time = Time;
3322 ds[i].InterfaceID = InterfaceID;
3323 ds[i].Type = Type;
3324
3325 return(i);
3326 }
3327
3328 mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
3329 {
3330 // If more than 90% of the way to the query time, we should unconditionally accelerate it
3331 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
3332 return(mDNStrue);
3333
3334 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3335 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
3336 {
3337 // We forecast: qname (n) type (2) class (2)
3338 mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
3339 const mDNSu32 slot = HashSlot(&q->qname);
3340 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3341 const CacheRecord *rr;
3342 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
3343 if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
3344 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
3345 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
3346 rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
3347 {
3348 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3349 forecast += 12 + rr->resrec.rdestimate;
3350 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
3351 }
3352 return(mDNStrue);
3353 }
3354
3355 return(mDNSfalse);
3356 }
3357
3358 // How Standard Queries are generated:
3359 // 1. The Question Section contains the question
3360 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3361
3362 // How Probe Queries are generated:
3363 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3364 // if some other host is already using *any* records with this name, we want to know about it.
3365 // 2. The Authority Section contains the proposed values we intend to use for one or more
3366 // of our records with that name (analogous to the Update section of DNS Update packets)
3367 // because if some other host is probing at the same time, we each want to know what the other is
3368 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3369
3370 mDNSlocal void SendQueries(mDNS *const m)
3371 {
3372 mDNSu32 slot;
3373 CacheGroup *cg;
3374 CacheRecord *cr;
3375 AuthRecord *ar;
3376 int pktcount = 0;
3377 DNSQuestion *q;
3378 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3379 mDNSs32 maxExistingQuestionInterval = 0;
3380 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3381 CacheRecord *KnownAnswerList = mDNSNULL;
3382
3383 // 1. If time for a query, work out what we need to do
3384 if (m->timenow - m->NextScheduledQuery >= 0)
3385 {
3386 CacheRecord *rr;
3387
3388 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
3389 // to their NextRequiredQuery to be worth batching them together with this one
3390 FORALL_CACHERECORDS(slot, cg, rr)
3391 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3392 if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
3393 {
3394 debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
3395 q = rr->CRActiveQuestion;
3396 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
3397 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
3398 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
3399 if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
3400 else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; }
3401 else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID;
3402 else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
3403 }
3404
3405 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
3406 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
3407
3408 // Scan our list of questions to see which:
3409 // *WideArea* queries need to be sent
3410 // *unicast* queries need to be sent
3411 // *multicast* queries we're definitely going to send
3412 if (m->CurrentQuestion)
3413 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3414 m->CurrentQuestion = m->Questions;
3415 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3416 {
3417 q = m->CurrentQuestion;
3418 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
3419 else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
3420 {
3421 mDNSu8 *qptr = m->omsg.data;
3422 const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
3423
3424 // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
3425 if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
3426 if (q->LocalSocket)
3427 {
3428 InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
3429 qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
3430 mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
3431 q->ThisQInterval *= QuestionIntervalStep;
3432 }
3433 if (q->ThisQInterval > MaxQuestionInterval)
3434 q->ThisQInterval = MaxQuestionInterval;
3435 q->LastQTime = m->timenow;
3436 q->LastQTxTime = m->timenow;
3437 q->RecentAnswerPkts = 0;
3438 q->SendQNow = mDNSNULL;
3439 q->ExpectUnicastResp = NonZeroTime(m->timenow);
3440 }
3441 else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
3442 {
3443 //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3444 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
3445 if (maxExistingQuestionInterval < q->ThisQInterval)
3446 maxExistingQuestionInterval = q->ThisQInterval;
3447 }
3448 // If m->CurrentQuestion wasn't modified out from under us, advance it now
3449 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
3450 // m->CurrentQuestion point to the right question
3451 if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
3452 }
3453 m->CurrentQuestion = mDNSNULL;
3454
3455 // Scan our list of questions
3456 // (a) to see if there are any more that are worth accelerating, and
3457 // (b) to update the state variables for *all* the questions we're going to send
3458 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
3459 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
3460 // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
3461 m->NextScheduledQuery = m->timenow + 0x78000000;
3462 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3463 {
3464 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
3465 (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
3466 {
3467 // If at least halfway to next query time, advance to next interval
3468 // If less than halfway to next query time, then
3469 // treat this as logically a repeat of the last transmission, without advancing the interval
3470 if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
3471 {
3472 //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3473 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
3474 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
3475 q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
3476 q->ThisQInterval *= QuestionIntervalStep;
3477 if (q->ThisQInterval > MaxQuestionInterval)
3478 q->ThisQInterval = MaxQuestionInterval;
3479 else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
3480 !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
3481 {
3482 // Generally don't need to log this.
3483 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
3484 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
3485 // and when there simply happen to be no instances of the service the client is looking
3486 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
3487 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3488 q->qname.c, DNSTypeName(q->qtype));
3489 // Sending third query, and no answers yet; time to begin doubting the source
3490 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
3491 }
3492 }
3493
3494 // Mark for sending. (If no active interfaces, then don't even try.)
3495 q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
3496 if (q->SendOnAll)
3497 {
3498 q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
3499 q->LastQTime = m->timenow;
3500 }
3501
3502 // If we recorded a duplicate suppression for this question less than half an interval ago,
3503 // then we consider it recent enough that we don't need to do an identical query ourselves.
3504 ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
3505
3506 q->LastQTxTime = m->timenow;
3507 q->RecentAnswerPkts = 0;
3508 if (q->RequestUnicast) q->RequestUnicast--;
3509 }
3510 // For all questions (not just the ones we're sending) check what the next scheduled event will be
3511 SetNextQueryTime(m,q);
3512 }
3513 }
3514
3515 // 2. Scan our authoritative RR list to see what probes we might need to send
3516 if (m->timenow - m->NextScheduledProbe >= 0)
3517 {
3518 m->NextScheduledProbe = m->timenow + 0x78000000;
3519
3520 if (m->CurrentRecord)
3521 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3522 m->CurrentRecord = m->ResourceRecords;
3523 while (m->CurrentRecord)
3524 {
3525 AuthRecord *rr = m->CurrentRecord;
3526 m->CurrentRecord = rr->next;
3527 if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing...
3528 {
3529 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3530 if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
3531 {
3532 SetNextAnnounceProbeTime(m, rr);
3533 }
3534 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3535 else if (rr->ProbeCount)
3536 {
3537 if (rr->AddressProxy.type == mDNSAddrType_IPv4)
3538 {
3539 LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr));
3540 SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b);
3541 }
3542 else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
3543 {
3544 //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
3545 //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
3546 }
3547 // Mark for sending. (If no active interfaces, then don't even try.)
3548 rr->SendRNow = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID;
3549 rr->LastAPTime = m->timenow;
3550 // When we have a late conflict that resets a record to probing state we use a special marker value greater
3551 // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
3552 if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
3553 rr->ProbeCount = DefaultProbeCountForTypeUnique;
3554 rr->ProbeCount--;
3555 SetNextAnnounceProbeTime(m, rr);
3556 if (rr->ProbeCount == 0)
3557 {
3558 // If this is the last probe for this record, then see if we have any matching records
3559 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
3560 AuthRecord *r2;
3561 for (r2 = m->DuplicateRecords; r2; r2=r2->next)
3562 if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
3563 r2->ProbeCount = 0;
3564 // ... then acknowledge this record to the client.
3565 // We do this optimistically, just as we're about to send the third probe.
3566 // This helps clients that both advertise and browse, and want to filter themselves
3567 // from the browse results list, because it helps ensure that the registration
3568 // confirmation will be delivered 1/4 second *before* the browse "add" event.
3569 // A potential downside is that we could deliver a registration confirmation and then find out
3570 // moments later that there's a name conflict, but applications have to be prepared to handle
3571 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
3572 if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
3573 }
3574 }
3575 // else, if it has now finished probing, move it to state Verified,
3576 // and update m->NextScheduledResponse so it will be announced
3577 else
3578 {
3579 if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow
3580 rr->resrec.RecordType = kDNSRecordTypeVerified;
3581 rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
3582 rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
3583 SetNextAnnounceProbeTime(m, rr);
3584 }
3585 }
3586 }
3587 m->CurrentRecord = m->DuplicateRecords;
3588 while (m->CurrentRecord)
3589 {
3590 AuthRecord *rr = m->CurrentRecord;
3591 m->CurrentRecord = rr->next;
3592 if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
3593 AcknowledgeRecord(m, rr);
3594 }
3595 }
3596
3597 // 3. Now we know which queries and probes we're sending,
3598 // go through our interface list sending the appropriate queries on each interface
3599 while (intf)
3600 {
3601 const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
3602 int OwnerRecordSpace = 0;
3603 AuthRecord *rr;
3604 mDNSu8 *queryptr = m->omsg.data;
3605 mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
3606 InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
3607 if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
3608 if (!KnownAnswerList)
3609 {
3610 // Start a new known-answer list
3611 CacheRecord **kalistptr = &KnownAnswerList;
3612 mDNSu32 answerforecast = 0;
3613
3614 // Put query questions in this packet
3615 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3616 {
3617 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID))
3618 {
3619 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3620 SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ",
3621 q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
3622
3623 // If we're suppressing this question, or we successfully put it, update its SendQNow state
3624 if (SuppressOnThisInterface(q->DupSuppress, intf) ||
3625 BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
3626 q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3627
3628 // Once we've put at least one question, cut back our limit to the normal single-packet size
3629 if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData;
3630 }
3631 }
3632
3633 // Put probe questions in this packet
3634 for (rr = m->ResourceRecords; rr; rr=rr->next)
3635 if (rr->SendRNow == intf->InterfaceID)
3636 {
3637 mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
3638 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3639 mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
3640 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3641 mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
3642 if (newptr && newptr + forecast + os < limit)
3643 {
3644 queryptr = newptr;
3645 limit = m->omsg.data + NormalMaxDNSMessageData;
3646 answerforecast = forecast;
3647 OwnerRecordSpace = os;
3648 rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3649 rr->IncludeInProbe = mDNStrue;
3650 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
3651 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
3652 }
3653 else
3654 {
3655 verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3656 m->omsg.h.numQuestions--;
3657 }
3658 }
3659 }
3660
3661 if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
3662
3663 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3664 while (KnownAnswerList)
3665 {
3666 CacheRecord *ka = KnownAnswerList;
3667 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
3668 mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit);
3669 if (newptr)
3670 {
3671 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
3672 ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
3673 queryptr = newptr;
3674 limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
3675 KnownAnswerList = ka->NextInKAList;
3676 ka->NextInKAList = mDNSNULL;
3677 }
3678 else
3679 {
3680 // If we ran out of space and we have more than one question in the packet, that's an error --
3681 // we shouldn't have put more than one question if there was a risk of us running out of space.
3682 if (m->omsg.h.numQuestions > 1)
3683 LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
3684 m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
3685 break;
3686 }
3687 }
3688
3689 for (rr = m->ResourceRecords; rr; rr=rr->next)
3690 if (rr->IncludeInProbe)
3691 {
3692 mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
3693 rr->IncludeInProbe = mDNSfalse;
3694 if (newptr) queryptr = newptr;
3695 else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
3696 }
3697
3698 if (OwnerRecordSpace)
3699 {
3700 AuthRecord opt;
3701 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
3702 opt.resrec.rrclass = NormalMaxDNSMessageData;
3703 opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
3704 opt.resrec.rdestimate = sizeof(rdataOPT);
3705 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
3706 LogSPS("SendQueries putting %s", ARDisplayString(m, &opt));
3707 queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
3708 &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
3709 if (!queryptr)
3710 LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3711 m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
3712 }
3713
3714 if (queryptr > m->omsg.data)
3715 {
3716 if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
3717 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
3718 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
3719 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
3720 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
3721 m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
3722 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
3723 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
3724 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3725 if (++pktcount >= 1000)
3726 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
3727 // There might be more records left in the known answer list, or more questions to send
3728 // on this interface, so go around one more time and try again.
3729 }
3730 else // Nothing more to send on this interface; go to next
3731 {
3732 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3733 #if MDNS_DEBUGMSGS && 0
3734 const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
3735 debugf(msg, intf, next);
3736 #endif
3737 intf = next;
3738 }
3739 }
3740
3741 // 4. Final housekeeping
3742
3743 // 4a. Debugging check: Make sure we announced all our records
3744 for (ar = m->ResourceRecords; ar; ar=ar->next)
3745 if (ar->SendRNow)
3746 {
3747 if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
3748 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
3749 ar->SendRNow = mDNSNULL;
3750 }
3751
3752 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3753 // that their interface which went away might come back again, the logic will want to send queries
3754 // for those records, but we can't because their interface isn't here any more, so to keep the
3755 // state machine ticking over we just pretend we did so.
3756 // If the interface does not come back in time, the cache record will expire naturally
3757 FORALL_CACHERECORDS(slot, cg, cr)
3758 if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
3759 {
3760 cr->UnansweredQueries++;
3761 cr->CRActiveQuestion->SendQNow = mDNSNULL;
3762 SetNextCacheCheckTime(m, cr);
3763 }
3764
3765 // 4c. Debugging check: Make sure we sent all our planned questions
3766 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3767 // we legitimately couldn't send because the interface is no longer available
3768 for (q = m->Questions; q; q=q->next)
3769 if (q->SendQNow)
3770 {
3771 LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3772 q->SendQNow = mDNSNULL;
3773 }
3774 }
3775
3776 mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password)
3777 {
3778 int i, j;
3779 mDNSu8 *ptr = m->omsg.data;
3780
3781 if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
3782
3783 // 0x00 Destination address
3784 for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
3785
3786 // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
3787 for (i=0; i<6; i++) *ptr++ = 0x0;
3788
3789 // 0x0C Ethertype (0x0842)
3790 *ptr++ = 0x08;
3791 *ptr++ = 0x42;
3792
3793 // 0x0E Wakeup sync sequence
3794 for (i=0; i<6; i++) *ptr++ = 0xFF;
3795
3796 // 0x14 Wakeup data
3797 for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
3798
3799 // 0x74 Password
3800 for (i=0; i<6; i++) *ptr++ = password->b[i];
3801
3802 mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
3803
3804 // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
3805 // broadcast is the only reliable way to get a wakeup packet to the intended target machine.
3806 // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
3807 // key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
3808 // So, we send one of each, unicast first, then broadcast second.
3809 for (i=0; i<6; i++) m->omsg.data[i] = 0xFF;
3810 mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
3811 }
3812
3813 // ***************************************************************************
3814 #if COMPILER_LIKES_PRAGMA_MARK
3815 #pragma mark -
3816 #pragma mark - RR List Management & Task Management
3817 #endif
3818
3819 // Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3820 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
3821 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
3822 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
3823 mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
3824 {
3825 DNSQuestion *const q = m->CurrentQuestion;
3826 mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
3827 rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
3828 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
3829
3830 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
3831 // may be called twice, once when the record is received, and again when it's time to notify local clients.
3832 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3833
3834 rr->LastUsed = m->timenow;
3835 if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
3836 {
3837 if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
3838 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
3839 rr->CRActiveQuestion = q; // We know q is non-null
3840 SetNextCacheCheckTime(m, rr);
3841 }
3842
3843 // If this is:
3844 // (a) a no-cache add, where we've already done at least one 'QM' query, or
3845 // (b) a normal add, where we have at least one unique-type answer,
3846 // then there's no need to keep polling the network.
3847 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3848 // We do this for mDNS questions and uDNS one-shot questions, but not for
3849 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
3850 if ((AddRecord == QC_addnocache && !q->RequestUnicast) ||
3851 (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
3852 if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
3853 {
3854 q->LastQTime = m->timenow;
3855 q->LastQTxTime = m->timenow;
3856 q->RecentAnswerPkts = 0;
3857 q->ThisQInterval = MaxQuestionInterval;
3858 q->RequestUnicast = mDNSfalse;
3859 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3860 }
3861
3862 if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
3863
3864 // Only deliver negative answers if client has explicitly requested them
3865 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)))
3866 if (!AddRecord || !q->ReturnIntermed) return;
3867
3868 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
3869 if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed))
3870 {
3871 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
3872 if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))
3873 {
3874 CacheRecord neg;
3875 MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID);
3876 q->QuestionCallback(m, q, &neg.resrec, AddRecord);
3877 }
3878 else
3879 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
3880 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3881 }
3882 // Note: Proceed with caution here because client callback function is allowed to do anything,
3883 // including starting/stopping queries, registering/deregistering records, etc.
3884
3885 if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
3886 {
3887 const mDNSu32 c = q->CNAMEReferrals + 1;
3888 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
3889 // and track CNAMEs coming and going, we should really create a subordinate query here,
3890 // which we would subsequently cancel and retract if the CNAME referral record were removed.
3891 // In reality this is such a corner case we'll ignore it until someone actually needs it.
3892 LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
3893
3894 // If this query is a duplicate of another query, UpdateQuestionDuplicates called from
3895 // mDNS_StopQuery_internal copies the value of CNAMEReferrals from this query to the other
3896 // query on the Questions list. By setting the new value before calling mDNS_StopQuery_internal,
3897 // we ensure that the duplicate question gets a hgigher value and eventually the check for 10 above
3898 // would be true. Otherwise, the two queries would end up as active questions
3899 // sending mDNSResponder in an infinite loop e.g., Two queries starting off unique but receives
3900 // a CNAME response that refers to itself (test IN CNAME test) which makes it a duplicate of
3901 // one another. This fix now will make sure that stop at the 10th iteration.
3902 //
3903 // Though CNAME records that refer to itself are not added anymore in mDNSCoreReceiveResponse, this fix is
3904 // still needed to catch the cases where the CNAME referral spans across multiple records with a potential
3905 // cycle in it which in turn can make multiple queries duplicate of each other
3906
3907 q->CNAMEReferrals = c;
3908 mDNS_StopQuery_internal(m, q); // Stop old query
3909 AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname
3910 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
3911 mDNS_StartQuery_internal(m, q); // start new query
3912 q->CNAMEReferrals = c; // and keep count of how many times we've done this
3913 }
3914 }
3915
3916 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
3917 {
3918 rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3919 if (m->CurrentQuestion)
3920 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3921 m->CurrentQuestion = m->Questions;
3922 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3923 {
3924 DNSQuestion *q = m->CurrentQuestion;
3925 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3926 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3927 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3928 m->CurrentQuestion = q->next;
3929 }
3930 m->CurrentQuestion = mDNSNULL;
3931 }
3932
3933 mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
3934 {
3935 const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second
3936 const mDNSs32 start = m->timenow - 0x10000000;
3937 mDNSs32 delay = start;
3938 CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
3939 const CacheRecord *rr;
3940 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3941 if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
3942 if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
3943 delay = RRExpireTime(rr);
3944 if (delay - start > 0) return(NonZeroTime(delay));
3945 else return(0);
3946 }
3947
3948 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3949 // If new questions are created as a result of invoking client callbacks, they will be added to
3950 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3951 // rr is a new CacheRecord just received into our cache
3952 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3953 // Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3954 // which may change the record list and/or question list.
3955 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3956 mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
3957 {
3958 DNSQuestion *q;
3959
3960 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3961 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3962 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3963 {
3964 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3965 {
3966 // If this question is one that's actively sending queries, and it's received ten answers within one
3967 // second of sending the last query packet, then that indicates some radical network topology change,
3968 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
3969 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
3970 // because we will anyway send another query within a few seconds. The first reset query is sent out
3971 // randomized over the next four seconds to reduce possible synchronization between machines.
3972 if (q->LastAnswerPktNum != m->PktNum)
3973 {
3974 q->LastAnswerPktNum = m->PktNum;
3975 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
3976 q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
3977 {
3978 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
3979 q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval);
3980 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
3981 q->ThisQInterval = InitialQuestionInterval;
3982 SetNextQueryTime(m,q);
3983 }
3984 }
3985 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
3986 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
3987 q->CurrentAnswers++;
3988 q->unansweredQueries = 0;
3989 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
3990 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
3991 if (q->CurrentAnswers > 4000)
3992 {
3993 static int msgcount = 0;
3994 if (msgcount++ < 10)
3995 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
3996 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
3997 rr->resrec.rroriginalttl = 0;
3998 rr->UnansweredQueries = MaxUnansweredQueries;
3999 }
4000 }
4001 }
4002
4003 if (!rr->DelayDelivery)
4004 {
4005 if (m->CurrentQuestion)
4006 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4007 m->CurrentQuestion = m->Questions;
4008 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4009 {
4010 q = m->CurrentQuestion;
4011 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4012 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
4013 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4014 m->CurrentQuestion = q->next;
4015 }
4016 m->CurrentQuestion = mDNSNULL;
4017 }
4018
4019 SetNextCacheCheckTime(m, rr);
4020 }
4021
4022 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4023 // If new questions are created as a result of invoking client callbacks, they will be added to
4024 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4025 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4026 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4027 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4028 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4029 // Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4030 // which may change the record list and/or question list.
4031 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4032 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
4033 {
4034 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
4035 if (m->CurrentQuestion)
4036 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4037 m->CurrentQuestion = m->Questions;
4038 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
4039 // since we're not caching the record and we'll get no opportunity to do this later
4040 while (m->CurrentQuestion)
4041 {
4042 DNSQuestion *q = m->CurrentQuestion;
4043 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4044 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
4045 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4046 m->CurrentQuestion = q->next;
4047 }
4048 m->CurrentQuestion = mDNSNULL;
4049 }
4050
4051 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
4052 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
4053 // If new questions are created as a result of invoking client callbacks, they will be added to
4054 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4055 // rr is an existing cache CacheRecord that just expired and is being deleted
4056 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4057 // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4058 // which may change the record list and/or question list.
4059 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4060 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
4061 {
4062 if (m->CurrentQuestion)
4063 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4064 m->CurrentQuestion = m->Questions;
4065
4066 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
4067 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
4068 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4069 {
4070 DNSQuestion *q = m->CurrentQuestion;
4071 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4072 {
4073 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
4074 q->FlappingInterface1 = mDNSNULL;
4075 q->FlappingInterface2 = mDNSNULL;
4076 if (q->CurrentAnswers == 0)
4077 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4078 q, q->qname.c, DNSTypeName(q->qtype));
4079 else
4080 {
4081 q->CurrentAnswers--;
4082 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
4083 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
4084 }
4085 if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
4086 {
4087 if (q->CurrentAnswers == 0)
4088 {
4089 LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
4090 q->qname.c, DNSTypeName(q->qtype));
4091 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
4092 }
4093 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
4094 }
4095 }
4096 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
4097 m->CurrentQuestion = q->next;
4098 }
4099 m->CurrentQuestion = mDNSNULL;
4100 }
4101
4102 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
4103 {
4104 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4105 unsigned int i;
4106 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
4107 #endif
4108 e->next = m->rrcache_free;
4109 m->rrcache_free = e;
4110 m->rrcache_totalused--;
4111 }
4112
4113 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
4114 {
4115 CacheEntity *e = (CacheEntity *)(*cp);
4116 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4117 if ((*cp)->rrcache_tail != &(*cp)->members)
4118 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4119 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
4120 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4121 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
4122 (*cp)->name = mDNSNULL;
4123 *cp = (*cp)->next; // Cut record from list
4124 ReleaseCacheEntity(m, e);
4125 }
4126
4127 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
4128 {
4129 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
4130 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
4131 r->resrec.rdata = mDNSNULL;
4132 ReleaseCacheEntity(m, (CacheEntity *)r);
4133 }
4134
4135 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4136 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4137 // callbacks for old records are delivered before callbacks for newer records.
4138 mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
4139 {
4140 CacheRecord **rp = &cg->members;
4141
4142 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4143 m->lock_rrcache = 1;
4144
4145 while (*rp)
4146 {
4147 CacheRecord *const rr = *rp;
4148 mDNSs32 event = RRExpireTime(rr);
4149 if (m->timenow - event >= 0) // If expired, delete it
4150 {
4151 *rp = rr->next; // Cut it from the list
4152 verbosedebugf("CheckCacheExpiration: Deleting%7d %7d %p %s",
4153 m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
4154 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
4155 {
4156 CacheRecordRmv(m, rr);
4157 m->rrcache_active--;
4158 }
4159 ReleaseCacheRecord(m, rr);
4160 }
4161 else // else, not expired; see if we need to query
4162 {
4163 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
4164 event = rr->DelayDelivery;
4165 else
4166 {
4167 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
4168 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
4169 {
4170 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query
4171 event = rr->NextRequiredQuery; // then just record when we want the next query
4172 else // else trigger our question to go out now
4173 {
4174 // Set NextScheduledQuery to timenow so that SendQueries() will run.
4175 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
4176 m->NextScheduledQuery = m->timenow;
4177 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4178 // which will correctly update m->NextCacheCheck for us.
4179 event = m->timenow + 0x3FFFFFFF;
4180 }
4181 }
4182 }
4183 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4184 (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
4185 if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
4186 m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
4187 rp = &rr->next;
4188 }
4189 }
4190 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
4191 cg->rrcache_tail = rp;
4192 m->lock_rrcache = 0;
4193 }
4194
4195 mDNSlocal void AnswerNewQuestion(mDNS *const m)
4196 {
4197 mDNSBool ShouldQueryImmediately = mDNStrue;
4198 DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer
4199 const mDNSu32 slot = HashSlot(&q->qname);
4200 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4201
4202 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4203
4204 if (cg) CheckCacheExpiration(m, cg);
4205 m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4206
4207 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4208 // This should be safe, because calling the client's question callback may cause the
4209 // question list to be modified, but should not ever cause the rrcache list to be modified.
4210 // If the client's question callback deletes the question, then m->CurrentQuestion will
4211 // be advanced, and we'll exit out of the loop
4212 m->lock_rrcache = 1;
4213 if (m->CurrentQuestion)
4214 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4215 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
4216
4217 if (q->NoAnswer == NoAnswer_Fail)
4218 {
4219 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4220 MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
4221 q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
4222 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
4223 q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state
4224 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4225 }
4226
4227 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4228 if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
4229 {
4230 if (m->CurrentRecord)
4231 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4232 m->CurrentRecord = m->ResourceRecords;
4233 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4234 {
4235 AuthRecord *rr = m->CurrentRecord;
4236 m->CurrentRecord = rr->next;
4237 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
4238 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4239 {
4240 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
4241 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4242 }
4243 }
4244 m->CurrentRecord = mDNSNULL;
4245 }
4246
4247 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
4248
4249 if (m->CurrentQuestion == q)
4250 {
4251 CacheRecord *rr;
4252 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4253 if (SameNameRecordAnswersQuestion(&rr->resrec, q))
4254 {
4255 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
4256 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
4257 if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
4258 {
4259 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
4260 rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd);
4261 continue; // Go to next one in loop
4262 }
4263
4264 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
4265 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4266 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
4267 ShouldQueryImmediately = mDNSfalse;
4268 q->CurrentAnswers++;
4269 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4270 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4271 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
4272 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4273 }
4274 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
4275 ShouldQueryImmediately = mDNSfalse;
4276 }
4277
4278 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
4279
4280 if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
4281 {
4282 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4283 q->ThisQInterval = InitialQuestionInterval;
4284 q->LastQTime = m->timenow - q->ThisQInterval;
4285 if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries
4286 {
4287 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
4288 if (!m->RandomQueryDelay)
4289 m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
4290 q->LastQTime += m->RandomQueryDelay;
4291 }
4292
4293 if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
4294 m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
4295 }
4296
4297 m->CurrentQuestion = mDNSNULL;
4298 m->lock_rrcache = 0;
4299 }
4300
4301 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4302 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
4303 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
4304 {
4305 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
4306 m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any)
4307
4308 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4309
4310 if (m->CurrentQuestion)
4311 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4312 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
4313
4314 if (m->CurrentRecord)
4315 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4316 m->CurrentRecord = m->ResourceRecords;
4317
4318 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4319 {
4320 AuthRecord *rr = m->CurrentRecord;
4321 m->CurrentRecord = rr->next;
4322 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4323 {
4324 AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
4325 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
4326 }
4327 }
4328
4329 m->CurrentQuestion = mDNSNULL;
4330 m->CurrentRecord = mDNSNULL;
4331 }
4332
4333 mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4334 {
4335 CacheEntity *e = mDNSNULL;
4336
4337 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4338 m->lock_rrcache = 1;
4339
4340 // If we have no free records, ask the client layer to give us some more memory
4341 if (!m->rrcache_free && m->MainCallback)
4342 {
4343 if (m->rrcache_totalused != m->rrcache_size)
4344 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4345 m->rrcache_totalused, m->rrcache_size);
4346
4347 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4348 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
4349 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4350 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
4351 // and recycle them, instead of allocating more memory.
4352 if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active)
4353 LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4354 m->rrcache_size, m->rrcache_active);
4355 else
4356 {
4357 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
4358 m->MainCallback(m, mStatus_GrowCache);
4359 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
4360 }
4361 }
4362
4363 // If we still have no free records, recycle all the records we can.
4364 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4365 if (!m->rrcache_free)
4366 {
4367 mDNSu32 oldtotalused = m->rrcache_totalused;
4368 mDNSu32 slot;
4369 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4370 {
4371 CacheGroup **cp = &m->rrcache_hash[slot];
4372 while (*cp)
4373 {
4374 CacheRecord **rp = &(*cp)->members;
4375 while (*rp)
4376 {
4377 // Records that answer still-active questions are not candidates for recycling
4378 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4379 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4380 rp=&(*rp)->next;
4381 else
4382 {
4383 CacheRecord *rr = *rp;
4384 *rp = (*rp)->next; // Cut record from list
4385 ReleaseCacheRecord(m, rr);
4386 }
4387 }
4388 if ((*cp)->rrcache_tail != rp)
4389 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4390 (*cp)->rrcache_tail = rp;
4391 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4392 else ReleaseCacheGroup(m, cp);
4393 }
4394 }
4395 LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4396 oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
4397 }
4398
4399 if (m->rrcache_free) // If there are records in the free list, take one
4400 {
4401 e = m->rrcache_free;
4402 m->rrcache_free = e->next;
4403 if (++m->rrcache_totalused >= m->rrcache_report)
4404 {
4405 LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
4406 if (m->rrcache_report < 100) m->rrcache_report += 10;
4407 else if (m->rrcache_report < 1000) m->rrcache_report += 100;
4408 else m->rrcache_report += 1000;
4409 }
4410 mDNSPlatformMemZero(e, sizeof(*e));
4411 }
4412
4413 m->lock_rrcache = 0;
4414
4415 return(e);
4416 }
4417
4418 mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4419 {
4420 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4421 if (r)
4422 {
4423 r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage
4424 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage
4425 {
4426 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4427 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4428 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4429 }
4430 }
4431 return(r);
4432 }
4433
4434 mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4435 {
4436 mDNSu16 namelen = DomainNameLength(rr->name);
4437 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4438 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4439 cg->next = m->rrcache_hash[slot];
4440 cg->namehash = rr->namehash;
4441 cg->members = mDNSNULL;
4442 cg->rrcache_tail = &cg->members;
4443 cg->name = (domainname*)cg->namestorage;
4444 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4445 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4446 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4447 if (!cg->name)
4448 {
4449 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4450 ReleaseCacheEntity(m, (CacheEntity*)cg);
4451 return(mDNSNULL);
4452 }
4453 AssignDomainName(cg->name, rr->name);
4454
4455 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4456 m->rrcache_hash[slot] = cg;
4457 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4458
4459 return(cg);
4460 }
4461
4462 mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4463 {
4464 if (m->mDNS_busy != m->mDNS_reentrancy+1)
4465 LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4466 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
4467 // a positive answer using an expired record (e.g. from an interface that has gone away).
4468 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4469 // summary deletion without giving the proper callback to any questions that are monitoring it.
4470 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4471 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60;
4472 rr->UnansweredQueries = MaxUnansweredQueries;
4473 rr->resrec.rroriginalttl = 0;
4474 SetNextCacheCheckTime(m, rr);
4475 }
4476
4477 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4478 {
4479 mDNSs32 time;
4480 mDNSPlatformLock(m);
4481 if (m->mDNS_busy)
4482 {
4483 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4484 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4485 }
4486
4487 if (m->timenow) time = m->timenow;
4488 else time = mDNS_TimeNow_NoLock(m);
4489 mDNSPlatformUnlock(m);
4490 return(time);
4491 }
4492
4493 // To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4494 // had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4495 // (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4496 #define SetSPSProxyListChanged(X) do { \
4497 if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4498 m->SPSProxyListChanged = (X); } while(0)
4499
4500 // Called from mDNS_Execute() to expire stale proxy records
4501 mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
4502 {
4503 m->CurrentRecord = list;
4504 while (m->CurrentRecord)
4505 {
4506 AuthRecord *rr = m->CurrentRecord;
4507 if (rr->WakeUp.HMAC.l[0])
4508 {
4509 if (m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS
4510 {
4511 if (m->NextScheduledSPS - rr->TimeExpire > 0)
4512 m->NextScheduledSPS = rr->TimeExpire;
4513 }
4514 else // else proxy record expired, so remove it
4515 {
4516 LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4517 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr));
4518 SetSPSProxyListChanged(rr->resrec.InterfaceID);
4519 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
4520 // Don't touch rr after this -- memory may have been free'd
4521 }
4522 }
4523 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
4524 // because the list may have been changed in that call.
4525 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
4526 m->CurrentRecord = rr->next;
4527 }
4528 }
4529
4530 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4531 {
4532 mDNS_Lock(m); // Must grab lock before trying to read m->timenow
4533
4534 if (m->timenow - m->NextScheduledEvent >= 0)
4535 {
4536 int i;
4537
4538 verbosedebugf("mDNS_Execute");
4539 if (m->CurrentQuestion)
4540 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4541
4542 // 1. If we're past the probe suppression time, we can clear it
4543 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4544
4545 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4546 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4547
4548 // 3. Purge our cache of stale old records
4549 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4550 {
4551 mDNSu32 slot;
4552 m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4553 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4554 {
4555 CacheGroup **cp = &m->rrcache_hash[slot];
4556 while (*cp)
4557 {
4558 CheckCacheExpiration(m, *cp);
4559 if ((*cp)->members) cp=&(*cp)->next;
4560 else ReleaseCacheGroup(m, cp);
4561 }
4562 }
4563 }
4564
4565 if (m->timenow - m->NextScheduledSPS >= 0)
4566 {
4567 m->NextScheduledSPS = m->timenow + 0x3FFFFFFF;
4568 CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords
4569 CheckProxyRecords(m, m->ResourceRecords);
4570 }
4571
4572 SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now
4573
4574 if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
4575 {
4576 m->DelaySleep = 0;
4577 if (m->SleepState == SleepState_Transferring)
4578 {
4579 LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4580 BeginSleepProcessing(m);
4581 }
4582 }
4583
4584 // 4. See if we can answer any of our new local questions from the cache
4585 for (i=0; m->NewQuestions && i<1000; i++)
4586 {
4587 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4588 AnswerNewQuestion(m);
4589 }
4590 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4591
4592 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4593 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4594
4595 for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
4596 {
4597 AuthRecord *rr = m->NewLocalRecords;
4598 m->NewLocalRecords = m->NewLocalRecords->next;
4599 AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
4600 }
4601 if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4602
4603 // 5. See what packets we need to send
4604 if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
4605 DiscardDeregistrations(m);
4606 if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
4607 {
4608 // If the platform code is ready, and we're not suppressing packet generation right now
4609 // then send our responses, probes, and questions.
4610 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4611 // We send queries next, because there might be final-stage probes that complete their probing here, causing
4612 // them to advance to announcing state, and we want those to be included in any announcements we send out.
4613 // Finally, we send responses, including the previously mentioned records that just completed probing.
4614 m->SuppressSending = 0;
4615
4616 // 6. Send Query packets. This may cause some probing records to advance to announcing state
4617 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4618 if (m->timenow - m->NextScheduledQuery >= 0)
4619 {
4620 DNSQuestion *q;
4621 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4622 m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
4623 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4624 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
4625 if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
4626 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4627 }
4628 if (m->timenow - m->NextScheduledProbe >= 0)
4629 {
4630 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4631 m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
4632 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4633 }
4634
4635 // 7. Send Response packets, including probing records just advanced to announcing state
4636 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4637 if (m->timenow - m->NextScheduledResponse >= 0)
4638 {
4639 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4640 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4641 }
4642 }
4643
4644 // Clear RandomDelay values, ready to pick a new different value next time
4645 m->RandomQueryDelay = 0;
4646 m->RandomReconfirmDelay = 0;
4647 }
4648
4649 // Note about multi-threaded systems:
4650 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4651 // performing mDNS API operations that change our next scheduled event time.
4652 //
4653 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
4654 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4655 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4656 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4657 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4658 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4659 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4660 // without blocking. This avoids the race condition between the signal from the other thread arriving
4661 // just *before* or just *after* the main thread enters the blocking primitive.
4662 //
4663 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4664 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4665 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4666 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4667 // by the time it gets to the timer callback function).
4668
4669 #ifndef UNICAST_DISABLED
4670 uDNS_Execute(m);
4671 #endif
4672 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4673 return(m->NextScheduledEvent);
4674 }
4675
4676 mDNSlocal void SuspendLLQs(mDNS *m)
4677 {
4678 DNSQuestion *q;
4679 for (q = m->Questions; q; q = q->next)
4680 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established)
4681 { q->ReqLease = 0; sendLLQRefresh(m, q); }
4682 }
4683
4684 // ActivateUnicastQuery() is called from three places:
4685 // 1. When a new question is created
4686 // 2. On wake from sleep
4687 // 3. When the DNS configuration changes
4688 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4689 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4690 mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
4691 {
4692 // For now this AutoTunnel stuff is specific to Mac OS X.
4693 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4694 #if APPLE_OSX_mDNSResponder
4695 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4696 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4697 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4698 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4699 // returns results for both at the same time.
4700 if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
4701 {
4702 question->NoAnswer = NoAnswer_Suspended;
4703 AddNewClientTunnel(m, question);
4704 return;
4705 }
4706 #endif // APPLE_OSX_mDNSResponder
4707
4708 if (!question->DuplicateOf)
4709 {
4710 debugf("ActivateUnicastQuery: %##s %s%s%s",
4711 question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
4712 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
4713 if (question->LongLived)
4714 {
4715 question->state = LLQ_InitialRequest;
4716 question->id = zeroOpaque64;
4717 question->servPort = zeroIPPort;
4718 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
4719 }
4720 if (ScheduleImmediately)
4721 {
4722 question->ThisQInterval = InitialQuestionInterval;
4723 question->LastQTime = m->timenow - question->ThisQInterval;
4724 SetNextQueryTime(m, question);
4725 }
4726 }
4727 }
4728
4729 mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
4730 {
4731 DNSQuestion *q;
4732
4733 #ifndef UNICAST_DISABLED
4734 // Retrigger all our uDNS questions
4735 if (m->CurrentQuestion)
4736 LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4737 m->CurrentQuestion = m->Questions;
4738 while (m->CurrentQuestion)
4739 {
4740 q = m->CurrentQuestion;
4741 m->CurrentQuestion = m->CurrentQuestion->next;
4742 if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
4743 }
4744 #endif
4745
4746 // Retrigger all our mDNS questions
4747 for (q = m->Questions; q; q=q->next) // Scan our list of questions
4748 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
4749 {
4750 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
4751 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
4752 q->LastQTime = m->timenow - q->ThisQInterval;
4753 q->RecentAnswerPkts = 0;
4754 ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4755 m->NextScheduledQuery = m->timenow;
4756 }
4757 }
4758
4759 // ***************************************************************************
4760 #if COMPILER_LIKES_PRAGMA_MARK
4761 #pragma mark -
4762 #pragma mark - Power Management (Sleep/Wake)
4763 #endif
4764
4765 mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
4766 {
4767 const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
4768 const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace;
4769 const int sps = intf->NextSPSAttempt / 3;
4770 AuthRecord *rr;
4771
4772 if (!intf->SPSAddr[sps].type)
4773 {
4774 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
4775 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
4776 m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
4777 LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c);
4778 goto exit;
4779 }
4780
4781 // Mark our mDNS records (not unicast records) for transfer to SPS
4782 if (mDNSOpaque16IsZero(id))
4783 for (rr = m->ResourceRecords; rr; rr=rr->next)
4784 if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
4785 if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
4786 rr->SendRNow = mDNSInterfaceMark; // mark it now
4787
4788 while (1)
4789 {
4790 mDNSu8 *p = m->omsg.data;
4791 // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4792 // For now we follow that same logic for SPS registrations too.
4793 // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4794 // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4795 InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags);
4796
4797 for (rr = m->ResourceRecords; rr; rr=rr->next)
4798 if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0))
4799 {
4800 mDNSu8 *newptr;
4801 const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace;
4802 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
4803 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
4804 newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
4805 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
4806 if (!newptr)
4807 LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr));
4808 else
4809 {
4810 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr));
4811 rr->SendRNow = mDNSNULL;
4812 rr->ThisAPInterval = mDNSPlatformOneSecond;
4813 rr->LastAPTime = m->timenow;
4814 rr->updateid = m->omsg.h.id;
4815 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4816 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
4817 p = newptr;
4818 }
4819 }
4820
4821 if (!m->omsg.h.mDNS_numUpdates) break;
4822 else
4823 {
4824 AuthRecord opt;
4825 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
4826 opt.resrec.rrclass = NormalMaxDNSMessageData;
4827 opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record
4828 opt.resrec.rdestimate = sizeof(rdataOPT) * 2;
4829 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
4830 opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4;
4831 opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE;
4832 SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]);
4833 LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt));
4834 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
4835 if (!p)
4836 LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt));
4837 else
4838 {
4839 mStatus err;
4840 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
4841 mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
4842 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
4843 err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL);
4844 if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
4845 if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1)
4846 {
4847 LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c);
4848 intf->NetWakeResolve[sps].qtype = kDNSType_A;
4849 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]);
4850 return;
4851 }
4852 }
4853 }
4854 }
4855
4856 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime
4857
4858 exit:
4859 if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++;
4860 }
4861
4862 // RetrySPSRegistrations is called from SendResponses, with the lock held
4863 mDNSlocal void RetrySPSRegistrations(mDNS *const m)
4864 {
4865 AuthRecord *rr;
4866 NetworkInterfaceInfo *intf;
4867
4868 // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4869 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4870 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10)
4871 intf->NextSPSAttemptTime++;
4872
4873 // Retry any record registrations that are due
4874 for (rr = m->ResourceRecords; rr; rr=rr->next)
4875 if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4876 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4877 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID)
4878 {
4879 LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr));
4880 SendSPSRegistration(m, intf, rr->updateid);
4881 }
4882
4883 // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4884 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4885 if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8)
4886 intf->NextSPSAttempt++;
4887 }
4888
4889 mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4890 {
4891 NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext;
4892 int sps = question - intf->NetWakeResolve;
4893 (void)m; // Unused
4894 LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer));
4895
4896 if (!AddRecord) return; // Don't care about REMOVE events
4897 if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
4898
4899 // if (answer->rrtype == kDNSType_AAAA) return; // To test failing to resolve sleep proxy's address
4900
4901 mDNS_StopQuery(m, question);
4902 question->ThisQInterval = -1;
4903
4904 if (answer->rrtype == kDNSType_SRV)
4905 {
4906 intf->SPSPort[sps] = answer->rdata->u.srv.port;
4907 AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
4908 question->qtype = kDNSType_AAAA;
4909 mDNS_StartQuery(m, question);
4910 }
4911 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
4912 {
4913 intf->SPSAddr[sps].type = mDNSAddrType_IPv6;
4914 intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6;
4915 mDNS_Lock(m);
4916 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now
4917 mDNS_Unlock(m);
4918 }
4919 else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) // If negative answer for IPv6, look for IPv4 addresses instead
4920 {
4921 LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c);
4922 question->qtype = kDNSType_A;
4923 mDNS_StartQuery(m, question);
4924 }
4925 else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr))
4926 {
4927 intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
4928 intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
4929 mDNS_Lock(m);
4930 if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now
4931 mDNS_Unlock(m);
4932 }
4933 }
4934
4935 mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m)
4936 {
4937 AuthRecord *rr;
4938 for (rr = m->ResourceRecords; rr; rr=rr->next)
4939 if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort))
4940 return mDNStrue;
4941 return mDNSfalse;
4942 }
4943
4944 mDNSlocal void SendSleepGoodbyes(mDNS *const m)
4945 {
4946 AuthRecord *rr;
4947 m->SleepState = SleepState_Sleeping;
4948
4949 #ifndef UNICAST_DISABLED
4950 SleepServiceRegistrations(m);
4951 SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records
4952 #endif
4953
4954 // Mark all the records we need to deregister and send them
4955 for (rr = m->ResourceRecords; rr; rr=rr->next)
4956 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
4957 rr->ImmedAnswer = mDNSInterfaceMark;
4958 SendResponses(m);
4959 }
4960
4961 // BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
4962 mDNSlocal void BeginSleepProcessing(mDNS *const m)
4963 {
4964 mDNSBool SendGoodbyes = mDNStrue;
4965 const CacheRecord *sps[3] = { mDNSNULL };
4966
4967 m->NextScheduledSPRetry = m->timenow;
4968
4969 if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
4970 else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services");
4971 else // If we have at least one advertised service
4972 {
4973 NetworkInterfaceInfo *intf;
4974 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4975 {
4976 if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname);
4977 #if APPLE_OSX_mDNSResponder
4978 else if (ActivateLocalProxy(m, intf->ifname) == mStatus_NoError)
4979 {
4980 SendGoodbyes = mDNSfalse;
4981 LogSPS("BeginSleepProcessing: %-6s using local proxy", intf->ifname);
4982 // This will leave m->SleepState set to SleepState_Transferring,
4983 // which is okay because with no outstanding resolves, or updates in flight,
4984 // mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
4985 }
4986 #endif // APPLE_OSX_mDNSResponder
4987 else
4988 {
4989 FindSPSInCache(m, &intf->NetWakeBrowse, sps);
4990 if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval);
4991 else
4992 {
4993 int i;
4994 SendGoodbyes = mDNSfalse;
4995 intf->NextSPSAttempt = 0;
4996 intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
4997 // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
4998 for (i=0; i<3; i++)
4999 {
5000 #if ForceAlerts
5001 if (intf->SPSAddr[i].type)
5002 { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; }
5003 if (intf->NetWakeResolve[i].ThisQInterval >= 0)
5004 { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; }
5005 #endif
5006 intf->SPSAddr[i].type = mDNSAddrType_None;
5007 if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]);
5008 intf->NetWakeResolve[i].ThisQInterval = -1;
5009 if (sps[i])
5010 {
5011 LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i]));
5012 mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf);
5013 intf->NetWakeResolve[i].ReturnIntermed = mDNStrue;
5014 mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]);
5015 }
5016 }
5017 }
5018 }
5019 }
5020 }
5021
5022 if (SendGoodbyes) // If we didn't find even one Sleep Proxy
5023 {
5024 LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
5025 SendSleepGoodbyes(m);
5026 }
5027 }
5028
5029 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
5030 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
5031 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
5032 mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
5033 {
5034 AuthRecord *rr;
5035
5036 mDNS_Lock(m);
5037
5038 LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
5039
5040 if (sleep && !m->SleepState) // Going to sleep
5041 {
5042 // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5043 if (m->SPSSocket)
5044 {
5045 mDNSu8 oldstate = m->SPSState;
5046 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5047 m->SPSState = 2;
5048 if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords);
5049 mDNS_ReclaimLockAfterCallback();
5050 }
5051
5052 m->SleepState = SleepState_Transferring;
5053 if (m->SystemWakeOnLANEnabled && m->DelaySleep)
5054 {
5055 // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5056 LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
5057 m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10;
5058 }
5059 else
5060 {
5061 m->DelaySleep = 0;
5062 m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10;
5063 BeginSleepProcessing(m);
5064 }
5065
5066 #ifndef UNICAST_DISABLED
5067 SuspendLLQs(m);
5068 #endif
5069 LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
5070 m->SleepState == SleepState_Transferring ? "Transferring" :
5071 m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
5072 }
5073 else if (!sleep) // Waking up
5074 {
5075 mDNSu32 slot;
5076 CacheGroup *cg;
5077 CacheRecord *cr;
5078 NetworkInterfaceInfo *intf;
5079
5080 // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5081 if (m->SleepState != SleepState_Awake)
5082 {
5083 m->SleepState = SleepState_Awake;
5084 m->SleepSeqNum++;
5085 // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5086 // then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5087 // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5088 // before we make our determination of whether there's a Sleep Proxy out there we should register with.
5089 m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16);
5090 }
5091
5092 if (m->SPSState == 3)
5093 {
5094 mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5095 m->SPSState = 0;
5096 mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
5097 mDNS_ReclaimLockAfterCallback();
5098 }
5099
5100 // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5101 // on wake we go through our record list and clear updateid back to zero
5102 for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID;
5103
5104 // ... and the same for NextSPSAttempt
5105 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
5106
5107 // Restart unicast and multicast queries
5108 mDNSCoreRestartQueries(m);
5109
5110 // and reactivtate service registrations
5111 m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
5112 LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
5113
5114 // 2. Re-validate our cache records
5115 m->NextCacheCheck = m->timenow;
5116 FORALL_CACHERECORDS(slot, cg, cr)
5117 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
5118
5119 // 3. Retrigger probing and announcing for all our authoritative records
5120 for (rr = m->ResourceRecords; rr; rr=rr->next)
5121 if (AuthRecord_uDNS(rr))
5122 {
5123 ActivateUnicastRegistration(m, rr);
5124 }
5125 else
5126 {
5127 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
5128 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
5129 rr->AnnounceCount = InitialAnnounceCount;
5130 InitializeLastAPTime(m, rr);
5131 }
5132
5133 // 4. Refresh NAT mappings
5134 // We don't want to have to assume that all hardware can necessarily keep accurate
5135 // track of passage of time while asleep, so on wake we refresh our NAT mappings
5136 m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
5137 m->retryGetAddr = m->timenow;
5138 RecreateNATMappings(m);
5139 }
5140
5141 mDNS_Unlock(m);
5142 }
5143
5144 mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
5145 {
5146 DNSQuestion *q;
5147 AuthRecord *rr;
5148 ServiceRecordSet *srs;
5149 NetworkInterfaceInfo *intf;
5150
5151 mDNS_Lock(m);
5152
5153 if (m->DelaySleep) goto notready;
5154
5155 // If we've not hit the sleep limit time, and it's not time for our next retry, we can skip these checks
5156 if (m->SleepLimit - now > 0 && m->NextScheduledSPRetry - now > 0) goto notready;
5157
5158 m->NextScheduledSPRetry = now + 0x40000000UL;
5159
5160 // See if we might need to retransmit any lost Sleep Proxy Registrations
5161 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5162 if (intf->NextSPSAttempt >= 0)
5163 {
5164 if (now - intf->NextSPSAttemptTime >= 0)
5165 {
5166 LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt);
5167 SendSPSRegistration(m, intf, zeroID);
5168 // Don't need to "goto notready" here, becase if we do still have record registrations
5169 // that have not been acknowledged yet, we'll catch that in the record list scan below.
5170 }
5171 else
5172 if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
5173 m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
5174 }
5175
5176 // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
5177 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5178 if (intf->NetWakeResolve[0].ThisQInterval >= 0)
5179 {
5180 LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
5181 goto spsnotready;
5182 }
5183
5184 // Scan list of registered records
5185 for (rr = m->ResourceRecords; rr; rr = rr->next)
5186 if (!AuthRecord_uDNS(rr))
5187 if (!mDNSOpaque16IsZero(rr->updateid))
5188 { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; }
5189
5190 // Scan list of private LLQs, and make sure they've all completed their handshake with the server
5191 for (q = m->Questions; q; q = q->next)
5192 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
5193 {
5194 LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5195 goto notready;
5196 }
5197
5198 // Scan list of registered records
5199 for (rr = m->ResourceRecords; rr; rr = rr->next)
5200 if (AuthRecord_uDNS(rr))
5201 if (rr->state == regState_Refresh && rr->tcp)
5202 { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
5203
5204 // Scan list of registered services
5205 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
5206 if (srs->state == regState_NoTarget && srs->tcp) goto notready;
5207
5208 mDNS_Unlock(m);
5209 return mDNStrue;
5210
5211 spsnotready:
5212
5213 // If we failed to complete sleep proxy registration within ten seconds, we give up on that
5214 // and allow up to ten seconds more to complete wide-area deregistration instead
5215 if (now - m->SleepLimit >= 0)
5216 {
5217 LogMsg("Failed to register with SPS, now sending goodbyes");
5218
5219 for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5220 if (intf->NetWakeBrowse.ThisQInterval >= 0)
5221 {
5222 LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
5223 mDNS_DeactivateNetWake_internal(m, intf);
5224 }
5225
5226 for (rr = m->ResourceRecords; rr; rr = rr->next)
5227 if (!AuthRecord_uDNS(rr))
5228 if (!mDNSOpaque16IsZero(rr->updateid))
5229 {
5230 LogSPS("ReadyForSleep clearing updateid for %s", ARDisplayString(m, rr));
5231 rr->updateid = zeroID;
5232 }
5233
5234 // We'd really like to allow up to ten seconds more here,
5235 // but if we don't respond to the sleep notification within 30 seconds
5236 // we'll be put back to sleep forcibly without the chance to schedule the next maintenance wake.
5237 // Right now we wait 16 sec after wake for all the interfaces to come up, then we wait up to 10 seconds
5238 // more for SPS resolves and record registrations to complete, which puts us at 26 seconds.
5239 // If we allow just one more second to send our goodbyes, that puts us at 27 seconds.
5240 m->SleepLimit = now + mDNSPlatformOneSecond * 1;
5241
5242 SendSleepGoodbyes(m);
5243 }
5244
5245 notready:
5246 mDNS_Unlock(m);
5247 return mDNSfalse;
5248 }
5249
5250 mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
5251 {
5252 AuthRecord *ar;
5253
5254 // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5255 // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5256 // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5257 // and if that happens we don't want to just give up and go back to sleep and never try again.
5258 mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes
5259
5260 NATTraversalInfo *nat;
5261 for (nat = m->NATTraversals; nat; nat=nat->next)
5262 if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4)
5263 {
5264 mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time
5265 if (e - t > 0) e = t;
5266 LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5267 nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
5268 mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
5269 nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
5270 nat->retryInterval / mDNSPlatformOneSecond,
5271 nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
5272 (t - now) / mDNSPlatformOneSecond);
5273 }
5274
5275 // This loop checks both the time we need to renew wide-area registrations,
5276 // and the time we need to renew Sleep Proxy registrations
5277 for (ar = m->ResourceRecords; ar; ar = ar->next)
5278 if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4)
5279 {
5280 mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time
5281 if (e - t > 0) e = t;
5282 LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5283 ar, ar->ThisAPInterval / mDNSPlatformOneSecond,
5284 (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
5285 ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
5286 (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar));
5287 }
5288
5289 return(e - now);
5290 }
5291
5292 // ***************************************************************************
5293 #if COMPILER_LIKES_PRAGMA_MARK
5294 #pragma mark -
5295 #pragma mark - Packet Reception Functions
5296 #endif
5297
5298 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5299
5300 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
5301 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
5302 {
5303 mDNSu8 *responseptr = response->data;
5304 const mDNSu8 *const limit = response->data + sizeof(response->data);
5305 const mDNSu8 *ptr = query->data;
5306 AuthRecord *rr;
5307 mDNSu32 maxttl = 0x70000000;
5308 int i;
5309
5310 // Initialize the response fields so we can answer the questions
5311 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
5312
5313 // ***
5314 // *** 1. Write out the list of questions we are actually going to answer with this packet
5315 // ***
5316 if (LegacyQuery)
5317 {
5318 maxttl = 10;
5319 for (i=0; i<query->h.numQuestions; i++) // For each question...
5320 {
5321 DNSQuestion q;
5322 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question...
5323 if (!ptr) return(mDNSNULL);
5324
5325 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers
5326 {
5327 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question
5328 { // then put the question in the question section
5329 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
5330 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
5331 break; // break out of the ResponseRecords loop, and go on to the next question
5332 }
5333 }
5334 }
5335
5336 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
5337 }
5338
5339 // ***
5340 // *** 2. Write Answers
5341 // ***
5342 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5343 if (rr->NR_AnswerTo)
5344 {
5345 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec,
5346 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5347 if (p) responseptr = p;
5348 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
5349 }
5350
5351 // ***
5352 // *** 3. Write Additionals
5353 // ***
5354 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5355 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
5356 {
5357 mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec,
5358 maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5359 if (p) responseptr = p;
5360 else debugf("GenerateUnicastResponse: No more space for additionals");
5361 }
5362
5363 return(responseptr);
5364 }
5365
5366 // AuthRecord *our is our Resource Record
5367 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5368 // Returns 0 if there is no conflict
5369 // Returns +1 if there was a conflict and we won
5370 // Returns -1 if there was a conflict and we lost and have to rename
5371 mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt)
5372 {
5373 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
5374 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
5375 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5376 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5377
5378 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
5379 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
5380 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
5381 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict
5382
5383 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost
5384 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won
5385 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost
5386 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won
5387
5388 LogMsg("CompareRData ERROR: Invalid state");
5389 return(-1);
5390 }
5391
5392 // See if we have an authoritative record that's identical to this packet record,
5393 // whose canonical DependentOn record is the specified master record.
5394 // The DependentOn pointer is typically used for the TXT record of service registrations
5395 // It indicates that there is no inherent conflict detection for the TXT record
5396 // -- it depends on the SRV record to resolve name conflicts
5397 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
5398 // pointer chain (if any) to make sure we reach the canonical DependentOn record
5399 // If the record has no DependentOn, then just return that record's pointer
5400 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5401 mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
5402 {
5403 const AuthRecord *r1;
5404 for (r1 = m->ResourceRecords; r1; r1=r1->next)
5405 {
5406 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
5407 {
5408 const AuthRecord *r2 = r1;
5409 while (r2->DependentOn) r2 = r2->DependentOn;
5410 if (r2 == master) return(mDNStrue);
5411 }
5412 }
5413 for (r1 = m->DuplicateRecords; r1; r1=r1->next)
5414 {
5415 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
5416 {
5417 const AuthRecord *r2 = r1;
5418 while (r2->DependentOn) r2 = r2->DependentOn;
5419 if (r2 == master) return(mDNStrue);
5420 }
5421 }
5422 return(mDNSfalse);
5423 }
5424
5425 // Find the canonical RRSet pointer for this RR received in a packet.
5426 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
5427 // pointers (if any) to make sure we return the canonical member of this name/type/class
5428 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
5429 mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
5430 {
5431 const AuthRecord *rr;
5432 for (rr = m->ResourceRecords; rr; rr=rr->next)
5433 {
5434 if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
5435 {
5436 while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
5437 return(rr);
5438 }
5439 }
5440 return(mDNSNULL);
5441 }
5442
5443 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
5444 // as one of our records (our) but different rdata.
5445 // 1. If our record is not a type that's supposed to be unique, we don't care.
5446 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
5447 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
5448 // points to our record, ignore this conflict (e.g. the packet record matches one of our
5449 // TXT records, and that record is marked as dependent on 'our', its SRV record).
5450 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
5451 // are members of the same RRSet, then this is not a conflict.
5452 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
5453 {
5454 // If not supposed to be unique, not a conflict
5455 if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
5456
5457 // If a dependent record, not a conflict
5458 if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
5459 else
5460 {
5461 // If the pktrr matches a member of ourset, not a conflict
5462 const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
5463 const AuthRecord *pktset = FindRRSet(m, pktrr);
5464 if (pktset == ourset) return(mDNSfalse);
5465
5466 // For records we're proxying, where we don't know the full
5467 // relationship between the records, having any matching record
5468 // in our AuthRecords list is sufficient evidence of non-conflict
5469 if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse);
5470 }
5471
5472 // Okay, this is a conflict
5473 return(mDNStrue);
5474 }
5475
5476 // Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
5477 // the record list and/or question list.
5478 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5479 mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
5480 DNSQuestion *q, AuthRecord *our)
5481 {
5482 int i;
5483 const mDNSu8 *ptr = LocateAuthorities(query, end);
5484 mDNSBool FoundUpdate = mDNSfalse;
5485
5486 for (i = 0; i < query->h.numAuthorities; i++)
5487 {
5488 ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
5489 if (!ptr) break;
5490 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5491 {
5492 FoundUpdate = mDNStrue;
5493 if (PacketRRConflict(m, our, &m->rec.r))
5494 {
5495 int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
5496 if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype;
5497 if (!result) result = CompareRData(our, &m->rec.r);
5498 if (result)
5499 {
5500 const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: ";
5501 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5502 LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
5503 }
5504 // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network.
5505 // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
5506 // If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
5507 if (result < 0)
5508 {
5509 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
5510 our->ProbeCount = DefaultProbeCountForTypeUnique;
5511 our->AnnounceCount = InitialAnnounceCount;
5512 InitializeLastAPTime(m, our);
5513 goto exit;
5514 }
5515 }
5516 #if 0
5517 else
5518 {
5519 LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5520 LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our->resrec.rdatahash, ARDisplayString(m, our));
5521 }
5522 #endif
5523 }
5524 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5525 }
5526 if (!FoundUpdate)
5527 LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
5528 exit:
5529 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5530 }
5531
5532 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr)
5533 {
5534 mDNSu32 slot = HashSlot(pktrr->name);
5535 CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
5536 CacheRecord *rr;
5537 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5538 if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
5539 return(rr);
5540 }
5541
5542 // Called from ProcessQuery when we get an mDNS packet with an owner record in it
5543 mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
5544 {
5545 m->CurrentRecord = thelist;
5546 while (m->CurrentRecord)
5547 {
5548 AuthRecord *const rr = m->CurrentRecord;
5549 if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
5550 if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60)
5551 {
5552 LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
5553 m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
5554 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
5555 SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
5556 }
5557 // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
5558 // because the list may have been changed in that call.
5559 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
5560 m->CurrentRecord = rr->next;
5561 }
5562 }
5563
5564 // ProcessQuery examines a received query to see if we have any answers to give
5565 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
5566 const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
5567 mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
5568 {
5569 mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5570 AuthRecord *ResponseRecords = mDNSNULL;
5571 AuthRecord **nrp = &ResponseRecords;
5572 CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated
5573 CacheRecord **eap = &ExpectedAnswers;
5574 DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet
5575 DNSQuestion **dqp = &DupQuestions;
5576 mDNSs32 delayresponse = 0;
5577 mDNSBool SendLegacyResponse = mDNSfalse;
5578 const mDNSu8 *ptr;
5579 mDNSu8 *responseptr = mDNSNULL;
5580 AuthRecord *rr;
5581 int i;
5582
5583 // ***
5584 // *** 1. Look in Additional Section for an OPT record
5585 // ***
5586 ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space);
5587 if (ptr)
5588 {
5589 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec);
5590 if (m->rec.r.resrec.rrtype == kDNSType_OPT)
5591 {
5592 const rdataOPT *opt;
5593 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
5594 // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
5595 // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
5596 for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++)
5597 if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0])
5598 {
5599 ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords);
5600 ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords);
5601 }
5602 }
5603 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5604 }
5605
5606 // ***
5607 // *** 2. Parse Question Section and mark potential answers
5608 // ***
5609 ptr = query->data;
5610 for (i=0; i<query->h.numQuestions; i++) // For each question...
5611 {
5612 mDNSBool QuestionNeedsMulticastResponse;
5613 int NumAnswersForThisQuestion = 0;
5614 AuthRecord *NSECAnswer = mDNSNULL;
5615 DNSQuestion pktq, *q;
5616 ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
5617 if (!ptr) goto exit;
5618
5619 // The only queries that *need* a multicast response are:
5620 // * Queries sent via multicast
5621 // * from port 5353
5622 // * that don't have the kDNSQClass_UnicastResponse bit set
5623 // These queries need multicast responses because other clients will:
5624 // * suppress their own identical questions when they see these questions, and
5625 // * expire their cache records if they don't see the expected responses
5626 // For other queries, we may still choose to send the occasional multicast response anyway,
5627 // to keep our neighbours caches warm, and for ongoing conflict detection.
5628 QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
5629 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
5630 pktq.qclass &= ~kDNSQClass_UnicastResponse;
5631
5632 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
5633 // can result in user callbacks which may change the record list and/or question list.
5634 // Also note: we just mark potential answer records here, without trying to build the
5635 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
5636 // from that list while we're in the middle of trying to build it.
5637 if (m->CurrentRecord)
5638 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
5639 m->CurrentRecord = m->ResourceRecords;
5640 while (m->CurrentRecord)
5641 {
5642 rr = m->CurrentRecord;
5643 m->CurrentRecord = rr->next;
5644 if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
5645 {
5646 if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
5647 {
5648 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
5649 ResolveSimultaneousProbe(m, query, end, &pktq, rr);
5650 else if (ResourceRecordIsValidAnswer(rr))
5651 {
5652 NumAnswersForThisQuestion++;
5653 // Note: We should check here if this is a probe-type query, and if so, generate an immediate
5654 // unicast answer back to the source, because timeliness in answering probes is important.
5655
5656 // Notes:
5657 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
5658 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
5659 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
5660 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
5661 // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
5662 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
5663 if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
5664 {
5665 // We only mark this question for sending if it is at least one second since the last time we multicast it
5666 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
5667 // This is to guard against the case where someone blasts us with queries as fast as they can.
5668 if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
5669 (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
5670 rr->NR_AnswerTo = (mDNSu8*)~0;
5671 }
5672 else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
5673 }
5674 }
5675 else if (rr->resrec.RecordType == kDNSRecordTypeVerified)
5676 {
5677 // If we don't have any answers for this question, but we do own another record with the same name,
5678 // then mark it to generate an NSEC record on this interface
5679 if (!NSECAnswer) NSECAnswer = rr;
5680 }
5681 }
5682 }
5683
5684 if (NumAnswersForThisQuestion == 0 && NSECAnswer)
5685 {
5686 NumAnswersForThisQuestion++;
5687 NSECAnswer->SendNSECNow = InterfaceID;
5688 m->NextScheduledResponse = m->timenow;
5689 }
5690
5691 // If we couldn't answer this question, someone else might be able to,
5692 // so use random delay on response to reduce collisions
5693 if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
5694
5695 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5696 if (QuestionNeedsMulticastResponse)
5697 #else
5698 // We only do the following accelerated cache expiration and duplicate question suppression processing
5699 // for non-truncated multicast queries with multicast responses.
5700 // For any query generating a unicast response we don't do this because we can't assume we will see the response.
5701 // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
5702 // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
5703 if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC))
5704 #endif
5705 {
5706 const mDNSu32 slot = HashSlot(&pktq.qname);
5707 CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
5708 CacheRecord *cr;
5709
5710 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
5711 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5712 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5713 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5714 #endif
5715 for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
5716 if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
5717 if (!cr->NextInKAList && eap != &cr->NextInKAList)
5718 {
5719 *eap = cr;
5720 eap = &cr->NextInKAList;
5721 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5722 if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
5723 {
5724 // Although MPUnansweredQ is only really used for multi-packet query processing,
5725 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
5726 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
5727 cr->MPUnansweredQ++;
5728 cr->MPLastUnansweredQT = m->timenow;
5729 cr->MPExpectingKA = mDNStrue;
5730 }
5731 #endif
5732 }
5733
5734 // Check if this question is the same as any of mine.
5735 // We only do this for non-truncated queries. Right now it would be too complicated to try
5736 // to keep track of duplicate suppression state between multiple packets, especially when we
5737 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
5738 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5739 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5740 #endif
5741 for (q = m->Questions; q; q=q->next)
5742 if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
5743 if (!q->InterfaceID || q->InterfaceID == InterfaceID)
5744 if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
5745 if (q->qtype == pktq.qtype &&
5746 q->qclass == pktq.qclass &&
5747 q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
5748 { *dqp = q; dqp = &q->NextInDQList; }
5749 }
5750 }
5751
5752 // ***
5753 // *** 3. Now we can safely build the list of marked answers
5754 // ***
5755 for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers
5756 if (rr->NR_AnswerTo) // If we marked the record...
5757 AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list
5758
5759 // ***
5760 // *** 4. Add additional records
5761 // ***
5762 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
5763
5764 // ***
5765 // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
5766 // ***
5767 for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section...
5768 {
5769 // Get the record...
5770 CacheRecord *ourcacherr;
5771 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
5772 if (!ptr) goto exit;
5773
5774 // See if this Known-Answer suppresses any of our currently planned answers
5775 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5776 if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5777 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5778
5779 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5780 for (rr=m->ResourceRecords; rr; rr=rr->next)
5781 {
5782 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5783 if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5784 {
5785 if (srcaddr->type == mDNSAddrType_IPv4)
5786 {
5787 if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
5788 }
5789 else if (srcaddr->type == mDNSAddrType_IPv6)
5790 {
5791 if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
5792 }
5793 if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
5794 {
5795 rr->ImmedAnswer = mDNSNULL;
5796 rr->ImmedUnicast = mDNSfalse;
5797 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5798 LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
5799 #endif
5800 }
5801 }
5802 }
5803
5804 ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
5805
5806 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5807 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5808 // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
5809 if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
5810 {
5811 ourcacherr->MPUnansweredKA++;
5812 ourcacherr->MPExpectingKA = mDNSfalse;
5813 }
5814 #endif
5815
5816 // Having built our ExpectedAnswers list from the questions in this packet, we then remove
5817 // any records that are suppressed by the Known Answer list in this packet.
5818 eap = &ExpectedAnswers;
5819 while (*eap)
5820 {
5821 CacheRecord *cr = *eap;
5822 if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
5823 { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
5824 else eap = &cr->NextInKAList;
5825 }
5826
5827 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5828 if (!ourcacherr)
5829 {
5830 dqp = &DupQuestions;
5831 while (*dqp)
5832 {
5833 DNSQuestion *q = *dqp;
5834 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5835 { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
5836 else dqp = &q->NextInDQList;
5837 }
5838 }
5839 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5840 }
5841
5842 // ***
5843 // *** 6. Cancel any additionals that were added because of now-deleted records
5844 // ***
5845 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5846 if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
5847 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5848
5849 // ***
5850 // *** 7. Mark the send flags on the records we plan to send
5851 // ***
5852 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5853 {
5854 if (rr->NR_AnswerTo)
5855 {
5856 mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response
5857 mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response)
5858
5859 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5860 if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
5861 {
5862 SendMulticastResponse = mDNStrue;
5863 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5864 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5865 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5866 if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
5867 }
5868
5869 // If the client insists on a multicast response, then we'd better send one
5870 if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
5871 else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue;
5872 else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue;
5873
5874 if (SendMulticastResponse || SendUnicastResponse)
5875 {
5876 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5877 rr->ImmedAnswerMarkTime = m->timenow;
5878 #endif
5879 m->NextScheduledResponse = m->timenow;
5880 // If we're already planning to send this on another interface, just send it on all interfaces
5881 if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
5882 rr->ImmedAnswer = mDNSInterfaceMark;
5883 else
5884 {
5885 rr->ImmedAnswer = InterfaceID; // Record interface to send it on
5886 if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
5887 if (srcaddr->type == mDNSAddrType_IPv4)
5888 {
5889 if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4;
5890 else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
5891 }
5892 else if (srcaddr->type == mDNSAddrType_IPv6)
5893 {
5894 if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6;
5895 else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
5896 }
5897 }
5898 }
5899 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5900 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5901 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5902 // else, for a simple unique record reply, we can reply immediately; no need for delay
5903 if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms
5904 else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
5905 }
5906 else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
5907 {
5908 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
5909 // If two clients on different interfaces do queries that invoke the same optional additional answer,
5910 // then the earlier client is out of luck
5911 rr->ImmedAdditional = InterfaceID;
5912 // No need to set m->NextScheduledResponse here
5913 // We'll send these additional records when we send them, or not, as the case may be
5914 }
5915 }
5916
5917 // ***
5918 // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
5919 // ***
5920 if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
5921 {
5922 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5923 mDNSs32 oldss = m->SuppressSending;
5924 if (oldss && delayresponse)
5925 LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
5926 #endif
5927 // Pick a random delay:
5928 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
5929 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5930 // This is an integer value, with resolution determined by the platform clock rate.
5931 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
5932 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5933 // The +49 before dividing is to ensure we round up, not down, to ensure that even
5934 // on platforms where the native clock rate is less than fifty ticks per second,
5935 // we still guarantee that the final calculated delay is at least one platform tick.
5936 // We want to make sure we don't ever allow the delay to be zero ticks,
5937 // because if that happens we'll fail the Bonjour Conformance Test.
5938 // Our final computed delay is 20-120ms for normal delayed replies,
5939 // or 400-500ms in the case of multi-packet known-answer lists.
5940 m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
5941 if (m->SuppressSending == 0) m->SuppressSending = 1;
5942 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5943 if (oldss && delayresponse)
5944 LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow);
5945 #endif
5946 }
5947
5948 // ***
5949 // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5950 // ***
5951 if (SendLegacyResponse)
5952 responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
5953
5954 exit:
5955 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5956
5957 // ***
5958 // *** 10. Finally, clear our link chains ready for use next time
5959 // ***
5960 while (ResponseRecords)
5961 {
5962 rr = ResponseRecords;
5963 ResponseRecords = rr->NextResponse;
5964 rr->NextResponse = mDNSNULL;
5965 rr->NR_AnswerTo = mDNSNULL;
5966 rr->NR_AdditionalTo = mDNSNULL;
5967 }
5968
5969 while (ExpectedAnswers)
5970 {
5971 CacheRecord *cr = ExpectedAnswers;
5972 ExpectedAnswers = cr->NextInKAList;
5973 cr->NextInKAList = mDNSNULL;
5974
5975 // For non-truncated queries, we can definitively say that we should expect
5976 // to be seeing a response for any records still left in the ExpectedAnswers list
5977 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5978 if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond)
5979 {
5980 cr->UnansweredQueries++;
5981 cr->LastUnansweredTime = m->timenow;
5982 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5983 if (cr->UnansweredQueries > 1)
5984 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5985 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
5986 #endif
5987 SetNextCacheCheckTime(m, cr);
5988 }
5989
5990 // If we've seen multiple unanswered queries for this record,
5991 // then mark it to expire in five seconds if we don't get a response by then.
5992 if (cr->UnansweredQueries >= MaxUnansweredQueries)
5993 {
5994 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5995 // Only show debugging message if this record was not about to expire anyway
5996 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
5997 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5998 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
5999 #endif
6000 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
6001 }
6002 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6003 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
6004 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
6005 // possible packet loss of up to 20% of the additional KA packets.)
6006 else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8)
6007 {
6008 // We want to do this conservatively.
6009 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
6010 // then we don't want them to all hit the network simultaneously with their final expiration queries.
6011 // By setting the record to expire in four minutes, we achieve two things:
6012 // (a) the 90-95% final expiration queries will be less bunched together
6013 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
6014 mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4;
6015 if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
6016 remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
6017
6018 // Only show debugging message if this record was not about to expire anyway
6019 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
6020 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
6021 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
6022
6023 if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
6024 cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query
6025 cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics
6026 cr->MPUnansweredKA = 0;
6027 cr->MPExpectingKA = mDNSfalse;
6028
6029 if (remain < kDefaultReconfirmTimeForNoAnswer)
6030 remain = kDefaultReconfirmTimeForNoAnswer;
6031 mDNS_Reconfirm_internal(m, cr, remain);
6032 }
6033 #endif
6034 }
6035
6036 while (DupQuestions)
6037 {
6038 DNSQuestion *q = DupQuestions;
6039 DupQuestions = q->NextInDQList;
6040 q->NextInDQList = mDNSNULL;
6041 i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
6042 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
6043 srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
6044 }
6045
6046 return(responseptr);
6047 }
6048
6049 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
6050 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
6051 const mDNSInterfaceID InterfaceID)
6052 {
6053 mDNSu8 *responseend = mDNSNULL;
6054 mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr &&
6055 !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
6056
6057 if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
6058 {
6059 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6060 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
6061 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
6062 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
6063 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
6064 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
6065 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
6066 return;
6067 }
6068
6069 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6070 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6071 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
6072 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
6073 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
6074 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
6075 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
6076
6077 responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
6078 !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
6079
6080 if (responseend) // If responseend is non-null, that means we built a unicast response packet
6081 {
6082 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
6083 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
6084 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
6085 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
6086 srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
6087 mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL);
6088 }
6089 }
6090
6091 #if 0
6092 mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
6093 {
6094 DNSServer *s;
6095 (void)m; // Unused
6096 (void)srcaddr; // Unused
6097 for (s = m->DNSServers; s; s = s->next)
6098 if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
6099 return(mDNSfalse);
6100 }
6101 #endif
6102
6103 struct UDPSocket_struct
6104 {
6105 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
6106 };
6107
6108 mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question)
6109 {
6110 DNSQuestion *q;
6111 for (q = m->Questions; q; q=q->next)
6112 if (q->LocalSocket &&
6113 mDNSSameIPPort (q->LocalSocket->port, port) &&
6114 mDNSSameOpaque16(q->TargetQID, id) &&
6115 q->qtype == question->qtype &&
6116 q->qclass == question->qclass &&
6117 q->qnamehash == question->qnamehash &&
6118 SameDomainName(&q->qname, &question->qname))
6119 return(q);
6120 return(mDNSNULL);
6121 }
6122
6123 mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr)
6124 {
6125 DNSQuestion *q;
6126 (void)id;
6127 (void)srcaddr;
6128 for (q = m->Questions; q; q=q->next)
6129 if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q))
6130 {
6131 if (!mDNSOpaque16IsZero(q->TargetQID))
6132 {
6133 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr));
6134 if (mDNSSameOpaque16(q->TargetQID, id))
6135 {
6136 if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue);
6137 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
6138 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
6139 // if (TrustedSource(m, srcaddr)) return(mDNStrue);
6140 LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
6141 q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
6142 return(mDNSfalse);
6143 }
6144 }
6145 else
6146 {
6147 if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
6148 return(mDNStrue);
6149 }
6150 }
6151 return(mDNSfalse);
6152 }
6153
6154 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
6155 // Currently this applies only to rdata types containing more than one domainname,
6156 // or types where the domainname is not the last item in the structure.
6157 // In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
6158 mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr)
6159 {
6160 switch (rr->rrtype)
6161 {
6162 case kDNSType_SOA: return sizeof(rdataSOA);
6163 case kDNSType_RP: return sizeof(rdataRP);
6164 case kDNSType_PX: return sizeof(rdataPX);
6165 case kDNSType_NSEC:return sizeof(rdataNSEC);
6166 default: return rr->rdlength;
6167 }
6168 }
6169
6170 mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
6171 {
6172 CacheRecord *rr = mDNSNULL;
6173 mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec);
6174
6175 if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r));
6176
6177 //if (RDLength > InlineCacheRDSize)
6178 // LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
6179
6180 if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now
6181 if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg
6182 if (!rr) NoCacheAnswer(m, &m->rec.r);
6183 else
6184 {
6185 RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
6186 *rr = m->rec.r; // Block copy the CacheRecord object
6187 rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
6188 rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
6189
6190 // If this is an oversized record with external storage allocated, copy rdata to external storage
6191 if (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize)
6192 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
6193 else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && RDLength <= InlineCacheRDSize)
6194 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
6195 if (RDLength > InlineCacheRDSize)
6196 mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
6197
6198 rr->next = mDNSNULL; // Clear 'next' pointer
6199 *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
6200 cg->rrcache_tail = &(rr->next); // Advance tail pointer
6201 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
6202 rr->DelayDelivery = NonZeroTime(m->timenow);
6203 else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique,
6204 rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have
6205 rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event
6206 else
6207 rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
6208
6209 CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
6210 }
6211 return(rr);
6212 }
6213
6214 mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
6215 {
6216 rr->TimeRcvd = m->timenow;
6217 rr->resrec.rroriginalttl = ttl;
6218 rr->UnansweredQueries = 0;
6219 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6220 rr->MPUnansweredQ = 0;
6221 rr->MPUnansweredKA = 0;
6222 rr->MPExpectingKA = mDNSfalse;
6223 #endif
6224 SetNextCacheCheckTime(m, rr);
6225 }
6226
6227 mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
6228 {
6229 CacheRecord *rr;
6230 const mDNSu32 slot = HashSlot(&q->qname);
6231 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
6232 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6233 if (rr->CRActiveQuestion == q)
6234 {
6235 //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
6236 RefreshCacheRecord(m, rr, lease);
6237 }
6238 }
6239
6240 mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds
6241 {
6242 if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease;
6243 else if (LLQType == uDNS_LLQ_Events)
6244 {
6245 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
6246 if (ttl == 0xFFFFFFFF) ttl = 0;
6247 else ttl = kLLQ_DefLease;
6248 }
6249 else // else not LLQ (standard uDNS response)
6250 {
6251 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
6252 // also do this check here to make sure we can't get overflow below when we add a quarter to the TTL
6253 if (ttl > 0x60000000UL / mDNSPlatformOneSecond) ttl = 0x60000000UL / mDNSPlatformOneSecond;
6254
6255 // Adjustment factor to avoid race condition:
6256 // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
6257 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
6258 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
6259 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
6260 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
6261 // the cached copy at our local caching server will already have expired, so the server will be forced
6262 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
6263 ttl += ttl/4 + 2;
6264
6265 // For mDNS, TTL zero means "delete this record"
6266 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
6267 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
6268 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
6269 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
6270 if (ttl < 15) ttl = 15;
6271 }
6272
6273 return ttl;
6274 }
6275
6276 // Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
6277 // the record list and/or question list.
6278 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6279 // InterfaceID non-NULL tells us the interface this multicast response was received on
6280 // InterfaceID NULL tells us this was a unicast response
6281 // dstaddr NULL tells us we received this over an outgoing TCP connection we made
6282 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
6283 const DNSMessage *const response, const mDNSu8 *end,
6284 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
6285 const mDNSInterfaceID InterfaceID)
6286 {
6287 int i;
6288 mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
6289 mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
6290 uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
6291
6292 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
6293 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
6294 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
6295 CacheRecord *CacheFlushRecords = (CacheRecord*)1;
6296 CacheRecord **cfp = &CacheFlushRecords;
6297
6298 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
6299 // to guard against spoof responses, then the only credible protection against that is cryptographic
6300 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
6301 int firstauthority = response->h.numAnswers;
6302 int firstadditional = firstauthority + response->h.numAuthorities;
6303 int totalrecords = firstadditional + response->h.numAdditionals;
6304 const mDNSu8 *ptr = response->data;
6305
6306 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
6307 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
6308 srcaddr, dstaddr, InterfaceID,
6309 response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
6310 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
6311 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
6312 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
6313
6314 // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
6315 // When a DNS client receives a reply with TC
6316 // set, it should ignore that response, and query again, using a
6317 // mechanism, such as a TCP connection, that will permit larger replies.
6318 // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
6319 // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
6320 // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
6321 // <rdar://problem/6690034> Can't bind to Active Directory
6322 // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
6323 // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
6324 // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
6325 // and not even do the TCP query.
6326 // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
6327 if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return;
6328
6329 if (LLQType == uDNS_LLQ_Ignore) return;
6330
6331 // 1. We ignore questions (if any) in mDNS response packets
6332 // 2. If this is an LLQ response, we handle it much the same
6333 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
6334 // answer as being the authoritative complete RRSet, and respond by deleting all other
6335 // matching cache records that don't appear in this packet.
6336 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
6337 if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC))
6338 ptr = LocateAnswers(response, end);
6339 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
6340 // in this response packet are immediately deemed to be invalid.
6341 else
6342 {
6343 mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask);
6344 mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth);
6345 mDNSBool returnEarly = mDNSfalse;
6346 // We could possibly combine this with the similar loop at the end of this function --
6347 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
6348 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
6349 // which it was received (or refreshed), and then at the end if we find any cache records which
6350 // answer questions in this packet's question section, but which aren't tagged with this packet's
6351 // packet number, then we deduce they are old and delete them
6352 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
6353 {
6354 DNSQuestion q, *qptr = mDNSNULL;
6355 ptr = getQuestion(response, ptr, end, InterfaceID, &q);
6356 if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))))
6357 {
6358 if (!failure)
6359 {
6360 CacheRecord *rr;
6361 const mDNSu32 slot = HashSlot(&q.qname);
6362 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
6363 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6364 if (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q))
6365 {
6366 debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
6367 rr->resrec.InterfaceID, CRDisplayString(m, rr));
6368 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
6369 rr->TimeRcvd = m->timenow - TicksTTL(rr) - 1;
6370 rr->UnansweredQueries = MaxUnansweredQueries;
6371 }
6372 }
6373 else
6374 {
6375 if (qptr)
6376 {
6377 LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
6378 PushDNSServerToEnd(m, qptr);
6379 }
6380 returnEarly = mDNStrue;
6381 }
6382 }
6383 }
6384 if (returnEarly)
6385 {
6386 LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
6387 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
6388 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
6389 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
6390 // not goto exit because we won't have any CacheFlushRecords and we do not want to
6391 // generate negative cache entries (we want to query the next server)
6392 return;
6393 }
6394 }
6395
6396 for (i = 0; i < totalrecords && ptr && ptr < end; i++)
6397 {
6398 // All responses sent via LL multicast are acceptable for caching
6399 // All responses received over our outbound TCP connections are acceptable for caching
6400 mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
6401 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
6402 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
6403
6404 const mDNSu8 RecordType =
6405 (i < firstauthority ) ? (mDNSu8)kDNSRecordTypePacketAns :
6406 (i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd;
6407 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
6408 if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting
6409
6410 // Don't want to cache OPT or TSIG pseudo-RRs
6411 if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
6412 { m->rec.r.resrec.RecordType = 0; continue; }
6413
6414 // if a CNAME record points to itself, then don't add it to the cache
6415 if ((m->rec.r.resrec.rrtype == kDNSType_CNAME) && SameDomainName(m->rec.r.resrec.name, &m->rec.r.resrec.rdata->u.name))
6416 {
6417 LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m->rec.r.resrec.name->c);
6418 m->rec.r.resrec.RecordType = 0;
6419 continue;
6420 }
6421
6422 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
6423 // In the case of active LLQs, we'll get remove events when the records actually do go away
6424 // In the case of polling LLQs, we assume the record remains valid until the next poll
6425 if (!mDNSOpaque16IsZero(response->h.id))
6426 m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
6427
6428 // If response was not sent via LL multicast,
6429 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
6430 if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
6431
6432 // 1. Check that this packet resource record does not conflict with any of ours
6433 if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
6434 {
6435 if (m->CurrentRecord)
6436 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
6437 m->CurrentRecord = m->ResourceRecords;
6438 while (m->CurrentRecord)
6439 {
6440 AuthRecord *rr = m->CurrentRecord;
6441 m->CurrentRecord = rr->next;
6442 // We accept all multicast responses, and unicast responses resulting from queries we issued
6443 // For other unicast responses, this code accepts them only for responses with an
6444 // (apparently) local source address that pertain to a record of our own that's in probing state
6445 if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue;
6446
6447 if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match...
6448 {
6449 // ... check to see if type and rdata are identical
6450 if (IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
6451 {
6452 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
6453 if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
6454 {
6455 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
6456 if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
6457 }
6458 else
6459 {
6460 if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; }
6461 else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
6462 }
6463 }
6464 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
6465 else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
6466 {
6467 LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
6468 LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
6469
6470 // If this record is marked DependentOn another record for conflict detection purposes,
6471 // then *that* record has to be bumped back to probing state to resolve the conflict
6472 if (rr->DependentOn)
6473 {
6474 while (rr->DependentOn) rr = rr->DependentOn;
6475 LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
6476 }
6477
6478 // If we've just whacked this record's ProbeCount, don't need to do it again
6479 if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
6480 LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr));
6481 else if (rr->ProbeCount == DefaultProbeCountForTypeUnique)
6482 LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr));
6483 else
6484 {
6485 LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r));
6486 // If we'd previously verified this record, put it back to probing state and try again
6487 if (rr->resrec.RecordType == kDNSRecordTypeVerified)
6488 {
6489 LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m, rr));
6490 rr->resrec.RecordType = kDNSRecordTypeUnique;
6491 // We set ProbeCount to one more than the usual value so we know we've already touched this record.
6492 // This is because our single probe for "example-name.local" could yield a response with (say) two A records and
6493 // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
6494 // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
6495 rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
6496 rr->AnnounceCount = InitialAnnounceCount;
6497 InitializeLastAPTime(m, rr);
6498 RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
6499 }
6500 // If we're probing for this record, we just failed
6501 else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
6502 {
6503 LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr));
6504 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
6505 }
6506 // We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
6507 // different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
6508 else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
6509 {
6510 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
6511 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
6512 }
6513 else
6514 LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
6515 }
6516 }
6517 // Else, matching signature, different type or rdata, but not a considered a conflict.
6518 // If the packet record has the cache-flush bit set, then we check to see if we
6519 // have any record(s) of the same type that we should re-assert to rescue them
6520 // (see note about "multi-homing and bridged networks" at the end of this function).
6521 else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
6522 if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
6523 { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
6524 }
6525 }
6526 }
6527
6528 if (!AcceptableResponse)
6529 {
6530 const CacheRecord *cr;
6531 for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
6532 {
6533 domainname *target = GetRRDomainNameTarget(&cr->resrec);
6534 if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name))
6535 { AcceptableResponse = mDNStrue; break; }
6536 }
6537 }
6538
6539 // 2. See if we want to add this packet resource record to our cache
6540 // We only try to cache answers if we have a cache to put them in
6541 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
6542 if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
6543 if (m->rrcache_size && AcceptableResponse)
6544 {
6545 const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
6546 CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
6547 CacheRecord *rr;
6548
6549 // 2a. Check if this packet resource record is already in our cache
6550 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6551 {
6552 // If we found this exact resource record, refresh its TTL
6553 if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
6554 {
6555 if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
6556 verbosedebugf("Found record size %5d interface %p already in cache: %s",
6557 m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
6558 rr->TimeRcvd = m->timenow;
6559
6560 if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
6561 {
6562 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
6563 if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
6564 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
6565
6566 // If this packet record is marked unique, and our previous cached copy was not, then fix it
6567 if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
6568 {
6569 DNSQuestion *q;
6570 for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
6571 rr->resrec.RecordType = m->rec.r.resrec.RecordType;
6572 }
6573 }
6574
6575 if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
6576 {
6577 // If the rdata of the packet record differs in name capitalization from the record in our cache
6578 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
6579 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
6580 rr->resrec.rroriginalttl = 0;
6581 rr->UnansweredQueries = MaxUnansweredQueries;
6582 SetNextCacheCheckTime(m, rr);
6583 // DO NOT break out here -- we want to continue as if we never found it
6584 }
6585 else if (m->rec.r.resrec.rroriginalttl > 0)
6586 {
6587 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
6588 RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
6589 break;
6590 }
6591 else
6592 {
6593 // If the packet TTL is zero, that means we're deleting this record.
6594 // To give other hosts on the network a chance to protest, we push the deletion
6595 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
6596 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
6597 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
6598 debugf("DE for %s", CRDisplayString(m, rr));
6599 rr->resrec.rroriginalttl = 1;
6600 rr->UnansweredQueries = MaxUnansweredQueries;
6601 SetNextCacheCheckTime(m, rr);
6602 break;
6603 }
6604 }
6605 }
6606
6607 // If packet resource record not in our cache, add it now
6608 // (unless it is just a deletion of a record we never had, in which case we don't care)
6609 if (!rr && m->rec.r.resrec.rroriginalttl > 0)
6610 {
6611 rr = CreateNewCacheEntry(m, slot, cg);
6612 if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
6613 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
6614 }
6615 }
6616 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6617 }
6618
6619 exit:
6620 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6621
6622 // If we've just received one or more records with their cache flush bits set,
6623 // then scan that cache slot to see if there are any old stale records we need to flush
6624 while (CacheFlushRecords != (CacheRecord*)1)
6625 {
6626 CacheRecord *r1 = CacheFlushRecords, *r2;
6627 const mDNSu32 slot = HashSlot(r1->resrec.name);
6628 const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
6629 CacheFlushRecords = CacheFlushRecords->NextInCFList;
6630 r1->NextInCFList = mDNSNULL;
6631
6632 // Look for records in the cache with the same signature as this new one with the cache flush
6633 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
6634 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
6635 // We make these TTL adjustments *only* for records that still have *more* than one second
6636 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
6637 // (and now has half a second remaining) could inadvertently get its life extended, by either
6638 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
6639 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
6640 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
6641 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
6642 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
6643 // To avoid this, we need to ensure that the cache flushing operation will only act to
6644 // *decrease* a record's remaining lifetime, never *increase* it.
6645 for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
6646 if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
6647 r1->resrec.rrtype == r2->resrec.rrtype &&
6648 r1->resrec.rrclass == r2->resrec.rrclass)
6649 {
6650 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
6651 // else, if record is old, mark it to be flushed
6652 if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
6653 {
6654 // If we find mismatched TTLs in an RRSet, correct them.
6655 // We only do this for records with a TTL of 2 or higher. It's possible to have a
6656 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
6657 // which we treat as a goodbye followed by an addition) and in that case it would be
6658 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
6659 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
6660 // because certain early Bonjour devices are known to have this specific mismatch, and
6661 // there's no point filling syslog with messages about something we already know about.
6662 // We also don't log this for uDNS responses, since a caching name server is obliged
6663 // to give us an aged TTL to correct for how long it has held the record,
6664 // so our received TTLs are expected to vary in that case
6665 if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
6666 {
6667 if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
6668 mDNSOpaque16IsZero(response->h.id))
6669 LogInfo("Correcting TTL from %4d to %4d for %s",
6670 r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
6671 r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
6672 }
6673 r2->TimeRcvd = m->timenow;
6674 }
6675 else // else, if record is old, mark it to be flushed
6676 {
6677 verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
6678 // We set stale records to expire in one second.
6679 // This gives the owner a chance to rescue it if necessary.
6680 // This is important in the case of multi-homing and bridged networks:
6681 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
6682 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
6683 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
6684 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
6685 // By delaying the deletion by one second, we give X a change to notice that this bridging has
6686 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
6687
6688 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
6689 // final expiration queries for this record.
6690
6691 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
6692 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
6693 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
6694 if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
6695 {
6696 debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
6697 r2->resrec.rroriginalttl = 0;
6698 m->NextCacheCheck = m->timenow;
6699 m->NextScheduledEvent = m->timenow;
6700 }
6701 else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
6702 {
6703 // We only set a record to expire in one second if it currently has *more* than a second to live
6704 // If it's already due to expire in a second or less, we just leave it alone
6705 r2->resrec.rroriginalttl = 1;
6706 r2->UnansweredQueries = MaxUnansweredQueries;
6707 r2->TimeRcvd = m->timenow - 1;
6708 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
6709 // that we marked for deletion via an explicit DE record
6710 }
6711 }
6712 SetNextCacheCheckTime(m, r2);
6713 }
6714 if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
6715 {
6716 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
6717 r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
6718 if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
6719 }
6720 }
6721
6722 // See if we need to generate negative cache entries for unanswered unicast questions
6723 ptr = response->data;
6724 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
6725 {
6726 DNSQuestion q;
6727 ptr = getQuestion(response, ptr, end, InterfaceID, &q);
6728 if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
6729 {
6730 // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
6731 // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
6732 // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
6733 // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
6734 // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
6735 // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
6736 // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
6737 // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
6738 // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
6739 // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
6740 if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
6741 LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
6742 else
6743 {
6744 CacheRecord *rr, *neg = mDNSNULL;
6745 mDNSu32 slot = HashSlot(&q.qname);
6746 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
6747 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6748 if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
6749 {
6750 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
6751 if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break;
6752 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
6753 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
6754 }
6755
6756 if (!rr)
6757 {
6758 // We start off assuming a negative caching TTL of 60 seconds
6759 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
6760 mDNSu32 negttl = 60;
6761 int repeat = 0;
6762 const domainname *name = &q.qname;
6763 mDNSu32 hash = q.qnamehash;
6764
6765 // Special case for our special Microsoft Active Directory "local SOA" check.
6766 // Some cheap home gateways don't include an SOA record in the authority section when
6767 // they send negative responses, so we don't know how long to cache the negative result.
6768 // Because we don't want to keep hitting the root name servers with our query to find
6769 // if we're on a network using Microsoft Active Directory using "local" as a private
6770 // internal top-level domain, we make sure to cache the negative result for at least one day.
6771 if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24;
6772
6773 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
6774 if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
6775 {
6776 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
6777 if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
6778 {
6779 const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
6780 mDNSu32 ttl_s = soa->min;
6781 // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
6782 // for the SOA record for ".", where the record is reported as non-cacheable
6783 // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
6784 if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0])
6785 ttl_s = m->rec.r.resrec.rroriginalttl;
6786 if (negttl < ttl_s) negttl = ttl_s;
6787
6788 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
6789 // with an Authority Section SOA record for d.com, then this is a hint that the authority
6790 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
6791 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
6792 if (q.qtype == kDNSType_SOA)
6793 {
6794 int qcount = CountLabels(&q.qname);
6795 int scount = CountLabels(m->rec.r.resrec.name);
6796 if (qcount - 1 > scount)
6797 if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
6798 repeat = qcount - 1 - scount;
6799 }
6800 }
6801 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6802 }
6803
6804 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
6805 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
6806 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
6807 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
6808 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
6809 // so that we back off our polling rate and don't keep hitting the server continually.
6810 if (neg)
6811 {
6812 if (negttl < neg->resrec.rroriginalttl * 2)
6813 negttl = neg->resrec.rroriginalttl * 2;
6814 if (negttl > 3600)
6815 negttl = 3600;
6816 }
6817
6818 negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary
6819
6820 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
6821 if (neg)
6822 {
6823 debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
6824 RefreshCacheRecord(m, neg, negttl);
6825 }
6826 else while (1)
6827 {
6828 debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
6829 MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any);
6830 CreateNewCacheEntry(m, slot, cg);
6831 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6832 if (!repeat) break;
6833 repeat--;
6834 name = (const domainname *)(name->c + 1 + name->c[0]);
6835 hash = DomainNameHashValue(name);
6836 slot = HashSlot(name);
6837 cg = CacheGroupForName(m, slot, hash, name);
6838 }
6839 }
6840 }
6841 }
6842 }
6843 }
6844
6845 mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result)
6846 {
6847 if (result && result != mStatus_MemFree)
6848 LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar));
6849
6850 if (result == mStatus_NameConflict)
6851 {
6852 LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
6853 InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
6854 SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password);
6855 }
6856 else if (result == mStatus_MemFree)
6857 {
6858 m->ProxyRecords--;
6859 mDNSPlatformMemFree(ar);
6860 }
6861 }
6862
6863 mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
6864 const DNSMessage *const msg, const mDNSu8 *end,
6865 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
6866 const mDNSInterfaceID InterfaceID)
6867 {
6868 int i;
6869 AuthRecord opt;
6870 mDNSu8 *p = m->omsg.data;
6871 OwnerOptData owner;
6872 mDNSu32 updatelease = 0;
6873 const mDNSu8 *ptr;
6874
6875 LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6876 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6877 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
6878 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
6879 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
6880 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
6881 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
6882
6883 if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
6884
6885 if (mDNS_PacketLoggingEnabled)
6886 DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
6887
6888 ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
6889 if (ptr)
6890 {
6891 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
6892 if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
6893 {
6894 const rdataOPT *o;
6895 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
6896 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
6897 {
6898 if (o->opt == kDNSOpt_Lease) updatelease = o->u.updatelease;
6899 else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner = o->u.owner;
6900 }
6901 }
6902 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6903 }
6904
6905 InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags);
6906
6907 if (!updatelease || !owner.HMAC.l[0])
6908 {
6909 static int msgs = 0;
6910 if (msgs < 100)
6911 {
6912 msgs++;
6913 LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport),
6914 !updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : "");
6915 }
6916 m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr;
6917 }
6918 else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS)
6919 {
6920 static int msgs = 0;
6921 if (msgs < 100)
6922 {
6923 msgs++;
6924 LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport),
6925 m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS);
6926 }
6927 m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
6928 }
6929 else
6930 {
6931 LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
6932
6933 if (updatelease > 24 * 60 * 60)
6934 updatelease = 24 * 60 * 60;
6935
6936 if (updatelease > 0x40000000UL / mDNSPlatformOneSecond)
6937 updatelease = 0x40000000UL / mDNSPlatformOneSecond;
6938
6939 ptr = LocateAuthorities(msg, end);
6940 for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++)
6941 {
6942 ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
6943 if (ptr)
6944 {
6945 mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
6946 AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
6947 if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; }
6948 else
6949 {
6950 mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared;
6951 m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet;
6952 mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar);
6953 AssignDomainName(&ar->namestorage, m->rec.r.resrec.name);
6954 ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse);
6955 ar->resrec.rdata->MaxRDLength = RDLengthMem;
6956 mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem);
6957 ar->WakeUp = owner;
6958 if (m->rec.r.resrec.rrtype == kDNSType_PTR)
6959 {
6960 mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name);
6961 if (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name);
6962 else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name);
6963 debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar));
6964 if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID);
6965 }
6966 ar->TimeRcvd = m->timenow;
6967 ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond;
6968 if (m->NextScheduledSPS - ar->TimeExpire > 0)
6969 m->NextScheduledSPS = ar->TimeExpire;
6970 mDNS_Register_internal(m, ar);
6971 // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
6972 if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
6973 m->ProxyRecords++;
6974 LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar));
6975 }
6976 }
6977 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
6978 }
6979
6980 if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask)
6981 {
6982 LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport));
6983 ClearProxyRecords(m, &owner, m->DuplicateRecords);
6984 ClearProxyRecords(m, &owner, m->ResourceRecords);
6985 }
6986 else
6987 {
6988 mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6989 opt.resrec.rrclass = NormalMaxDNSMessageData;
6990 opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
6991 opt.resrec.rdestimate = sizeof(rdataOPT);
6992 opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease;
6993 opt.resrec.rdata->u.opt[0].u.updatelease = updatelease;
6994 p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
6995 }
6996 }
6997
6998 if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
6999 }
7000
7001 mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID)
7002 {
7003 if (InterfaceID)
7004 {
7005 AuthRecord *rr;
7006 mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour
7007 const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
7008 if (ptr)
7009 {
7010 ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
7011 if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
7012 {
7013 const rdataOPT *o;
7014 const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
7015 for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
7016 if (o->opt == kDNSOpt_Lease)
7017 {
7018 updatelease = o->u.updatelease;
7019 LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease);
7020 }
7021 }
7022 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
7023 }
7024
7025 for (rr = m->ResourceRecords; rr; rr=rr->next)
7026 if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
7027 if (mDNSSameOpaque16(rr->updateid, msg->h.id))
7028 {
7029 rr->updateid = zeroID;
7030 rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond);
7031 LogSPS("Sleep Proxy registered record %5d %s", updatelease, ARDisplayString(m,rr));
7032 }
7033
7034 }
7035 // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
7036 // may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
7037 if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
7038 }
7039
7040 mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
7041 const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID)
7042 {
7043 if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
7044 {
7045 LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
7046 #if ForceAlerts
7047 *(long*)0 = 0;
7048 #endif
7049 }
7050
7051 // Create empty resource record
7052 cr->resrec.RecordType = kDNSRecordTypePacketNegative;
7053 cr->resrec.InterfaceID = InterfaceID;
7054 cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry
7055 cr->resrec.rrtype = rrtype;
7056 cr->resrec.rrclass = rrclass;
7057 cr->resrec.rroriginalttl = ttl_seconds;
7058 cr->resrec.rdlength = 0;
7059 cr->resrec.rdestimate = 0;
7060 cr->resrec.namehash = namehash;
7061 cr->resrec.rdatahash = 0;
7062 cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
7063 cr->resrec.rdata->MaxRDLength = 0;
7064
7065 cr->NextInKAList = mDNSNULL;
7066 cr->TimeRcvd = m->timenow;
7067 cr->DelayDelivery = 0;
7068 cr->NextRequiredQuery = m->timenow;
7069 cr->LastUsed = m->timenow;
7070 cr->CRActiveQuestion = mDNSNULL;
7071 cr->UnansweredQueries = 0;
7072 cr->LastUnansweredTime = 0;
7073 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
7074 cr->MPUnansweredQ = 0;
7075 cr->MPLastUnansweredQT = 0;
7076 cr->MPUnansweredKA = 0;
7077 cr->MPExpectingKA = mDNSfalse;
7078 #endif
7079 cr->NextInCFList = mDNSNULL;
7080 }
7081
7082 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
7083 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
7084 const mDNSInterfaceID InterfaceID)
7085 {
7086 mDNSInterfaceID ifid = InterfaceID;
7087 DNSMessage *msg = (DNSMessage *)pkt;
7088 const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery;
7089 const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
7090 const mDNSu8 UpdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_Update;
7091 const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
7092 mDNSu8 QR_OP;
7093 mDNSu8 *ptr = mDNSNULL;
7094 mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
7095 if (TLS) dstaddr = mDNSNULL;
7096
7097 #ifndef UNICAST_DISABLED
7098 if (mDNSSameAddress(srcaddr, &m->Router))
7099 {
7100 #ifdef _LEGACY_NAT_TRAVERSAL_
7101 if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)))
7102 {
7103 mDNS_Lock(m);
7104 LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
7105 mDNS_Unlock(m);
7106 return;
7107 }
7108 #endif
7109 if (mDNSSameIPPort(srcport, NATPMPPort))
7110 {
7111 mDNS_Lock(m);
7112 uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
7113 mDNS_Unlock(m);
7114 return;
7115 }
7116 }
7117 #ifdef _LEGACY_NAT_TRAVERSAL_
7118 else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; }
7119 #endif
7120
7121 #endif
7122 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
7123 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
7124 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
7125 ptr = (mDNSu8 *)&msg->h.numQuestions;
7126 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
7127 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
7128 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
7129 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
7130
7131 if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
7132
7133 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
7134 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
7135 if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
7136
7137 mDNS_Lock(m);
7138 m->PktNum++;
7139 #ifndef UNICAST_DISABLED
7140 if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR)))
7141 if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
7142 {
7143 ifid = mDNSInterface_Any;
7144 if (mDNS_PacketLoggingEnabled)
7145 DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
7146 uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
7147 // Note: mDNSCore also needs to get access to received unicast responses
7148 }
7149 #endif
7150 if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
7151 else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
7152 else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
7153 else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, InterfaceID);
7154 else
7155 {
7156 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
7157 msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID);
7158 if (mDNS_LoggingEnabled)
7159 {
7160 int i = 0;
7161 while (i<end-(mDNSu8 *)pkt)
7162 {
7163 char buffer[128];
7164 char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
7165 do if (i<end-(mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
7166 LogInfo("%s", buffer);
7167 }
7168 }
7169 }
7170 // Packet reception often causes a change to the task list:
7171 // 1. Inbound queries can cause us to need to send responses
7172 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
7173 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
7174 // 4. Response packets that answer questions may cause our client to issue new questions
7175 mDNS_Unlock(m);
7176 }
7177
7178 // ***************************************************************************
7179 #if COMPILER_LIKES_PRAGMA_MARK
7180 #pragma mark -
7181 #pragma mark - Searcher Functions
7182 #endif
7183
7184 // Targets are considered the same if both queries are untargeted, or
7185 // if both are targeted to the same address+port
7186 // (If Target address is zero, TargetPort is undefined)
7187 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
7188 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
7189
7190 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
7191 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
7192 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
7193 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
7194 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
7195
7196 // If IsLLQ(Q) is true, it means the question is both:
7197 // (a) long-lived and
7198 // (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
7199 // for multicast questions, we don't want to treat LongLived as anything special
7200 #define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
7201
7202 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
7203 {
7204 DNSQuestion *q;
7205 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
7206 // This prevents circular references, where two questions are each marked as a duplicate of the other.
7207 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
7208 // further in the list.
7209 for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question
7210 if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID,
7211 SameQTarget(q, question) && // and same unicast/multicast target settings
7212 q->qtype == question->qtype && // type,
7213 q->qclass == question->qclass && // class,
7214 IsLLQ(q) == IsLLQ(question) && // and long-lived status matches
7215 (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one
7216 q->qnamehash == question->qnamehash &&
7217 SameDomainName(&q->qname, &question->qname)) // and name
7218 return(q);
7219 return(mDNSNULL);
7220 }
7221
7222 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
7223 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
7224 {
7225 DNSQuestion *q;
7226 for (q = m->Questions; q; q=q->next) // Scan our list of questions
7227 if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate
7228 if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL)
7229 {
7230 // If q used to be a duplicate, but now is not,
7231 // then inherit the state from the question that's going away
7232 q->LastQTime = question->LastQTime;
7233 q->ThisQInterval = question->ThisQInterval;
7234 q->ExpectUnicastResp = question->ExpectUnicastResp;
7235 q->LastAnswerPktNum = question->LastAnswerPktNum;
7236 q->RecentAnswerPkts = question->RecentAnswerPkts;
7237 q->RequestUnicast = question->RequestUnicast;
7238 q->LastQTxTime = question->LastQTxTime;
7239 q->CNAMEReferrals = question->CNAMEReferrals;
7240 q->nta = question->nta;
7241 q->servAddr = question->servAddr;
7242 q->servPort = question->servPort;
7243 q->qDNSServer = question->qDNSServer;
7244 q->unansweredQueries = question->unansweredQueries;
7245
7246 q->TargetQID = question->TargetQID;
7247 q->LocalSocket = question->LocalSocket;
7248
7249 q->state = question->state;
7250 // q->tcp = question->tcp;
7251 q->ReqLease = question->ReqLease;
7252 q->expire = question->expire;
7253 q->ntries = question->ntries;
7254 q->id = question->id;
7255
7256 question->LocalSocket = mDNSNULL;
7257 question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question
7258 // question->tcp = mDNSNULL;
7259
7260 if (q->LocalSocket)
7261 debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7262
7263 if (q->nta)
7264 {
7265 LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7266 q->nta->ZoneDataContext = q;
7267 }
7268
7269 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
7270 if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
7271
7272 if (question->state == LLQ_Established)
7273 {
7274 LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7275 question->state = 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
7276 }
7277
7278 SetNextQueryTime(m,q);
7279 }
7280 }
7281
7282 // Look up a DNS Server, matching by name in split-dns configurations.
7283 mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
7284 {
7285 DNSServer *curmatch = mDNSNULL, *p;
7286 int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
7287
7288 for (p = m->DNSServers; p; p = p->next)
7289 {
7290 int scount = CountLabels(&p->domain);
7291 if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
7292 if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
7293 { curmatch = p; curmatchlen = scount; }
7294 }
7295 return(curmatch);
7296 }
7297
7298 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
7299 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
7300
7301 // Called in normal client context (lock not held)
7302 mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
7303 {
7304 DNSQuestion *q;
7305 (void)n; // Unused
7306 mDNS_Lock(m);
7307 LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
7308 for (q = m->Questions; q; q=q->next)
7309 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
7310 startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead
7311 #if APPLE_OSX_mDNSResponder
7312 UpdateAutoTunnelDomainStatuses(m);
7313 #endif
7314 mDNS_Unlock(m);
7315 }
7316
7317 mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
7318 {
7319 if (question->Target.type && !ValidQuestionTarget(question))
7320 {
7321 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
7322 question->Target.type, mDNSVal16(question->TargetPort));
7323 question->Target.type = mDNSAddrType_None;
7324 }
7325
7326 if (!question->Target.type) question->TargetPort = zeroIPPort; // If question->Target specified clear TargetPort
7327
7328 question->TargetQID =
7329 #ifndef UNICAST_DISABLED
7330 (question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) ||
7331 (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)))
7332 ? mDNS_NewMessageID(m) :
7333 #endif // UNICAST_DISABLED
7334 zeroID;
7335
7336 debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7337
7338 if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated
7339 return(mStatus_NoCache);
7340 else
7341 {
7342 int i;
7343 DNSQuestion **q;
7344
7345 if (!ValidateDomainName(&question->qname))
7346 {
7347 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7348 return(mStatus_Invalid);
7349 }
7350
7351 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
7352 q = &m->Questions;
7353 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
7354 while (*q && *q != question) q=&(*q)->next;
7355
7356 if (*q)
7357 {
7358 LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
7359 question->qname.c, DNSTypeName(question->qtype), question);
7360 return(mStatus_AlreadyRegistered);
7361 }
7362
7363 *q = question;
7364
7365 // If this question is referencing a specific interface, verify it exists
7366 if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast)
7367 {
7368 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
7369 if (!intf)
7370 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
7371 question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
7372 }
7373
7374 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
7375 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
7376 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
7377 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
7378 // that to go out immediately.
7379 question->next = mDNSNULL;
7380 question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion()
7381 question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
7382 question->LastQTime = m->timenow;
7383 question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
7384 question->ExpectUnicastResp = 0;
7385 question->LastAnswerPktNum = m->PktNum;
7386 question->RecentAnswerPkts = 0;
7387 question->CurrentAnswers = 0;
7388 question->LargeAnswers = 0;
7389 question->UniqueAnswers = 0;
7390 question->FlappingInterface1 = mDNSNULL;
7391 question->FlappingInterface2 = mDNSNULL;
7392 question->AuthInfo = GetAuthInfoForQuestion(m, question); // Must do this before calling FindDuplicateQuestion()
7393 question->DuplicateOf = FindDuplicateQuestion(m, question);
7394 question->NextInDQList = mDNSNULL;
7395 question->SendQNow = mDNSNULL;
7396 question->SendOnAll = mDNSfalse;
7397 question->RequestUnicast = 0;
7398 question->LastQTxTime = m->timenow;
7399 question->CNAMEReferrals = 0;
7400
7401 // We'll create our question->LocalSocket on demand, if needed.
7402 // We won't need one for duplicate questions, or from questions answered immediately out of the cache.
7403 // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
7404 // NAT mapping for receiving inbound add/remove events.
7405 question->LocalSocket = mDNSNULL;
7406 question->qDNSServer = mDNSNULL;
7407 question->unansweredQueries = 0;
7408 question->nta = mDNSNULL;
7409 question->servAddr = zeroAddr;
7410 question->servPort = zeroIPPort;
7411 question->tcp = mDNSNULL;
7412 question->NoAnswer = NoAnswer_Normal;
7413
7414 question->state = LLQ_InitialRequest;
7415 question->ReqLease = 0;
7416 question->expire = 0;
7417 question->ntries = 0;
7418 question->id = zeroOpaque64;
7419
7420 if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
7421
7422 for (i=0; i<DupSuppressInfoSize; i++)
7423 question->DupSuppress[i].InterfaceID = mDNSNULL;
7424
7425 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
7426 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
7427 question->LastQTime + question->ThisQInterval - m->timenow,
7428 question->DelayAnswering ? question->DelayAnswering - m->timenow : 0,
7429 question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf);
7430
7431 if (question->InterfaceID == mDNSInterface_LocalOnly)
7432 {
7433 if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
7434 }
7435 else
7436 {
7437 if (!m->NewQuestions) m->NewQuestions = question;
7438
7439 // If the question's id is non-zero, then it's Wide Area
7440 // MUST NOT do this Wide Area setup until near the end of
7441 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
7442 // NS, etc.) and if we haven't finished setting up our own question and setting
7443 // m->NewQuestions if necessary then we could end up recursively re-entering
7444 // this routine with the question list data structures in an inconsistent state.
7445 if (!mDNSOpaque16IsZero(question->TargetQID))
7446 {
7447 question->qDNSServer = GetServerForName(m, &question->qname);
7448 ActivateUnicastQuery(m, question, mDNSfalse);
7449
7450 // If long-lived query, and we don't have our NAT mapping active, start it now
7451 if (question->LongLived && !m->LLQNAT.clientContext)
7452 {
7453 m->LLQNAT.Protocol = NATOp_MapUDP;
7454 m->LLQNAT.IntPort = m->UnicastPort4;
7455 m->LLQNAT.RequestedPort = m->UnicastPort4;
7456 m->LLQNAT.clientCallback = LLQNATCallback;
7457 m->LLQNAT.clientContext = (void*)1; // Means LLQ NAT Traversal is active
7458 mDNS_StartNATOperation_internal(m, &m->LLQNAT);
7459 }
7460
7461 #if APPLE_OSX_mDNSResponder
7462 if (question->LongLived)
7463 UpdateAutoTunnelDomainStatuses(m);
7464 #endif
7465
7466 }
7467 SetNextQueryTime(m,question);
7468 }
7469
7470 return(mStatus_NoError);
7471 }
7472 }
7473
7474 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
7475 mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
7476 {
7477 debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
7478 mDNS_StopQuery_internal(m, &nta->question);
7479 mDNSPlatformMemFree(nta);
7480 }
7481
7482 mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
7483 {
7484 const mDNSu32 slot = HashSlot(&question->qname);
7485 CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
7486 CacheRecord *rr;
7487 DNSQuestion **qp = &m->Questions;
7488
7489 //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7490
7491 if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
7492 while (*qp && *qp != question) qp=&(*qp)->next;
7493 if (*qp) *qp = (*qp)->next;
7494 else
7495 {
7496 #if !ForceAlerts
7497 if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active
7498 #endif
7499 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
7500 question->qname.c, DNSTypeName(question->qtype));
7501 #if ForceAlerts
7502 *(long*)0 = 0;
7503 #endif
7504 return(mStatus_BadReferenceErr);
7505 }
7506
7507 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
7508 UpdateQuestionDuplicates(m, question);
7509 // But don't trash ThisQInterval until afterwards.
7510 question->ThisQInterval = -1;
7511
7512 // If there are any cache records referencing this as their active question, then see if there is any
7513 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
7514 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
7515 {
7516 if (rr->CRActiveQuestion == question)
7517 {
7518 DNSQuestion *q;
7519 for (q = m->Questions; q; q=q->next) // Scan our list of questions
7520 if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
7521 break;
7522 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
7523 rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
7524 if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
7525 }
7526 }
7527
7528 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
7529 // bump its pointer forward one question.
7530 if (m->CurrentQuestion == question)
7531 {
7532 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
7533 question->qname.c, DNSTypeName(question->qtype));
7534 m->CurrentQuestion = question->next;
7535 }
7536
7537 if (m->NewQuestions == question)
7538 {
7539 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
7540 question->qname.c, DNSTypeName(question->qtype));
7541 m->NewQuestions = question->next;
7542 }
7543
7544 if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
7545
7546 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
7547 question->next = mDNSNULL;
7548
7549 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
7550
7551 // And finally, cancel any associated GetZoneData operation that's still running.
7552 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
7553 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
7554 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
7555 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
7556 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
7557 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
7558 if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
7559 if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
7560 {
7561 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
7562 DNSQuestion *q;
7563 for (q = m->Questions; q; q=q->next)
7564 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) break;
7565 if (!q)
7566 {
7567 if (!m->LLQNAT.clientContext) // Should never happen, but just in case...
7568 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
7569 else
7570 {
7571 LogInfo("Stopping LLQNAT");
7572 mDNS_StopNATOperation_internal(m, &m->LLQNAT);
7573 m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running
7574 }
7575 }
7576
7577 // If necessary, tell server it can delete this LLQ state
7578 if (question->state == LLQ_Established)
7579 {
7580 question->ReqLease = 0;
7581 sendLLQRefresh(m, question);
7582 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
7583 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
7584 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
7585 // we let that run out its natural course and complete asynchronously.
7586 if (question->tcp)
7587 {
7588 question->tcp->question = mDNSNULL;
7589 question->tcp = mDNSNULL;
7590 }
7591 }
7592 #if APPLE_OSX_mDNSResponder
7593 UpdateAutoTunnelDomainStatuses(m);
7594 #endif
7595 }
7596
7597 return(mStatus_NoError);
7598 }
7599
7600 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
7601 {
7602 mStatus status;
7603 mDNS_Lock(m);
7604 status = mDNS_StartQuery_internal(m, question);
7605 mDNS_Unlock(m);
7606 return(status);
7607 }
7608
7609 mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
7610 {
7611 mStatus status;
7612 mDNS_Lock(m);
7613 status = mDNS_StopQuery_internal(m, question);
7614 mDNS_Unlock(m);
7615 return(status);
7616 }
7617
7618 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
7619 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
7620 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
7621 // specifically to catch and report if the client callback does try to make API calls
7622 mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question)
7623 {
7624 mStatus status;
7625 DNSQuestion *qq;
7626 mDNS_Lock(m);
7627
7628 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
7629 for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break;
7630
7631 status = mDNS_StopQuery_internal(m, question);
7632 if (status == mStatus_NoError && !qq)
7633 {
7634 const CacheRecord *rr;
7635 const mDNSu32 slot = HashSlot(&question->qname);
7636 CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
7637 LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7638 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
7639 if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
7640 {
7641 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
7642 if (question->QuestionCallback)
7643 question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
7644 }
7645 }
7646 mDNS_Unlock(m);
7647 return(status);
7648 }
7649
7650 mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr)
7651 {
7652 mStatus status;
7653 mDNS_Lock(m);
7654 status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7655 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
7656 mDNS_Unlock(m);
7657 return(status);
7658 }
7659
7660 mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
7661 {
7662 mStatus status = mStatus_BadReferenceErr;
7663 CacheRecord *cr;
7664 mDNS_Lock(m);
7665 cr = FindIdenticalRecordInCache(m, rr);
7666 debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr));
7667 if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7668 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
7669 mDNS_Unlock(m);
7670 return(status);
7671 }
7672
7673 mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
7674 const domainname *const srv, const domainname *const domain,
7675 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
7676 {
7677 question->InterfaceID = InterfaceID;
7678 question->Target = zeroAddr;
7679 question->qtype = kDNSType_PTR;
7680 question->qclass = kDNSClass_IN;
7681 question->LongLived = mDNSfalse;
7682 question->ExpectUnique = mDNSfalse;
7683 question->ForceMCast = ForceMCast;
7684 question->ReturnIntermed = mDNSfalse;
7685 question->QuestionCallback = Callback;
7686 question->QuestionContext = Context;
7687 if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
7688
7689 #ifndef UNICAST_DISABLED
7690 if (Question_uDNS(question))
7691 {
7692 question->LongLived = mDNStrue;
7693 question->ThisQInterval = InitialQuestionInterval;
7694 question->LastQTime = m->timenow - question->ThisQInterval;
7695 }
7696 #endif // UNICAST_DISABLED
7697 return(mDNS_StartQuery_internal(m, question));
7698 }
7699
7700 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
7701 const domainname *const srv, const domainname *const domain,
7702 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
7703 {
7704 mStatus status;
7705 mDNS_Lock(m);
7706 status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context);
7707 mDNS_Unlock(m);
7708 return(status);
7709 }
7710
7711 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
7712 {
7713 NetworkInterfaceInfo *intf;
7714 for (intf = m->HostInterfaces; intf; intf = intf->next)
7715 if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
7716 return(mDNSfalse);
7717 }
7718
7719 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7720 {
7721 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7722 mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
7723 if (!AddRecord) return;
7724 if (answer->rrtype != kDNSType_SRV) return;
7725
7726 query->info->port = answer->rdata->u.srv.port;
7727
7728 // If this is our first answer, then set the GotSRV flag and start the address query
7729 if (!query->GotSRV)
7730 {
7731 query->GotSRV = mDNStrue;
7732 query->qAv4.InterfaceID = answer->InterfaceID;
7733 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
7734 query->qAv6.InterfaceID = answer->InterfaceID;
7735 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
7736 mDNS_StartQuery(m, &query->qAv4);
7737 // Only do the AAAA query if this machine actually has IPv6 active
7738 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
7739 }
7740 // If this is not our first answer, only re-issue the address query if the target host name has changed
7741 else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
7742 !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
7743 {
7744 mDNS_StopQuery(m, &query->qAv4);
7745 if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
7746 if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
7747 {
7748 // If we get here, it means:
7749 // 1. This is not our first SRV answer
7750 // 2. The interface ID is different, but the target host and port are the same
7751 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
7752 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
7753 query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface
7754 query->qAv6.InterfaceID = query->qSRV.InterfaceID;
7755 }
7756 else
7757 {
7758 query->qAv4.InterfaceID = answer->InterfaceID;
7759 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
7760 query->qAv6.InterfaceID = answer->InterfaceID;
7761 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
7762 }
7763 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
7764 mDNS_StartQuery(m, &query->qAv4);
7765 // Only do the AAAA query if this machine actually has IPv6 active
7766 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
7767 }
7768 else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
7769 {
7770 if (++query->Answers >= 100)
7771 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
7772 query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
7773 mDNSVal16(answer->rdata->u.srv.port));
7774 query->ServiceInfoQueryCallback(m, query);
7775 }
7776 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7777 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7778 }
7779
7780 mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7781 {
7782 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7783 if (!AddRecord) return;
7784 if (answer->rrtype != kDNSType_TXT) return;
7785 if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
7786
7787 query->GotTXT = mDNStrue;
7788 query->info->TXTlen = answer->rdlength;
7789 query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero
7790 mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
7791
7792 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
7793
7794 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7795 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7796 if (query->ServiceInfoQueryCallback && query->GotADD)
7797 {
7798 if (++query->Answers >= 100)
7799 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
7800 query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
7801 query->ServiceInfoQueryCallback(m, query);
7802 }
7803 }
7804
7805 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7806 {
7807 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7808 //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
7809 if (!AddRecord) return;
7810
7811 if (answer->rrtype == kDNSType_A)
7812 {
7813 query->info->ip.type = mDNSAddrType_IPv4;
7814 query->info->ip.ip.v4 = answer->rdata->u.ipv4;
7815 }
7816 else if (answer->rrtype == kDNSType_AAAA)
7817 {
7818 query->info->ip.type = mDNSAddrType_IPv6;
7819 query->info->ip.ip.v6 = answer->rdata->u.ipv6;
7820 }
7821 else
7822 {
7823 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
7824 return;
7825 }
7826
7827 query->GotADD = mDNStrue;
7828 query->info->InterfaceID = answer->InterfaceID;
7829
7830 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
7831
7832 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7833 // callback function is allowed to do anything, including deleting this query and freeing its memory.
7834 if (query->ServiceInfoQueryCallback && query->GotTXT)
7835 {
7836 if (++query->Answers >= 100)
7837 debugf(answer->rrtype == kDNSType_A ?
7838 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
7839 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
7840 query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
7841 query->ServiceInfoQueryCallback(m, query);
7842 }
7843 }
7844
7845 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
7846 // If the query is not interface-specific, then InterfaceID may be zero
7847 // Each time the Callback is invoked, the remainder of the fields will have been filled in
7848 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
7849 mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
7850 ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
7851 {
7852 mStatus status;
7853 mDNS_Lock(m);
7854
7855 query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7856 query->qSRV.InterfaceID = info->InterfaceID;
7857 query->qSRV.Target = zeroAddr;
7858 AssignDomainName(&query->qSRV.qname, &info->name);
7859 query->qSRV.qtype = kDNSType_SRV;
7860 query->qSRV.qclass = kDNSClass_IN;
7861 query->qSRV.LongLived = mDNSfalse;
7862 query->qSRV.ExpectUnique = mDNStrue;
7863 query->qSRV.ForceMCast = mDNSfalse;
7864 query->qSRV.ReturnIntermed = mDNSfalse;
7865 query->qSRV.QuestionCallback = FoundServiceInfoSRV;
7866 query->qSRV.QuestionContext = query;
7867
7868 query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7869 query->qTXT.InterfaceID = info->InterfaceID;
7870 query->qTXT.Target = zeroAddr;
7871 AssignDomainName(&query->qTXT.qname, &info->name);
7872 query->qTXT.qtype = kDNSType_TXT;
7873 query->qTXT.qclass = kDNSClass_IN;
7874 query->qTXT.LongLived = mDNSfalse;
7875 query->qTXT.ExpectUnique = mDNStrue;
7876 query->qTXT.ForceMCast = mDNSfalse;
7877 query->qTXT.ReturnIntermed = mDNSfalse;
7878 query->qTXT.QuestionCallback = FoundServiceInfoTXT;
7879 query->qTXT.QuestionContext = query;
7880
7881 query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7882 query->qAv4.InterfaceID = info->InterfaceID;
7883 query->qAv4.Target = zeroAddr;
7884 query->qAv4.qname.c[0] = 0;
7885 query->qAv4.qtype = kDNSType_A;
7886 query->qAv4.qclass = kDNSClass_IN;
7887 query->qAv4.LongLived = mDNSfalse;
7888 query->qAv4.ExpectUnique = mDNStrue;
7889 query->qAv4.ForceMCast = mDNSfalse;
7890 query->qAv4.ReturnIntermed = mDNSfalse;
7891 query->qAv4.QuestionCallback = FoundServiceInfo;
7892 query->qAv4.QuestionContext = query;
7893
7894 query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
7895 query->qAv6.InterfaceID = info->InterfaceID;
7896 query->qAv6.Target = zeroAddr;
7897 query->qAv6.qname.c[0] = 0;
7898 query->qAv6.qtype = kDNSType_AAAA;
7899 query->qAv6.qclass = kDNSClass_IN;
7900 query->qAv6.LongLived = mDNSfalse;
7901 query->qAv6.ExpectUnique = mDNStrue;
7902 query->qAv6.ForceMCast = mDNSfalse;
7903 query->qAv6.ReturnIntermed = mDNSfalse;
7904 query->qAv6.QuestionCallback = FoundServiceInfo;
7905 query->qAv6.QuestionContext = query;
7906
7907 query->GotSRV = mDNSfalse;
7908 query->GotTXT = mDNSfalse;
7909 query->GotADD = mDNSfalse;
7910 query->Answers = 0;
7911
7912 query->info = info;
7913 query->ServiceInfoQueryCallback = Callback;
7914 query->ServiceInfoQueryContext = Context;
7915
7916 // info->name = Must already be set up by client
7917 // info->interface = Must already be set up by client
7918 info->ip = zeroAddr;
7919 info->port = zeroIPPort;
7920 info->TXTlen = 0;
7921
7922 // We use mDNS_StartQuery_internal here because we're already holding the lock
7923 status = mDNS_StartQuery_internal(m, &query->qSRV);
7924 if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
7925 if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
7926
7927 mDNS_Unlock(m);
7928 return(status);
7929 }
7930
7931 mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
7932 {
7933 mDNS_Lock(m);
7934 // We use mDNS_StopQuery_internal here because we're already holding the lock
7935 if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
7936 if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
7937 if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
7938 if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
7939 mDNS_Unlock(m);
7940 }
7941
7942 mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
7943 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
7944 {
7945 question->InterfaceID = InterfaceID;
7946 question->Target = zeroAddr;
7947 question->qtype = kDNSType_PTR;
7948 question->qclass = kDNSClass_IN;
7949 question->LongLived = mDNSfalse;
7950 question->ExpectUnique = mDNSfalse;
7951 question->ForceMCast = mDNSfalse;
7952 question->ReturnIntermed = mDNSfalse;
7953 question->QuestionCallback = Callback;
7954 question->QuestionContext = Context;
7955 if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
7956 if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
7957 if (!dom) dom = &localdomain;
7958 if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
7959 return(mDNS_StartQuery(m, question));
7960 }
7961
7962 // ***************************************************************************
7963 #if COMPILER_LIKES_PRAGMA_MARK
7964 #pragma mark -
7965 #pragma mark - Responder Functions
7966 #endif
7967
7968 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
7969 {
7970 mStatus status;
7971 mDNS_Lock(m);
7972 status = mDNS_Register_internal(m, rr);
7973 mDNS_Unlock(m);
7974 return(status);
7975 }
7976
7977 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
7978 const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
7979 {
7980 #ifndef UNICAST_DISABLED
7981 mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
7982 #else
7983 mDNSBool unicast = mDNSfalse;
7984 #endif
7985
7986 if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
7987 {
7988 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
7989 return(mStatus_Invalid);
7990 }
7991
7992 mDNS_Lock(m);
7993
7994 // If TTL is unspecified, leave TTL unchanged
7995 if (newttl == 0) newttl = rr->resrec.rroriginalttl;
7996
7997 // If we already have an update queued up which has not gone through yet,
7998 // give the client a chance to free that memory
7999 if (!unicast && rr->NewRData)
8000 {
8001 RData *n = rr->NewRData;
8002 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
8003 if (rr->UpdateCallback)
8004 rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary
8005 }
8006
8007 rr->NewRData = newrdata;
8008 rr->newrdlength = newrdlength;
8009 rr->UpdateCallback = Callback;
8010
8011 if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
8012
8013 if (rr->resrec.rroriginalttl == newttl &&
8014 rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
8015 CompleteRDataUpdate(m, rr);
8016 else
8017 {
8018 domainlabel name;
8019 domainname type, domain;
8020 DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
8021 rr->AnnounceCount = InitialAnnounceCount;
8022 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
8023 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
8024 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
8025 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
8026 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
8027 if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
8028 InitializeLastAPTime(m, rr);
8029 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
8030 if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
8031 if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
8032 if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
8033 if (rr->UpdateCredits <= 5)
8034 {
8035 mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
8036 if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
8037 rr->ThisAPInterval *= 4;
8038 rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
8039 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
8040 rr->resrec.name->c, delay, delay > 1 ? "s" : "");
8041 }
8042 rr->resrec.rroriginalttl = newttl;
8043 }
8044
8045 mDNS_Unlock(m);
8046 return(mStatus_NoError);
8047 }
8048
8049 // Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
8050 // the record list and/or question list.
8051 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8052 mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
8053 {
8054 mStatus status;
8055 mDNS_Lock(m);
8056 status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
8057 mDNS_Unlock(m);
8058 return(status);
8059 }
8060
8061 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
8062 mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
8063
8064 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
8065 {
8066 NetworkInterfaceInfo *intf;
8067 for (intf = m->HostInterfaces; intf; intf = intf->next)
8068 if (intf->Advertise) break;
8069 return(intf);
8070 }
8071
8072 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
8073 {
8074 char buffer[MAX_REVERSE_MAPPING_NAME];
8075 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
8076 if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
8077
8078 // Send dynamic update for non-linklocal IPv4 Addresses
8079 mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, mDNS_HostNameCallback, set);
8080 mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
8081 mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
8082
8083 #if ANSWER_REMOTE_HOSTNAME_QUERIES
8084 set->RR_A .AllowRemoteQuery = mDNStrue;
8085 set->RR_PTR .AllowRemoteQuery = mDNStrue;
8086 set->RR_HINFO.AllowRemoteQuery = mDNStrue;
8087 #endif
8088 // 1. Set up Address record to map from host name ("foo.local.") to IP address
8089 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
8090 AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
8091 if (set->ip.type == mDNSAddrType_IPv4)
8092 {
8093 set->RR_A.resrec.rrtype = kDNSType_A;
8094 set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
8095 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8096 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
8097 set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
8098 }
8099 else if (set->ip.type == mDNSAddrType_IPv6)
8100 {
8101 int i;
8102 set->RR_A.resrec.rrtype = kDNSType_AAAA;
8103 set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
8104 for (i = 0; i < 16; i++)
8105 {
8106 static const char hexValues[] = "0123456789ABCDEF";
8107 buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
8108 buffer[i * 4 + 1] = '.';
8109 buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
8110 buffer[i * 4 + 3] = '.';
8111 }
8112 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
8113 }
8114
8115 MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
8116 set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
8117 set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
8118
8119 set->RR_A.RRSet = &primary->RR_A; // May refer to self
8120
8121 mDNS_Register_internal(m, &set->RR_A);
8122 mDNS_Register_internal(m, &set->RR_PTR);
8123
8124 if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
8125 {
8126 mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
8127 AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
8128 set->RR_HINFO.DependentOn = &set->RR_A;
8129 mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
8130 p += 1 + (int)p[0];
8131 mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
8132 mDNS_Register_internal(m, &set->RR_HINFO);
8133 }
8134 else
8135 {
8136 debugf("Not creating HINFO record: platform support layer provided no information");
8137 set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
8138 }
8139 }
8140
8141 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
8142 {
8143 NetworkInterfaceInfo *intf;
8144
8145 // If we still have address records referring to this one, update them
8146 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
8147 AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
8148 for (intf = m->HostInterfaces; intf; intf = intf->next)
8149 if (intf->RR_A.RRSet == &set->RR_A)
8150 intf->RR_A.RRSet = A;
8151
8152 // Unregister these records.
8153 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
8154 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
8155 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
8156 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
8157 if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
8158 if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
8159 if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
8160 }
8161
8162 mDNSexport void mDNS_SetFQDN(mDNS *const m)
8163 {
8164 domainname newmname;
8165 NetworkInterfaceInfo *intf;
8166 AuthRecord *rr;
8167 newmname.c[0] = 0;
8168
8169 if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8170 if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8171
8172 mDNS_Lock(m);
8173
8174 if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged");
8175 else
8176 {
8177 AssignDomainName(&m->MulticastHostname, &newmname);
8178
8179 // 1. Stop advertising our address records on all interfaces
8180 for (intf = m->HostInterfaces; intf; intf = intf->next)
8181 if (intf->Advertise) DeadvertiseInterface(m, intf);
8182
8183 // 2. Start advertising our address records using the new name
8184 for (intf = m->HostInterfaces; intf; intf = intf->next)
8185 if (intf->Advertise) AdvertiseInterface(m, intf);
8186 }
8187
8188 // 3. Make sure that any AutoTarget SRV records (and the like) get updated
8189 for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
8190 for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
8191
8192 mDNS_Unlock(m);
8193 }
8194
8195 mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8196 {
8197 (void)rr; // Unused parameter
8198
8199 #if MDNS_DEBUGMSGS
8200 {
8201 char *msg = "Unknown result";
8202 if (result == mStatus_NoError) msg = "Name registered";
8203 else if (result == mStatus_NameConflict) msg = "Name conflict";
8204 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
8205 }
8206 #endif
8207
8208 if (result == mStatus_NoError)
8209 {
8210 // Notify the client that the host name is successfully registered
8211 if (m->MainCallback)
8212 m->MainCallback(m, mStatus_NoError);
8213 }
8214 else if (result == mStatus_NameConflict)
8215 {
8216 domainlabel oldlabel = m->hostlabel;
8217
8218 // 1. First give the client callback a chance to pick a new name
8219 if (m->MainCallback)
8220 m->MainCallback(m, mStatus_NameConflict);
8221
8222 // 2. If the client callback didn't do it, add (or increment) an index ourselves
8223 // This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
8224 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
8225 if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
8226 IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
8227
8228 // 3. Generate the FQDNs from the hostlabel,
8229 // and make sure all SRV records, etc., are updated to reference our new hostname
8230 mDNS_SetFQDN(m);
8231 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
8232 }
8233 else if (result == mStatus_MemFree)
8234 {
8235 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
8236 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
8237 debugf("mDNS_HostNameCallback: MemFree (ignored)");
8238 }
8239 else
8240 LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c);
8241 }
8242
8243 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
8244 {
8245 NetworkInterfaceInfo *intf;
8246 active->IPv4Available = mDNSfalse;
8247 active->IPv6Available = mDNSfalse;
8248 for (intf = m->HostInterfaces; intf; intf = intf->next)
8249 if (intf->InterfaceID == active->InterfaceID)
8250 {
8251 if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
8252 if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
8253 }
8254 }
8255
8256 mDNSlocal void RestartRecordGetZoneData(mDNS * const m)
8257 {
8258 AuthRecord *rr;
8259 ServiceRecordSet *s;
8260
8261 for (rr = m->ResourceRecords; rr; rr=rr->next)
8262 if (AuthRecord_uDNS(rr))
8263 {
8264 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c);
8265 if (rr->nta) CancelGetZoneData(m, rr->nta);
8266 rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
8267 }
8268
8269 for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
8270 {
8271 debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
8272 if (s->srs_nta) CancelGetZoneData(m, s->srs_nta);
8273 s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
8274 }
8275 }
8276
8277 mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set)
8278 {
8279 int i;
8280 set->NetWakeBrowse.ThisQInterval = -1;
8281 for (i=0; i<3; i++)
8282 {
8283 set->NetWakeResolve[i].ThisQInterval = -1;
8284 set->SPSAddr[i].type = mDNSAddrType_None;
8285 }
8286 set->NextSPSAttempt = -1;
8287 set->NextSPSAttemptTime = m->timenow;
8288 }
8289
8290 mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
8291 {
8292 NetworkInterfaceInfo *p = m->HostInterfaces;
8293 while (p && p != set) p=p->next;
8294 if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
8295
8296 if (set->InterfaceActive)
8297 {
8298 LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
8299 mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set);
8300 }
8301 }
8302
8303 mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
8304 {
8305 NetworkInterfaceInfo *p = m->HostInterfaces;
8306 while (p && p != set) p=p->next;
8307 if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
8308
8309 if (set->NetWakeBrowse.ThisQInterval >= 0)
8310 {
8311 int i;
8312 LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip);
8313
8314 // Stop our browse and resolve operations
8315 mDNS_StopQuery_internal(m, &set->NetWakeBrowse);
8316 for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]);
8317
8318 // Make special call to the browse callback to let it know it can to remove all records for this interface
8319 if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
8320
8321 // Reset our variables back to initial state, so we're ready for when NetWake is turned back on
8322 // (includes resetting NetWakeBrowse.ThisQInterval back to -1)
8323 InitializeNetWakeState(m, set);
8324 }
8325 }
8326
8327 mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
8328 {
8329 AuthRecord *rr;
8330 mDNSBool FirstOfType = mDNStrue;
8331 NetworkInterfaceInfo **p = &m->HostInterfaces;
8332
8333 if (!set->InterfaceID)
8334 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
8335
8336 if (!mDNSAddressIsValidNonZero(&set->mask))
8337 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
8338
8339 mDNS_Lock(m);
8340
8341 // Assume this interface will be active now, unless we find a duplicate already in the list
8342 set->InterfaceActive = mDNStrue;
8343 set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
8344 set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
8345
8346 InitializeNetWakeState(m, set);
8347
8348 // Scan list to see if this InterfaceID is already represented
8349 while (*p)
8350 {
8351 if (*p == set)
8352 {
8353 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
8354 mDNS_Unlock(m);
8355 return(mStatus_AlreadyRegistered);
8356 }
8357
8358 if ((*p)->InterfaceID == set->InterfaceID)
8359 {
8360 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
8361 set->InterfaceActive = mDNSfalse;
8362 if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
8363 if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
8364 if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
8365 }
8366
8367 p=&(*p)->next;
8368 }
8369
8370 set->next = mDNSNULL;
8371 *p = set;
8372
8373 if (set->Advertise)
8374 AdvertiseInterface(m, set);
8375
8376 LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
8377 set->InterfaceActive ?
8378 "not represented in list; marking active and retriggering queries" :
8379 "already represented in list; marking inactive for now");
8380
8381 if (set->NetWake) mDNS_ActivateNetWake_internal(m, set);
8382
8383 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8384 // giving the false impression that there's an active representative of this interface when there really isn't.
8385 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
8386 // even if we believe that we previously had an active representative of this interface.
8387 if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
8388 {
8389 DNSQuestion *q;
8390 // If flapping, delay between first and second queries is eight seconds instead of one
8391 mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0;
8392 mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
8393 mDNSs32 newSS = 0;
8394
8395 // Use a small amount of randomness:
8396 // In the case of a network administrator turning on an Ethernet hub so that all the
8397 // connected machines establish link at exactly the same time, we don't want them all
8398 // to go and hit the network with identical queries at exactly the same moment.
8399 newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
8400 #if APPLE_OSX_mDNSResponder
8401 // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
8402 // of network change notifications in a row, and we don't know when we're done getting notified.
8403 // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
8404 newSS += mDNSPlatformOneSecond * 2;
8405 #endif
8406 if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS;
8407
8408 if (flapping)
8409 {
8410 LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)",
8411 set->ifname, &set->ip);
8412 if (!m->SuppressProbes ||
8413 m->SuppressProbes - (m->timenow + delay) < 0)
8414 m->SuppressProbes = (m->timenow + delay);
8415 }
8416
8417 for (q = m->Questions; q; q=q->next) // Scan our list of questions
8418 if (mDNSOpaque16IsZero(q->TargetQID))
8419 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
8420 { // then reactivate this question
8421 mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
8422 mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
8423 mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0;
8424 if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
8425
8426 if (!q->ThisQInterval || q->ThisQInterval > initial)
8427 {
8428 q->ThisQInterval = initial;
8429 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
8430 }
8431 q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
8432 q->RecentAnswerPkts = 0;
8433 SetNextQueryTime(m,q);
8434 }
8435
8436 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
8437 // we now need them to re-probe if necessary, and then re-announce.
8438 for (rr = m->ResourceRecords; rr; rr=rr->next)
8439 if (!AuthRecord_uDNS(rr))
8440 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
8441 {
8442 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
8443 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
8444 if (rr->AnnounceCount < announce) rr->AnnounceCount = announce;
8445 InitializeLastAPTime(m, rr);
8446 }
8447 }
8448
8449 RestartRecordGetZoneData(m);
8450
8451 mDNS_Unlock(m);
8452 return(mStatus_NoError);
8453 }
8454
8455 // Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
8456 // the record list and/or question list.
8457 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8458 mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
8459 {
8460 NetworkInterfaceInfo **p = &m->HostInterfaces;
8461
8462 mDNSBool revalidate = mDNSfalse;
8463 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
8464 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
8465 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
8466 if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
8467
8468 mDNS_Lock(m);
8469
8470 // Find this record in our list
8471 while (*p && *p != set) p=&(*p)->next;
8472 if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
8473
8474 mDNS_DeactivateNetWake_internal(m, set);
8475
8476 // Unlink this record from our list
8477 *p = (*p)->next;
8478 set->next = mDNSNULL;
8479
8480 if (!set->InterfaceActive)
8481 {
8482 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
8483 NetworkInterfaceInfo *intf;
8484 for (intf = m->HostInterfaces; intf; intf = intf->next)
8485 if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
8486 UpdateInterfaceProtocols(m, intf);
8487 }
8488 else
8489 {
8490 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID);
8491 if (intf)
8492 {
8493 LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
8494 " making it active", set->InterfaceID, set->ifname, &set->ip);
8495 if (intf->InterfaceActive)
8496 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip);
8497 intf->InterfaceActive = mDNStrue;
8498 UpdateInterfaceProtocols(m, intf);
8499
8500 if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf);
8501
8502 // See if another representative *of the same type* exists. If not, we mave have gone from
8503 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
8504 for (intf = m->HostInterfaces; intf; intf = intf->next)
8505 if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
8506 break;
8507 if (!intf) revalidate = mDNStrue;
8508 }
8509 else
8510 {
8511 mDNSu32 slot;
8512 CacheGroup *cg;
8513 CacheRecord *rr;
8514 DNSQuestion *q;
8515 DNSServer *s;
8516
8517 LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
8518 " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
8519
8520 if (flapping)
8521 LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)",
8522 set->ifname, &set->ip);
8523
8524 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
8525 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
8526 for (q = m->Questions; q; q=q->next)
8527 {
8528 if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
8529 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
8530 {
8531 q->FlappingInterface2 = q->FlappingInterface1;
8532 q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away
8533 }
8534 }
8535
8536 // 2. Flush any cache records received on this interface
8537 revalidate = mDNSfalse; // Don't revalidate if we're flushing the records
8538 FORALL_CACHERECORDS(slot, cg, rr)
8539 if (rr->resrec.InterfaceID == set->InterfaceID)
8540 {
8541 // If this interface is deemed flapping,
8542 // postpone deleting the cache records in case the interface comes back again
8543 if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
8544 else
8545 {
8546 // We want these record to go away in 30 seconds
8547 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
8548 // if the interface does come back, any relevant questions will be reactivated anyway
8549 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
8550 rr->UnansweredQueries = MaxUnansweredQueries;
8551 }
8552 }
8553
8554 // 3. Any DNS servers specific to this interface are now unusable
8555 for (s = m->DNSServers; s; s = s->next)
8556 if (s->interface == set->InterfaceID)
8557 {
8558 s->interface = mDNSInterface_Any;
8559 s->teststate = DNSServer_Disabled;
8560 }
8561 }
8562 }
8563
8564 // If we were advertising on this interface, deregister those address and reverse-lookup records now
8565 if (set->Advertise) DeadvertiseInterface(m, set);
8566
8567 // If we have any cache records received on this interface that went away, then re-verify them.
8568 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8569 // giving the false impression that there's an active representative of this interface when there really isn't.
8570 // Don't need to do this when shutting down, because *all* interfaces are about to go away
8571 if (revalidate && !m->ShutdownTime)
8572 {
8573 mDNSu32 slot;
8574 CacheGroup *cg;
8575 CacheRecord *rr;
8576 m->NextCacheCheck = m->timenow;
8577 FORALL_CACHERECORDS(slot, cg, rr)
8578 if (rr->resrec.InterfaceID == set->InterfaceID)
8579 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
8580 }
8581
8582 mDNS_Unlock(m);
8583 }
8584
8585 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8586 {
8587 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
8588 (void)m; // Unused parameter
8589
8590 #if MDNS_DEBUGMSGS
8591 {
8592 char *msg = "Unknown result";
8593 if (result == mStatus_NoError) msg = "Name Registered";
8594 else if (result == mStatus_NameConflict) msg = "Name Conflict";
8595 else if (result == mStatus_MemFree) msg = "Memory Free";
8596 debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
8597 }
8598 #endif
8599
8600 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
8601 if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
8602
8603 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
8604 if (result == mStatus_NameConflict)
8605 {
8606 sr->Conflict = mDNStrue; // Record that this service set had a conflict
8607 mDNS_DeregisterService(m, sr); // Unlink the records from our list
8608 return;
8609 }
8610
8611 if (result == mStatus_MemFree)
8612 {
8613 // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
8614 // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
8615 // every record is finished cleaning up.
8616 mDNSu32 i;
8617 if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8618 if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8619 if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8620 if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8621 for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
8622
8623 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
8624 // then we can now report the NameConflict to the client
8625 if (sr->Conflict) result = mStatus_NameConflict;
8626
8627 if (sr->srs_nta)
8628 {
8629 LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV));
8630 CancelGetZoneData(m, sr->srs_nta);
8631 sr->srs_nta = mDNSNULL;
8632 }
8633 }
8634
8635 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
8636 // function is allowed to do anything, including deregistering this service and freeing its memory.
8637 if (sr->ServiceCallback)
8638 sr->ServiceCallback(m, sr, result);
8639 }
8640
8641 mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8642 {
8643 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
8644 if (sr->ServiceCallback)
8645 sr->ServiceCallback(m, sr, result);
8646 }
8647
8648 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8649 mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
8650 {
8651 mDNSu32 i;
8652 ServiceRecordSet **p = &m->ServiceRegistrations;
8653 while (*p && *p != srs) p=&(*p)->uDNS_next;
8654 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
8655
8656 srs->uDNS_next = mDNSNULL;
8657 *p = srs;
8658
8659 srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
8660 srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
8661 srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
8662 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
8663
8664 srs->srs_uselease = mDNStrue;
8665
8666 if (srs->RR_SRV.AutoTarget)
8667 {
8668 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
8669 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
8670 // with the port number in our advertised SRV record automatically tracking the external mapped port.
8671 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
8672 if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
8673 }
8674
8675 if (!GetServiceTarget(m, &srs->RR_SRV))
8676 {
8677 // defer registration until we've got a target
8678 LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
8679 srs->state = regState_NoTarget;
8680 return mStatus_NoError;
8681 }
8682
8683 ActivateUnicastRegistration(m, &srs->RR_SRV);
8684 srs->state = regState_FetchingZoneData;
8685 return mStatus_NoError;
8686 }
8687 #endif
8688
8689 // Note:
8690 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
8691 // Type is service type (e.g. "_ipp._tcp.")
8692 // Domain is fully qualified domain name (i.e. ending with a null label)
8693 // We always register a TXT, even if it is empty (so that clients are not
8694 // left waiting forever looking for a nonexistent record.)
8695 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
8696 // then the default host name (m->MulticastHostname) is automatically used
8697 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
8698 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
8699 const domainlabel *const name, const domainname *const type, const domainname *const domain,
8700 const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
8701 AuthRecord *SubTypes, mDNSu32 NumSubTypes,
8702 const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
8703 {
8704 mStatus err;
8705 mDNSu32 i;
8706
8707 sr->state = regState_Zero;
8708 sr->srs_uselease = 0;
8709 sr->TestForSelfConflict = 0;
8710 sr->Private = 0;
8711 sr->id = zeroID;
8712 sr->zone.c[0] = 0;
8713 sr->SRSUpdateServer = zeroAddr;
8714 sr->SRSUpdatePort = zeroIPPort;
8715 mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
8716 sr->NATinfo.IntPort = port; // Record originally-requested port
8717 sr->ClientCallbackDeferred = 0;
8718 sr->DeferredStatus = 0;
8719 sr->SRVUpdateDeferred = 0;
8720 sr->SRVChanged = 0;
8721 sr->tcp = mDNSNULL;
8722
8723 sr->ServiceCallback = Callback;
8724 sr->ServiceContext = Context;
8725 sr->Conflict = mDNSfalse;
8726
8727 sr->Extras = mDNSNULL;
8728 sr->NumSubTypes = NumSubTypes;
8729 sr->SubTypes = SubTypes;
8730
8731 // Initialize the AuthRecord objects to sane values
8732 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
8733 mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
8734 mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
8735 mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
8736 mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
8737
8738 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
8739 if (mDNSIPPortIsZero(port))
8740 return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
8741
8742 // If the client is registering an oversized TXT record,
8743 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
8744 if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
8745 sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
8746
8747 // Set up the record names
8748 // For now we only create an advisory record for the main type, not for subtypes
8749 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
8750 if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
8751 return(mStatus_BadParamErr);
8752 if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
8753 if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
8754 AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name);
8755
8756 // 1. Set up the ADV record rdata to advertise our service type
8757 AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
8758
8759 // 2. Set up the PTR record rdata to point to our service name
8760 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
8761 AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
8762 sr->RR_PTR.Additional1 = &sr->RR_SRV;
8763 sr->RR_PTR.Additional2 = &sr->RR_TXT;
8764
8765 // 2a. Set up any subtype PTRs to point to our service name
8766 // If the client is using subtypes, it is the client's responsibility to have
8767 // already set the first label of the record name to the subtype being registered
8768 for (i=0; i<NumSubTypes; i++)
8769 {
8770 domainname st;
8771 AssignDomainName(&st, sr->SubTypes[i].resrec.name);
8772 st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
8773 AppendDomainName(&st, type);
8774 mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
8775 if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
8776 AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage);
8777 sr->SubTypes[i].Additional1 = &sr->RR_SRV;
8778 sr->SubTypes[i].Additional2 = &sr->RR_TXT;
8779 }
8780
8781 // 3. Set up the SRV record rdata.
8782 sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
8783 sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
8784 sr->RR_SRV.resrec.rdata->u.srv.port = port;
8785
8786 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
8787 if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host);
8788 else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
8789
8790 // 4. Set up the TXT record rdata,
8791 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
8792 if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
8793 else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
8794 {
8795 sr->RR_TXT.resrec.rdlength = txtlen;
8796 if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
8797 mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen);
8798 }
8799 sr->RR_TXT.DependentOn = &sr->RR_SRV;
8800
8801 sr->srs_nta = mDNSNULL;
8802
8803 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8804 // If the client has specified an explicit InterfaceID,
8805 // then we do a multicast registration on that interface, even for unicast domains.
8806 if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
8807 {
8808 mStatus status;
8809 mDNS_Lock(m);
8810 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
8811 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
8812 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
8813 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
8814 if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
8815
8816 status = uDNS_RegisterService(m, sr);
8817 mDNS_Unlock(m);
8818 return(status);
8819 }
8820 #endif
8821
8822 mDNS_Lock(m);
8823 err = mDNS_Register_internal(m, &sr->RR_SRV);
8824 if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
8825 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
8826 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
8827 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
8828 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
8829 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
8830 if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
8831 for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
8832 if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
8833
8834 mDNS_Unlock(m);
8835
8836 if (err) mDNS_DeregisterService(m, sr);
8837 return(err);
8838 }
8839
8840 mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
8841 {
8842 (void)m; // Unused
8843 (void)rr; // Unused
8844 (void)result; // Unused
8845 LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr));
8846 }
8847
8848 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
8849 ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
8850 {
8851 ExtraResourceRecord **e;
8852 mStatus status;
8853
8854 extra->next = mDNSNULL;
8855 mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
8856 extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
8857 AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
8858
8859 mDNS_Lock(m);
8860 e = &sr->Extras;
8861 while (*e) e = &(*e)->next;
8862
8863 if (ttl == 0) ttl = kStandardTTL;
8864
8865 extra->r.DependentOn = &sr->RR_SRV;
8866
8867 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
8868 extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
8869
8870 status = mDNS_Register_internal(m, &extra->r);
8871 if (status == mStatus_NoError)
8872 {
8873 *e = extra;
8874 #ifndef UNICAST_DISABLED
8875 if (AuthRecord_uDNS(&sr->RR_SRV))
8876 {
8877 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???)
8878 extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
8879 if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
8880 }
8881 #endif
8882 }
8883
8884 mDNS_Unlock(m);
8885 return(status);
8886 }
8887
8888 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
8889 mDNSRecordCallback MemFreeCallback, void *Context)
8890 {
8891 ExtraResourceRecord **e;
8892 mStatus status;
8893
8894 mDNS_Lock(m);
8895 e = &sr->Extras;
8896 while (*e && *e != extra) e = &(*e)->next;
8897 if (!*e)
8898 {
8899 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
8900 status = mStatus_BadReferenceErr;
8901 }
8902 else
8903 {
8904 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
8905 extra->r.RecordCallback = MemFreeCallback;
8906 extra->r.RecordContext = Context;
8907 *e = (*e)->next;
8908 status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
8909 }
8910 mDNS_Unlock(m);
8911 return(status);
8912 }
8913
8914 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
8915 {
8916 // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
8917 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
8918 domainlabel name1, name2;
8919 domainname type, domain;
8920 const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target;
8921 ExtraResourceRecord *extras = sr->Extras;
8922 mStatus err;
8923
8924 DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
8925 if (!newname)
8926 {
8927 name2 = name1;
8928 IncrementLabelSuffix(&name2, mDNStrue);
8929 newname = &name2;
8930 }
8931
8932 if (SameDomainName(&domain, &localdomain))
8933 debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
8934 else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
8935
8936 err = mDNS_RegisterService(m, sr, newname, &type, &domain,
8937 host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
8938 sr->SubTypes, sr->NumSubTypes,
8939 sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
8940
8941 // mDNS_RegisterService() just reset sr->Extras to NULL.
8942 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
8943 // through the old list of extra records, and re-add them to our freshly created service registration
8944 while (!err && extras)
8945 {
8946 ExtraResourceRecord *e = extras;
8947 extras = extras->next;
8948 err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
8949 }
8950
8951 return(err);
8952 }
8953
8954 // Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
8955 // which may change the record list and/or question list.
8956 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8957 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
8958 {
8959 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
8960 if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
8961
8962 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8963 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
8964 {
8965 mStatus status;
8966 mDNS_Lock(m);
8967 status = uDNS_DeregisterService(m, sr);
8968 mDNS_Unlock(m);
8969 return(status);
8970 }
8971 #endif
8972 if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
8973 {
8974 debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
8975 return(mStatus_BadReferenceErr);
8976 }
8977 else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
8978 {
8979 debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
8980 // Avoid race condition:
8981 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
8982 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
8983 // If the client happens to deregister the service in the middle of that process, then
8984 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
8985 // instead of incorrectly promoting it to mStatus_NameConflict.
8986 // This race condition is exposed particularly when the conformance test generates
8987 // a whole batch of simultaneous conflicts across a range of services all advertised
8988 // using the same system default name, and if we don't take this precaution then
8989 // we end up incrementing m->nicelabel multiple times instead of just once.
8990 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
8991 sr->Conflict = mDNSfalse;
8992 return(mStatus_NoError);
8993 }
8994 else
8995 {
8996 mDNSu32 i;
8997 mStatus status;
8998 ExtraResourceRecord *e;
8999 mDNS_Lock(m);
9000 e = sr->Extras;
9001
9002 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
9003 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
9004 mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
9005 mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
9006
9007 mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
9008
9009 // We deregister all of the extra records, but we leave the sr->Extras list intact
9010 // in case the client wants to do a RenameAndReregister and reinstate the registration
9011 while (e)
9012 {
9013 mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
9014 e = e->next;
9015 }
9016
9017 for (i=0; i<sr->NumSubTypes; i++)
9018 mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
9019
9020 // Be sure to deregister the PTR last!
9021 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
9022 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
9023 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
9024 // we've deregistered all our records and done any other necessary cleanup before that happens.
9025 status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
9026 mDNS_Unlock(m);
9027 return(status);
9028 }
9029 }
9030
9031 // Create a registration that asserts that no such service exists with this name.
9032 // This can be useful where there is a given function is available through several protocols.
9033 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
9034 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
9035 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
9036 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
9037 mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
9038 const domainlabel *const name, const domainname *const type, const domainname *const domain,
9039 const domainname *const host,
9040 const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
9041 {
9042 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
9043 if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
9044 rr->resrec.rdata->u.srv.priority = 0;
9045 rr->resrec.rdata->u.srv.weight = 0;
9046 rr->resrec.rdata->u.srv.port = zeroIPPort;
9047 if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
9048 else rr->AutoTarget = Target_AutoHost;
9049 return(mDNS_Register(m, rr));
9050 }
9051
9052 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
9053 mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
9054 {
9055 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
9056 if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
9057 if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr);
9058 return(mDNS_Register(m, rr));
9059 }
9060
9061 mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
9062 {
9063 mDNSOpaque16 id;
9064 int i;
9065 for (i=0; i<10; i++)
9066 {
9067 AuthRecord *r;
9068 DNSQuestion *q;
9069 id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
9070 for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue;
9071 for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue;
9072 break;
9073 }
9074 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id));
9075 return id;
9076 }
9077
9078 // ***************************************************************************
9079 #if COMPILER_LIKES_PRAGMA_MARK
9080 #pragma mark -
9081 #pragma mark - Sleep Proxy Server
9082 #endif
9083
9084 mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
9085 {
9086 // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
9087 // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
9088 // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
9089 // then we'll transition out of probing state and start answering ARPs again.
9090 rr->resrec.RecordType = kDNSRecordTypeUnique;
9091 rr->ProbeCount = DefaultProbeCountForTypeUnique;
9092 rr->AnnounceCount = InitialAnnounceCount;
9093 InitializeLastAPTime(m, rr);
9094 }
9095
9096 mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
9097 {
9098 static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } };
9099 static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
9100 static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen
9101 static const mDNSOpaque16 ARP_op_request = { { 0, 1 } };
9102 const EthernetHeader *const eth = (const EthernetHeader *)p;
9103 const ARP_EthIP *const arp = (const ARP_EthIP *)(eth+1);
9104 const IPv4Header *const v4 = (const IPv4Header *)(eth+1);
9105 const IPv6Header *const v6 = (const IPv6Header *)(eth+1);
9106 if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger)
9107 {
9108 AuthRecord *rr;
9109 NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
9110 if (!intf) return;
9111
9112 debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa);
9113
9114 mDNS_Lock(m);
9115
9116 // Pass 1:
9117 // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
9118 // We also process and answer ARPs from our own kernel (no special treatment for localhost).
9119 // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
9120 // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below.
9121 if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
9122 for (rr = m->ResourceRecords; rr; rr=rr->next)
9123 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
9124 {
9125 static const char msg1[] = "ARP Req from owner -- re-probing";
9126 static const char msg2[] = "Ignoring ARP Request from ";
9127 static const char msg3[] = "Creating Local ARP Cache entry ";
9128 static const char msg4[] = "Answering ARP Request from ";
9129 const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
9130 (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
9131 mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4;
9132 LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
9133 InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
9134 if (msg == msg1) RestartProbing(m, rr);
9135 else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID);
9136 else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b);
9137 }
9138
9139 // Pass 2:
9140 // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
9141 // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
9142 // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
9143 // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
9144 // If we see an apparently conflicting ARP, we check the sender hardware address:
9145 // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
9146 // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
9147 if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
9148 debugf("ARP from self for %.4a", &arp->tpa);
9149 else
9150 {
9151 if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
9152 for (rr = m->ResourceRecords; rr; rr=rr->next)
9153 if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
9154 {
9155 RestartProbing(m, rr);
9156 if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
9157 LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
9158 InterfaceNameForID(m, InterfaceID),
9159 mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ",
9160 &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
9161 else
9162 {
9163 LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
9164 InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
9165 SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
9166 }
9167 }
9168 }
9169
9170 mDNS_Unlock(m);
9171 }
9172 else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
9173 {
9174 const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4;
9175 const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0);
9176 debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst);
9177 if (end >= required)
9178 {
9179 #define SSH_AsNumber 22
9180 #define ARD_AsNumber 3283
9181 #define IPSEC_AsNumber 4500
9182 static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } };
9183 static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } };
9184 static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } };
9185
9186 mDNSBool wake = mDNSfalse;
9187 mDNSIPPort port = zeroIPPort;
9188
9189 switch (v4->protocol)
9190 {
9191 #define XX wake ? "Received" : "Ignoring", end-p
9192 case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
9193 break;
9194
9195 case 6: {
9196 const TCPHeader *const tcp = (const TCPHeader *)trans;
9197 port = tcp->dst;
9198
9199 // Plan to wake if
9200 // (a) RST is not set, AND
9201 // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
9202 wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1);
9203
9204 // For now, to reduce spurious wakeups, we wake only for TCP SYN,
9205 // except for ssh connections, where we'll wake for plain data packets too
9206 if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse;
9207
9208 LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX,
9209 &v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port),
9210 (tcp->flags & 2) ? " SYN" : "",
9211 (tcp->flags & 1) ? " FIN" : "",
9212 (tcp->flags & 4) ? " RST" : "");
9213 }
9214 break;
9215
9216 case 17: {
9217 const UDPHeader *const udp = (const UDPHeader *)trans;
9218 mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
9219 port = udp->dst;
9220 wake = mDNStrue;
9221
9222 // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
9223 if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
9224
9225 // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
9226 // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
9227 // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
9228 // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
9229 if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
9230
9231 LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
9232 }
9233 break;
9234
9235 default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst);
9236 break;
9237 }
9238
9239 if (wake)
9240 {
9241 AuthRecord *rr, *r2;
9242
9243 mDNS_Lock(m);
9244 for (rr = m->ResourceRecords; rr; rr=rr->next)
9245 if (rr->resrec.InterfaceID == InterfaceID &&
9246 rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst))
9247 {
9248 const mDNSu8 *const tp = (v4->protocol == 6) ? (const mDNSu8 *)"\x4_tcp" : (const mDNSu8 *)"\x4_udp";
9249 for (r2 = m->ResourceRecords; r2; r2=r2->next)
9250 if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
9251 r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
9252 SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp))
9253 break;
9254 if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record
9255 if (r2)
9256 {
9257 rr->AnnounceCount = 0;
9258 LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
9259 InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
9260 SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
9261 }
9262 else
9263 LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
9264 InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
9265 }
9266 mDNS_Unlock(m);
9267 }
9268 }
9269 }
9270 else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
9271 {
9272 debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst);
9273 (void)v6;
9274 }
9275 }
9276
9277 mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name)
9278 {
9279 name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
9280 m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel);
9281 }
9282
9283 mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
9284 {
9285 if (result == mStatus_NameConflict)
9286 mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
9287 else if (result == mStatus_MemFree)
9288 {
9289 if (m->SleepState)
9290 m->SPSState = 3;
9291 else
9292 {
9293 m->SPSState = (m->SPSSocket != mDNSNULL);
9294 if (m->SPSState)
9295 {
9296 domainlabel name;
9297 ConstructSleepProxyServerName(m, &name);
9298 mDNS_RegisterService(m, srs,
9299 &name, &SleepProxyServiceType, &localdomain,
9300 mDNSNULL, m->SPSSocket->port, // Host, port
9301 (mDNSu8 *)"", 1, // TXT data, length
9302 mDNSNULL, 0, // Subtypes (none)
9303 mDNSInterface_Any, // Interface ID
9304 SleepProxyServerCallback, mDNSNULL); // Callback and context
9305 }
9306 LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped");
9307 }
9308 }
9309 }
9310
9311 mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
9312 {
9313 // If turning off SPS, close our socket
9314 // (Do this first, BEFORE calling mDNS_DeregisterService below)
9315 if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; }
9316
9317 // If turning off, or changing type, deregister old name
9318 if (m->SPSState == 1 && sps != m->SPSType)
9319 { m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); }
9320
9321 // Record our new SPS parameters
9322 m->SPSType = sps;
9323 m->SPSPortability = port;
9324 m->SPSMarginalPower = marginalpower;
9325 m->SPSTotalPower = totpower;
9326
9327 // If turning on, open socket and advertise service
9328 if (sps)
9329 {
9330 if (!m->SPSSocket)
9331 {
9332 m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
9333 if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
9334 }
9335 if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree);
9336 }
9337 }
9338
9339 // ***************************************************************************
9340 #if COMPILER_LIKES_PRAGMA_MARK
9341 #pragma mark -
9342 #pragma mark - Startup and Shutdown
9343 #endif
9344
9345 mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
9346 {
9347 if (storage && numrecords)
9348 {
9349 mDNSu32 i;
9350 debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
9351 for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
9352 storage[numrecords-1].next = m->rrcache_free;
9353 m->rrcache_free = storage;
9354 m->rrcache_size += numrecords;
9355 }
9356 }
9357
9358 mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
9359 {
9360 mDNS_Lock(m);
9361 mDNS_GrowCache_internal(m, storage, numrecords);
9362 mDNS_Unlock(m);
9363 }
9364
9365 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
9366 CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
9367 mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
9368 {
9369 mDNSu32 slot;
9370 mDNSs32 timenow;
9371 mStatus result;
9372
9373 if (!rrcachestorage) rrcachesize = 0;
9374
9375 m->p = p;
9376 m->KnownBugs = 0;
9377 m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
9378 m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
9379 m->DivertMulticastAdvertisements = mDNSfalse;
9380 m->mDNSPlatformStatus = mStatus_Waiting;
9381 m->UnicastPort4 = zeroIPPort;
9382 m->UnicastPort6 = zeroIPPort;
9383 m->PrimaryMAC = zeroEthAddr;
9384 m->MainCallback = Callback;
9385 m->MainContext = Context;
9386 m->rec.r.resrec.RecordType = 0;
9387
9388 // For debugging: To catch and report locking failures
9389 m->mDNS_busy = 0;
9390 m->mDNS_reentrancy = 0;
9391 m->ShutdownTime = 0;
9392 m->lock_rrcache = 0;
9393 m->lock_Questions = 0;
9394 m->lock_Records = 0;
9395
9396 // Task Scheduling variables
9397 result = mDNSPlatformTimeInit();
9398 if (result != mStatus_NoError) return(result);
9399 m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
9400 timenow = mDNS_TimeNow_NoLock(m);
9401
9402 m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
9403 m->timenow_last = timenow;
9404 m->NextScheduledEvent = timenow;
9405 m->SuppressSending = timenow;
9406 m->NextCacheCheck = timenow + 0x78000000;
9407 m->NextScheduledQuery = timenow + 0x78000000;
9408 m->NextScheduledProbe = timenow + 0x78000000;
9409 m->NextScheduledResponse = timenow + 0x78000000;
9410 m->NextScheduledNATOp = timenow + 0x78000000;
9411 m->NextScheduledSPS = timenow + 0x78000000;
9412 m->RandomQueryDelay = 0;
9413 m->RandomReconfirmDelay = 0;
9414 m->PktNum = 0;
9415 m->SleepState = SleepState_Awake;
9416 m->SleepSeqNum = 0;
9417 m->SystemWakeOnLANEnabled = mDNSfalse;
9418 m->DelaySleep = 0;
9419 m->SleepLimit = 0;
9420
9421 // These fields only required for mDNS Searcher...
9422 m->Questions = mDNSNULL;
9423 m->NewQuestions = mDNSNULL;
9424 m->CurrentQuestion = mDNSNULL;
9425 m->LocalOnlyQuestions = mDNSNULL;
9426 m->NewLocalOnlyQuestions = mDNSNULL;
9427 m->rrcache_size = 0;
9428 m->rrcache_totalused = 0;
9429 m->rrcache_active = 0;
9430 m->rrcache_report = 10;
9431 m->rrcache_free = mDNSNULL;
9432
9433 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
9434
9435 mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
9436
9437 // Fields below only required for mDNS Responder...
9438 m->hostlabel.c[0] = 0;
9439 m->nicelabel.c[0] = 0;
9440 m->MulticastHostname.c[0] = 0;
9441 m->HIHardware.c[0] = 0;
9442 m->HISoftware.c[0] = 0;
9443 m->ResourceRecords = mDNSNULL;
9444 m->DuplicateRecords = mDNSNULL;
9445 m->NewLocalRecords = mDNSNULL;
9446 m->CurrentRecord = mDNSNULL;
9447 m->HostInterfaces = mDNSNULL;
9448 m->ProbeFailTime = 0;
9449 m->NumFailedProbes = 0;
9450 m->SuppressProbes = 0;
9451
9452 #ifndef UNICAST_DISABLED
9453 m->NextuDNSEvent = timenow + 0x78000000;
9454 m->NextSRVUpdate = timenow + 0x78000000;
9455 m->SuppressStdPort53Queries = 0;
9456
9457 m->ServiceRegistrations = mDNSNULL;
9458 m->DNSServers = mDNSNULL;
9459
9460 m->Router = zeroAddr;
9461 m->AdvertisedV4 = zeroAddr;
9462 m->AdvertisedV6 = zeroAddr;
9463
9464 m->AuthInfoList = mDNSNULL;
9465
9466 m->ReverseMap.ThisQInterval = -1;
9467 m->StaticHostname.c[0] = 0;
9468 m->FQDN.c[0] = 0;
9469 m->Hostnames = mDNSNULL;
9470 m->AutoTunnelHostAddr.b[0] = 0;
9471 m->AutoTunnelHostAddrActive = mDNSfalse;
9472 m->AutoTunnelLabel.c[0] = 0;
9473
9474 m->RegisterSearchDomains = mDNSfalse;
9475
9476 // NAT traversal fields
9477 m->NATTraversals = mDNSNULL;
9478 m->CurrentNATTraversal = mDNSNULL;
9479 m->retryIntervalGetAddr = 0; // delta between time sent and retry
9480 m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry
9481 m->ExternalAddress = zerov4Addr;
9482
9483 m->NATMcastRecvskt = mDNSNULL;
9484 m->LastNATupseconds = 0;
9485 m->LastNATReplyLocalTime = timenow;
9486 m->LastNATMapResultCode = NATErr_None;
9487
9488 m->UPnPInterfaceID = 0;
9489 m->SSDPSocket = mDNSNULL;
9490 m->SSDPWANPPPConnection = mDNSfalse;
9491 m->UPnPRouterPort = zeroIPPort;
9492 m->UPnPSOAPPort = zeroIPPort;
9493 m->UPnPRouterURL = mDNSNULL;
9494 m->UPnPWANPPPConnection = mDNSfalse;
9495 m->UPnPSOAPURL = mDNSNULL;
9496 m->UPnPRouterAddressString = mDNSNULL;
9497 m->UPnPSOAPAddressString = mDNSNULL;
9498 m->SPSType = 0;
9499 m->SPSPortability = 0;
9500 m->SPSMarginalPower = 0;
9501 m->SPSTotalPower = 0;
9502 m->SPSState = 0;
9503 m->SPSProxyListChanged = mDNSNULL;
9504 m->SPSSocket = mDNSNULL;
9505 m->SPSBrowseCallback = mDNSNULL;
9506 m->ProxyRecords = 0;
9507
9508 #endif
9509
9510 #if APPLE_OSX_mDNSResponder
9511 m->TunnelClients = mDNSNULL;
9512 #endif
9513
9514 result = mDNSPlatformInit(m);
9515
9516 #ifndef UNICAST_DISABLED
9517 // It's better to do this *after* the platform layer has set up the
9518 // interface list and security credentials
9519 uDNS_SetupDNSConfig(m); // Get initial DNS configuration
9520 #endif
9521
9522 return(result);
9523 }
9524
9525 mDNSexport void mDNS_ConfigChanged(mDNS *const m)
9526 {
9527 if (m->SPSState == 1)
9528 {
9529 domainlabel name, newname;
9530 domainname type, domain;
9531 DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain);
9532 ConstructSleepProxyServerName(m, &newname);
9533 if (!SameDomainLabelCS(name.c, newname.c))
9534 {
9535 LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c);
9536 // When SleepProxyServerCallback gets the mStatus_MemFree message,
9537 // it will reregister the service under the new name
9538 m->SPSState = 2;
9539 mDNS_DeregisterService(m, &m->SPSRecords);
9540 }
9541 }
9542
9543 if (m->MainCallback)
9544 m->MainCallback(m, mStatus_ConfigChanged);
9545 }
9546
9547 mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
9548 {
9549 (void)m; // unused
9550 debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
9551 mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
9552 }
9553
9554 mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
9555 {
9556 mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
9557 cr->resrec.rrtype == kDNSType_A ||
9558 cr->resrec.rrtype == kDNSType_AAAA ||
9559 cr->resrec.rrtype == kDNSType_SRV;
9560
9561 (void) lameduck;
9562 (void) ptr;
9563 debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
9564
9565 if (purge) mDNS_PurgeCacheResourceRecord(m, cr);
9566 else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
9567 }
9568
9569 mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
9570 {
9571 mDNSu32 slot;
9572 CacheGroup *cg;
9573 CacheRecord *cr;
9574
9575 mDNSAddr v4, v6, r;
9576 domainname fqdn;
9577 DNSServer *ptr, **p = &m->DNSServers;
9578 const DNSServer *oldServers = m->DNSServers;
9579 DNSQuestion *q;
9580
9581 debugf("uDNS_SetupDNSConfig: entry");
9582
9583 if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
9584
9585 mDNS_Lock(m);
9586
9587 // Let the platform layer get the current DNS information
9588 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
9589 // (no need to hit the network with domain enumeration queries until we actually need that information).
9590 for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
9591
9592 mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
9593
9594 // Update our qDNSServer pointers before we go and free the DNSServer object memory
9595 for (q = m->Questions; q; q=q->next)
9596 if (!mDNSOpaque16IsZero(q->TargetQID))
9597 {
9598 DNSServer *s = GetServerForName(m, &q->qname);
9599 DNSServer *t = q->qDNSServer;
9600 if (t != s)
9601 {
9602 // If DNS Server for this question has changed, reactivate it
9603 debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
9604 t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
9605 s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
9606 q->qname.c, DNSTypeName(q->qtype));
9607 q->qDNSServer = s;
9608 q->unansweredQueries = 0;
9609 ActivateUnicastQuery(m, q, mDNStrue);
9610 }
9611 }
9612
9613 // Flush all records that match a new resolver
9614 FORALL_CACHERECORDS(slot, cg, cr)
9615 {
9616 ptr = GetServerForName(m, cr->resrec.name);
9617 if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
9618 PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
9619 }
9620
9621 while (*p)
9622 {
9623 if (((*p)->flags & DNSServer_FlagDelete) != 0)
9624 {
9625 // Scan our cache, looking for uDNS records that we would have queried this server for.
9626 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
9627 // different DNS servers can give different answers to the same question.
9628 ptr = *p;
9629 ptr->flags &= ~DNSServer_FlagDelete; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
9630 FORALL_CACHERECORDS(slot, cg, cr)
9631 if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
9632 PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
9633 *p = (*p)->next;
9634 debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
9635 mDNSPlatformMemFree(ptr);
9636 }
9637 else
9638 {
9639 (*p)->flags &= ~DNSServer_FlagNew;
9640 p = &(*p)->next;
9641 }
9642 }
9643
9644 // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
9645 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
9646 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
9647 // Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated.
9648 if ((m->DNSServers != mDNSNULL) != (oldServers != mDNSNULL))
9649 {
9650 int count = 0;
9651 FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
9652 LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
9653 m->DNSServers ? "DNS server became" : "No DNS servers", count);
9654 }
9655
9656 // If we no longer have any DNS servers, we need to force anything that needs to get zone data
9657 // to get that information again (which will fail, since we have no more DNS servers)
9658 if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL)) RestartRecordGetZoneData(m);
9659
9660 // Did our FQDN change?
9661 if (!SameDomainName(&fqdn, &m->FQDN))
9662 {
9663 if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
9664
9665 AssignDomainName(&m->FQDN, &fqdn);
9666
9667 if (m->FQDN.c[0])
9668 {
9669 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
9670 mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
9671 }
9672 }
9673
9674 mDNS_Unlock(m);
9675
9676 // handle router and primary interface changes
9677 v4 = v6 = r = zeroAddr;
9678 v4.type = r.type = mDNSAddrType_IPv4;
9679
9680 if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
9681 {
9682 mDNS_SetPrimaryInterfaceInfo(m,
9683 !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
9684 !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL,
9685 !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL);
9686 }
9687 else
9688 {
9689 mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL);
9690 if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
9691 }
9692
9693 return mStatus_NoError;
9694 }
9695
9696 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
9697 {
9698 m->mDNSPlatformStatus = result;
9699 if (m->MainCallback)
9700 {
9701 mDNS_Lock(m);
9702 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
9703 m->MainCallback(m, mStatus_NoError);
9704 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
9705 mDNS_Unlock(m);
9706 }
9707 }
9708
9709 extern ServiceRecordSet *CurrentServiceRecordSet;
9710
9711 mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start)
9712 {
9713 m->CurrentRecord = start;
9714 while (m->CurrentRecord)
9715 {
9716 AuthRecord *rr = m->CurrentRecord;
9717 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
9718 {
9719 LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
9720 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9721 }
9722 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
9723 // the list may have been changed in that call.
9724 if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
9725 m->CurrentRecord = rr->next;
9726 }
9727 }
9728
9729 mDNSexport void mDNS_StartExit(mDNS *const m)
9730 {
9731 NetworkInterfaceInfo *intf;
9732 AuthRecord *rr;
9733
9734 mDNS_Lock(m);
9735
9736 m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
9737
9738 mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
9739 mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0);
9740 mDNS_ReclaimLockAfterCallback();
9741
9742 #ifndef UNICAST_DISABLED
9743 {
9744 SearchListElem *s;
9745 SuspendLLQs(m);
9746 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
9747 // because we deregister all records and services later in this routine
9748 while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
9749
9750 // For each member of our SearchList, deregister any records it may have created, and cut them from the list.
9751 // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
9752 // and we may crash because the list still contains dangling pointers.
9753 for (s = SearchList; s; s = s->next)
9754 while (s->AuthRecs)
9755 {
9756 ARListElem *dereg = s->AuthRecs;
9757 s->AuthRecs = s->AuthRecs->next;
9758 mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal); // Memory will be freed in the FreeARElemCallback
9759 }
9760 }
9761 #endif
9762
9763 for (intf = m->HostInterfaces; intf; intf = intf->next)
9764 if (intf->Advertise)
9765 DeadvertiseInterface(m, intf);
9766
9767 // Shut down all our active NAT Traversals
9768 while (m->NATTraversals)
9769 {
9770 NATTraversalInfo *t = m->NATTraversals;
9771 mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
9772
9773 // After stopping the NAT Traversal, we zero out the fields.
9774 // This has particularly important implications for our AutoTunnel records --
9775 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
9776 // handlers to just turn around and attempt to re-register those same records.
9777 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
9778 t->ExternalAddress = zerov4Addr;
9779 t->ExternalPort = zeroIPPort;
9780 t->Lifetime = 0;
9781 t->Result = mStatus_NoError;
9782 }
9783
9784 // Make sure there are nothing but deregistering records remaining in the list
9785 if (m->CurrentRecord)
9786 LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
9787
9788 // We're in the process of shutting down, so queries, etc. are no longer available.
9789 // Consequently, determining certain information, e.g. the uDNS update server's IP
9790 // address, will not be possible. The records on the main list are more likely to
9791 // already contain such information, so we deregister the duplicate records first.
9792 LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
9793 DeregLoop(m, m->DuplicateRecords);
9794 LogInfo("mDNS_StartExit: Deregistering resource records");
9795 DeregLoop(m, m->ResourceRecords);
9796
9797 // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
9798 // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
9799 if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond)
9800 {
9801 m->NextScheduledResponse = m->timenow;
9802 m->SuppressSending = 0;
9803 }
9804
9805 #if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9806 CurrentServiceRecordSet = m->ServiceRegistrations;
9807 while (CurrentServiceRecordSet)
9808 {
9809 ServiceRecordSet *srs = CurrentServiceRecordSet;
9810 LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c);
9811 uDNS_DeregisterService(m, srs);
9812 if (CurrentServiceRecordSet == srs)
9813 CurrentServiceRecordSet = srs->uDNS_next;
9814 }
9815 #endif
9816
9817 if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
9818 else LogInfo("mDNS_StartExit: No deregistering records remain");
9819
9820 if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
9821 else LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
9822
9823 for (rr = m->DuplicateRecords; rr; rr = rr->next)
9824 LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
9825
9826 // If any deregistering records remain, send their deregistration announcements before we exit
9827 if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
9828
9829 mDNS_Unlock(m);
9830
9831 LogInfo("mDNS_StartExit: done");
9832 }
9833
9834 mDNSexport void mDNS_FinalExit(mDNS *const m)
9835 {
9836 mDNSu32 rrcache_active = 0;
9837 mDNSu32 rrcache_totalused = 0;
9838 mDNSu32 slot;
9839 AuthRecord *rr;
9840 ServiceRecordSet *srs;
9841
9842 LogInfo("mDNS_FinalExit: mDNSPlatformClose");
9843 mDNSPlatformClose(m);
9844
9845 rrcache_totalused = m->rrcache_totalused;
9846 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
9847 {
9848 while (m->rrcache_hash[slot])
9849 {
9850 CacheGroup *cg = m->rrcache_hash[slot];
9851 while (cg->members)
9852 {
9853 CacheRecord *cr = cg->members;
9854 cg->members = cg->members->next;
9855 if (cr->CRActiveQuestion) rrcache_active++;
9856 ReleaseCacheRecord(m, cr);
9857 }
9858 cg->rrcache_tail = &cg->members;
9859 ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
9860 }
9861 }
9862 debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
9863 if (rrcache_active != m->rrcache_active)
9864 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
9865
9866 for (rr = m->ResourceRecords; rr; rr = rr->next)
9867 LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
9868
9869 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
9870 LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c);
9871
9872 LogInfo("mDNS_FinalExit: done");
9873 }