1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here.
19 *
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform).
24
25 * Formatting notes:
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37
38    Change History (most recent first):
39
40Log: mDNS.c,v $
41Revision 1.969.2.1  2009/07/23 23:41:25  cheshire
42<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
43
44Revision 1.969  2009/06/30 21:18:19  cheshire
45<rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
46Additional fixes:
471. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
482. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
49
50Revision 1.968  2009/06/29 23:51:09  cheshire
51<rdar://problem/6690034> Can't bind to Active Directory
52
53Revision 1.967  2009/06/27 00:25:27  cheshire
54<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
55Removed overly-complicate and ineffective multi-packet known-answer snooping code
56(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
57
58Revision 1.966  2009/06/26 01:55:55  cheshire
59<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
60Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
61add additional NSEC records only when there's space to do that without having to generate an additional packet
62
63Revision 1.965  2009/06/24 22:14:21  cheshire
64<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
65
66Revision 1.964  2009/06/03 23:07:13  cheshire
67<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
68Large records were not being added in cases where an NSEC record was also required
69
70Revision 1.963  2009/05/28 00:39:19  cheshire
71<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
72After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
73
74Revision 1.962  2009/05/19 23:40:37  cheshire
75<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
76Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
77
78Revision 1.961  2009/05/19 23:00:43  cheshire
79Improved comments and debugging messages
80
81Revision 1.960  2009/05/13 17:25:33  mkrochma
82<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
83Sleep proxy client should only look for services being advertised via Multicast
84
85Revision 1.959  2009/05/12 23:10:31  cheshire
86<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
87Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
88
89Revision 1.958  2009/05/12 19:19:20  cheshire
90<rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
91
92Revision 1.957  2009/05/07 23:56:25  cheshire
93<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
94To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
95
96Revision 1.956  2009/05/07 23:46:27  cheshire
97<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
98
99Revision 1.955  2009/05/07 23:40:54  cheshire
100Minor code rearrangement in preparation for upcoming changes
101
102Revision 1.954  2009/05/01 21:28:34  cheshire
103<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
104No longer suspend network operations after we've acknowledged that the machine is going to sleep,
105because other software may not have yet acknowledged the sleep event, and may be still trying
106to do unicast DNS queries or other Bonjour operations.
107
108Revision 1.953  2009/05/01 19:17:35  cheshire
109<rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
110
111Revision 1.952  2009/05/01 19:16:45  mcguire
112<rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
113
114Revision 1.951  2009/04/28 23:48:19  jessic2
115<rdar://problem/6830541> regservice_callback: instance->request is NULL 0
116
117Revision 1.950  2009/04/25 01:17:10  mcguire
118Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
119
120Revision 1.949  2009/04/25 01:11:02  mcguire
121Refactor: create separate function: RestartRecordGetZoneData
122
123Revision 1.948  2009/04/24 21:25:16  cheshire
124<rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
125
126Revision 1.947  2009/04/24 19:41:12  mcguire
127<rdar://problem/6791775> 4 second delay in DNS response
128
129Revision 1.946  2009/04/24 19:28:39  mcguire
130<rdar://problem/6791775> 4 second delay in DNS response
131
132Revision 1.945  2009/04/24 00:30:30  cheshire
133<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
134Added code to generate and process NSEC records
135
136Revision 1.944  2009/04/23 22:06:29  cheshire
137Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
138<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
139
140Revision 1.943  2009/04/22 01:19:56  jessic2
141<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
142
143Revision 1.942  2009/04/21 02:13:29  cheshire
144<rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
145Made code less susceptible to being tricked by stale packets echoed back from the network.
146
147Revision 1.941  2009/04/15 22:22:23  mcguire
148<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
149Additional fix: protect against deref of NULL
150
151Revision 1.940  2009/04/15 20:42:51  mcguire
152<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
153
154Revision 1.939  2009/04/11 00:19:32  jessic2
155<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
156
157Revision 1.938  2009/04/06 23:44:57  cheshire
158<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
159
160Revision 1.937  2009/04/04 00:14:49  mcguire
161fix logging in BeginSleepProcessing
162
163Revision 1.936  2009/04/04 00:10:59  mcguire
164don't ignore m->SystemWakeOnLANEnabled when going to sleep
165
166Revision 1.935  2009/04/01 17:50:11  mcguire
167cleanup mDNSRandom
168
169Revision 1.934  2009/03/27 17:17:58  cheshire
170Improved "Ignoring suspect uDNS response" debugging message
171
172Revision 1.933  2009/03/21 02:40:21  cheshire
173<rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
174
175Revision 1.932  2009/03/20 23:53:03  jessic2
176<rdar://problem/6646228> SIGHUP should restart all in-progress queries
177
178Revision 1.931  2009/03/18 19:08:15  cheshire
179Show old/new sleep sequence numbers in logical order
180
181Revision 1.930  2009/03/17 23:40:45  cheshire
182For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
183
184Revision 1.929  2009/03/17 21:55:56  cheshire
185Fixed mistake in logic for decided when we're ready to go to sleep
186
187Revision 1.928  2009/03/17 19:48:12  cheshire
188<rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
189
190Revision 1.927  2009/03/17 01:22:56  cheshire
191<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
192Initial support for resolving up to three Sleep Proxies in parallel
193
194Revision 1.926  2009/03/17 01:05:07  mcguire
195<rdar://problem/6657640> Reachability fixes on DNS config change
196
197Revision 1.925  2009/03/13 01:35:36  mcguire
198<rdar://problem/6657640> Reachability fixes on DNS config change
199
200Revision 1.924  2009/03/10 23:45:20  cheshire
201Added comments explaining usage of SetSPSProxyListChanged()
202
203Revision 1.923  2009/03/09 21:53:02  cheshire
204<rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
205
206Revision 1.922  2009/03/09 21:30:17  cheshire
207Improved some LogSPS messages; made RestartProbing() subroutine
208
209Revision 1.921  2009/03/06 22:53:31  cheshire
210Don't bother registering with Sleep Proxy if we have no advertised services
211
212Revision 1.920  2009/03/06 20:08:55  cheshire
213<rdar://problem/6601429> Sleep Proxy: Return error responses to clients
214
215Revision 1.919  2009/03/05 21:54:43  cheshire
216Improved "Sleep Proxy Server started / stopped" message
217
218Revision 1.918  2009/03/04 01:37:14  cheshire
219<rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
220
221Revision 1.917  2009/03/03 23:14:25  cheshire
222Got rid of code duplication by making subroutine "SetupOwnerOpt"
223
224Revision 1.916  2009/03/03 23:04:43  cheshire
225For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
226
227Revision 1.915  2009/03/03 22:51:53  cheshire
228<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
229
230Revision 1.914  2009/03/03 00:46:09  cheshire
231Additional debugging information in ResolveSimultaneousProbe
232
233Revision 1.913  2009/02/27 03:08:47  cheshire
234<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
235
236Revision 1.912  2009/02/27 02:31:28  cheshire
237Improved "Record not found in list" debugging message
238
239Revision 1.911  2009/02/21 01:42:11  cheshire
240Updated log messages
241
242Revision 1.910  2009/02/19 01:50:53  cheshire
243Converted some LogInfo messages to LogSPS
244
245Revision 1.909  2009/02/14 00:04:59  cheshire
246Left-justify interface names
247
248Revision 1.908  2009/02/13 19:40:07  cheshire
249Improved alignment of LogSPS messages
250
251Revision 1.907  2009/02/13 18:16:05  cheshire
252Fixed some compile warnings
253
254Revision 1.906  2009/02/13 06:10:17  cheshire
255Convert LogOperation messages to LogInfo
256
257Revision 1.905  2009/02/12 20:57:24  cheshire
258Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
259
260Revision 1.904  2009/02/11 02:37:29  cheshire
261m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
262Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
263so that it happens correctly even when we delay re-sleep due to a very short wakeup.
264
265Revision 1.903  2009/02/09 23:34:31  cheshire
266Additional logging for debugging unknown packets
267
268Revision 1.902  2009/02/07 05:57:01  cheshire
269Fixed debugging log message
270
271Revision 1.901  2009/02/07 02:57:31  cheshire
272<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
273
274Revision 1.900  2009/02/02 21:29:24  cheshire
275<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
276If Negative response for our special Microsoft Active Directory "local SOA" check has no
277SOA record in the authority section, assume we should cache the negative result for 24 hours
278
279Revision 1.899  2009/01/31 00:37:50  cheshire
280When marking cache records for deletion in response to a uDNS response,
281make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
282
283Revision 1.898  2009/01/30 23:49:20  cheshire
284Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
285
286Revision 1.897  2009/01/30 22:04:49  cheshire
287Workaround to reduce load on root name servers when caching the SOA record for "."
288
289Revision 1.896  2009/01/30 22:00:05  cheshire
290Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
291
292Revision 1.895  2009/01/30 17:46:39  cheshire
293Improved debugging messages for working out why spurious name conflicts are happening
294
295Revision 1.894  2009/01/30 00:22:09  cheshire
296<rdar://problem/6540743> No announcement after probing & no conflict notice
297
298Revision 1.893  2009/01/29 22:27:03  mcguire
299<rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
300
301Revision 1.892  2009/01/24 01:38:23  cheshire
302Fixed error in logic for targeted queries
303
304Revision 1.891  2009/01/22 02:14:25  cheshire
305<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
306
307Revision 1.890  2009/01/22 00:45:02  cheshire
308Improved SPS debugging log messages; we are eligible to start answering ARP requests
309after we send our first announcement, not after we send our last probe
310
311Revision 1.889  2009/01/21 03:43:56  mcguire
312<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
313
314Revision 1.888  2009/01/20 00:27:43  mcguire
315<rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
316
317Revision 1.887  2009/01/17 05:14:37  cheshire
318Convert SendQueries Probe messages to LogSPS messages
319
320Revision 1.886  2009/01/17 03:43:09  cheshire
321Added SPSLogging switch to facilitate Sleep Proxy Server debugging
322
323Revision 1.885  2009/01/16 22:44:18  cheshire
324<rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
325
326Revision 1.884  2009/01/16 21:43:52  cheshire
327Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
328
329Revision 1.883  2009/01/16 21:11:18  cheshire
330When purging expired Sleep Proxy records, need to check DuplicateRecords list too
331
332Revision 1.882  2009/01/16 19:54:28  cheshire
333Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
334
335Revision 1.881  2009/01/14 01:38:38  mcguire
336<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
337
338Revision 1.880  2009/01/10 01:51:19  cheshire
339q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
340
341Revision 1.879  2009/01/10 01:43:52  cheshire
342Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
343
344Revision 1.878  2009/01/10 01:38:10  cheshire
345Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
346
347Revision 1.877  2009/01/10 01:36:08  cheshire
348Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
349
350Revision 1.876  2009/01/09 22:56:06  cheshire
351Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
352
353Revision 1.875  2009/01/09 22:54:46  cheshire
354When tranferring record from DuplicateRecords list to ResourceRecords list,
355need to copy across state of 'Answered Local-Only-Questions' flag
356
357Revision 1.874  2009/01/07 23:07:24  cheshire
358<rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
359
360Revision 1.873  2008/12/17 00:18:59  mkrochma
361Change some LogMsg to LogOperation before submitting
362
363Revision 1.872  2008/12/12 01:30:40  cheshire
364Update platform-layer BPF filters when we add or remove AddressProxy records
365
366Revision 1.871  2008/12/10 02:25:31  cheshire
367Minor fixes to use of LogClientOperations symbol
368
369Revision 1.870  2008/12/10 02:11:41  cheshire
370ARMv5 compiler doesn't like uncommented stuff after #endif
371
372Revision 1.869  2008/12/05 02:35:24  mcguire
373<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
374
375Revision 1.868  2008/12/04 21:08:51  mcguire
376<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
377
378Revision 1.867  2008/11/26 21:19:36  cheshire
379<rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
380
381Revision 1.866  2008/11/26 20:32:46  cheshire
382<rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
383Update advertised name when Sleep Proxy "intent" metric changes
384
385Revision 1.865  2008/11/26 19:49:25  cheshire
386Record originally-requested port in sr->NATinfo.IntPort
387
388Revision 1.864  2008/11/26 19:02:37  cheshire
389Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
390
391Revision 1.863  2008/11/26 03:59:03  cheshire
392Wait 30 seconds before starting ARP Announcements
393
394Revision 1.862  2008/11/25 23:43:07  cheshire
395<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
396Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
397
398Revision 1.861  2008/11/25 22:46:30  cheshire
399For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
400
401Revision 1.860  2008/11/25 05:07:15  cheshire
402<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
403
404Revision 1.859  2008/11/20 02:07:56  cheshire
405<rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
406
407Revision 1.858  2008/11/20 01:38:36  cheshire
408For consistency with other parts of the code, changed code to only check
409that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
410
411Revision 1.857  2008/11/14 22:55:18  cheshire
412Fixed log messages
413
414Revision 1.856  2008/11/14 21:08:28  cheshire
415Only put owner option in query packet if we have a non-zero MAC address to put
416Only process owner options in received query packets if the MAC address in the option is non-zero
417
418Revision 1.855  2008/11/14 02:29:54  cheshire
419If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
420
421Revision 1.854  2008/11/14 00:00:53  cheshire
422After client machine wakes up, Sleep Proxy machine need to remove any records
423it was temporarily holding as proxy for that client
424
425Revision 1.853  2008/11/13 19:07:30  cheshire
426Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
427
428Revision 1.852  2008/11/12 23:23:11  cheshire
429Before waking a host, check to see if it has an SRV record advertising
430a service on the port in question, and if not, don't bother waking it.
431
432Revision 1.851  2008/11/12 01:54:15  cheshire
433<rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
434It turns out it is beneficial to have the domain on the end, because it allows better name compression
435
436Revision 1.850  2008/11/11 01:56:57  cheshire
437Improved name conflict log messages
438
439Revision 1.849  2008/11/06 23:50:43  cheshire
440Allow plain (non-SYN) ssh data packets to wake sleeping host
441
442Revision 1.848  2008/11/05 02:40:28  mkrochma
443Change mDNS_SetFQDN syslog mesage to debugf
444
445Revision 1.847  2008/11/04 23:06:50  cheshire
446Split RDataBody union definition into RDataBody and RDataBody2, and removed
447SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
448
449Revision 1.846  2008/11/04 22:21:44  cheshire
450Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
451
452Revision 1.845  2008/11/03 23:52:05  cheshire
453Improved ARP debugging messages to differentiate ARP Announcements from Requests
454
455Revision 1.844  2008/10/31 23:43:51  cheshire
456Fixed compile error in Posix build
457
458Revision 1.843  2008/10/31 22:55:04  cheshire
459Initial support for structured SPS names
460
461Revision 1.842  2008/10/30 00:12:07  cheshire
462Fixed spin when PutSPSRec fails to put a record because it's too big to fit
463
464Revision 1.841  2008/10/29 23:23:38  cheshire
465Refined cache size reporting to go in steps of 1000 when number is above 1000
466
467Revision 1.840  2008/10/29 21:34:10  cheshire
468Removed some old debugging messages
469
470Revision 1.839  2008/10/29 21:31:32  cheshire
471Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
472
473Revision 1.838  2008/10/28 18:30:37  cheshire
474Added debugging message in mDNSCoreReceiveRawPacket
475
476Revision 1.837  2008/10/24 23:58:05  cheshire
477Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
478
479Revision 1.836  2008/10/24 23:18:18  cheshire
480If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
481
482Revision 1.835  2008/10/24 23:07:59  cheshire
483Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
484
485Revision 1.834  2008/10/24 23:03:24  cheshire
486Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
487
488Revision 1.833  2008/10/24 23:01:26  cheshire
489To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
490
491Revision 1.832  2008/10/24 22:58:24  cheshire
492For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
493
494Revision 1.831  2008/10/24 22:50:41  cheshire
495When waking SPS client, include interface name in syslog message
496
497Revision 1.830  2008/10/24 20:50:34  cheshire
498Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
499
500Revision 1.829  2008/10/23 23:55:57  cheshire
501Fixed some missing "const" declarations
502
503Revision 1.828  2008/10/23 22:25:56  cheshire
504Renamed field "id" to more descriptive "updateid"
505
506Revision 1.827  2008/10/23 03:06:25  cheshire
507Fixed "Waking host" log message
508
509Revision 1.826  2008/10/22 23:21:30  cheshire
510Make sure we have enough bytes before reading into the transport-level header
511
512Revision 1.825  2008/10/22 22:31:53  cheshire
513Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
514
515Revision 1.824  2008/10/22 20:00:31  cheshire
516If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
517
518Revision 1.823  2008/10/22 19:55:35  cheshire
519Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
520
521Revision 1.822  2008/10/22 01:41:39  cheshire
522Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
523
524Revision 1.821  2008/10/22 01:12:53  cheshire
525Answer ARP Requests for any IP address we're proxying for
526
527Revision 1.820  2008/10/21 01:11:11  cheshire
528Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
529
530Revision 1.819  2008/10/20 22:16:27  cheshire
531Updated comments; increased cache shedding threshold from 3000 to 4000
532
533Revision 1.818  2008/10/16 22:01:54  cheshire
534Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
535
536Revision 1.817  2008/10/16 21:40:49  cheshire
537Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
538
539Revision 1.816  2008/10/15 23:12:36  cheshire
540On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
541
542Revision 1.815  2008/10/15 20:46:38  cheshire
543When transferring records to SPS, include Lease Option
544
545Revision 1.814  2008/10/15 19:51:27  cheshire
546Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
547
548Revision 1.813  2008/10/15 00:09:23  cheshire
549When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
550
551Revision 1.812  2008/10/15 00:01:40  cheshire
552When going to sleep, discover and resolve SPS, and if successful, transfer records to it
553
554Revision 1.811  2008/10/14 23:51:57  cheshire
555Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
556
557Revision 1.810  2008/10/14 21:37:55  cheshire
558Removed unnecessary m->BeSleepProxyServer variable
559
560Revision 1.809  2008/10/10 23:45:48  cheshire
561For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
562not a wide-area unicast hostname
563
564Revision 1.808  2008/10/09 18:59:19  cheshire
565Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
566
567Revision 1.807  2008/10/07 15:56:58  cheshire
568Fixed "unused variable" warnings in non-debug builds
569
570Revision 1.806  2008/10/04 00:53:37  cheshire
571On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
572
573Revision 1.805  2008/10/03 18:17:28  cheshire
574<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
575Update advertised Sleep Proxy Server name if user changes computer name
576
577Revision 1.804  2008/10/03 01:26:06  mcguire
578<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
579Put back Duplicate Record check
580
581Revision 1.803  2008/10/02 23:38:56  mcguire
582<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
583
584Revision 1.802  2008/10/02 23:13:48  cheshire
585<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
586Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
587
588Revision 1.801  2008/10/02 22:51:04  cheshire
589<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
590Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
591
592Revision 1.800  2008/10/02 22:13:15  cheshire
593<rdar://problem/6230680> 100ms delay on shutdown
594Additional refinement: Also need to clear m->SuppressSending
595
596Revision 1.799  2008/09/29 20:12:37  cheshire
597Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
598
599Revision 1.798  2008/09/26 19:53:14  cheshire
600Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
601
602Revision 1.797  2008/09/25 20:40:59  cheshire
603<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
604In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
605
606Revision 1.796  2008/09/25 20:17:10  cheshire
607<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
608Added defensive code to make sure *all* records of a ServiceRecordSet have
609completed deregistering before we pass on the mStatus_MemFree message
610
611Revision 1.795  2008/09/25 00:30:11  cheshire
612<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
613
614Revision 1.794  2008/09/24 23:48:05  cheshire
615Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
616it only needs to access the embedded SRV member of the set
617
618Revision 1.793  2008/09/23 04:11:53  cheshire
619<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
620
621Revision 1.792  2008/09/23 02:30:07  cheshire
622Get rid of PutResourceRecordCappedTTL()
623
624Revision 1.791  2008/09/20 00:34:21  mcguire
625<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
626
627Revision 1.790  2008/09/18 22:46:34  cheshire
628<rdar://problem/6230680> 100ms delay on shutdown
629
630Revision 1.789  2008/09/18 06:15:06  mkrochma
631<rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
632
633Revision 1.788  2008/09/16 21:11:41  cheshire
634<rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
635
636Revision 1.787  2008/09/05 22:53:24  cheshire
637Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
638
639Revision 1.786  2008/09/05 22:23:28  cheshire
640Moved initialization of "question->LocalSocket" to more logical place
641
642Revision 1.785  2008/08/14 19:20:55  cheshire
643<rdar://problem/6143846> Negative responses over TCP incorrectly rejected
644
645Revision 1.784  2008/08/13 00:47:53  mcguire
646Handle failures when packet logging
647
648Revision 1.783  2008/07/25 07:09:51  mcguire
649<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
650
651Revision 1.782  2008/07/24 20:23:03  cheshire
652<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
653
654Revision 1.781  2008/07/18 21:37:35  mcguire
655<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
656
657Revision 1.780  2008/07/18 02:24:36  cheshire
658<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
659Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
660we're still on our first or second query after an interface registration or wake from sleep).
661
662Revision 1.779  2008/07/18 01:05:23  cheshire
663<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
664
665Revision 1.778  2008/06/26 17:24:11  mkrochma
666<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
667
668Revision 1.777  2008/06/19 01:20:48  mcguire
669<rdar://problem/4206534> Use all configured DNS servers
670
671Revision 1.776  2008/04/17 20:14:14  cheshire
672<rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
673
674Revision 1.775  2008/03/26 01:53:34  mcguire
675<rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
676
677Revision 1.774  2008/03/17 17:46:08  mcguire
678When activating an LLQ, reset all the important state and destroy any tcp connection,
679so that everything will be restarted as if the question had just been asked.
680Also reset servPort, so that the SOA query will be re-issued.
681
682Revision 1.773  2008/03/14 22:52:36  mcguire
683<rdar://problem/5321824> write status to the DS
684Update status when any unicast LLQ is started
685
686Revision 1.772  2008/03/06 02:48:34  mcguire
687<rdar://problem/5321824> write status to the DS
688
689Revision 1.771  2008/02/26 22:04:44  cheshire
690<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
691Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
692question while it's still in our 'm->NewQuestions' section of the list
693
694Revision 1.770  2008/02/22 23:09:02  cheshire
695<rdar://problem/5338420> BTMM: Not processing additional records
696Refinements:
6971. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
6982. Once we decide a record is acceptable, we can break out of the loop
699
700Revision 1.769  2008/02/22 00:00:19  cheshire
701<rdar://problem/5338420> BTMM: Not processing additional records
702
703Revision 1.768  2008/02/19 23:26:50  cheshire
704<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
705
706Revision 1.767  2007/12/22 02:25:29  cheshire
707<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
708
709Revision 1.766  2007/12/15 01:12:27  cheshire
710<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
711
712Revision 1.765  2007/12/15 00:18:51  cheshire
713Renamed question->origLease to question->ReqLease
714
715Revision 1.764  2007/12/14 00:49:53  cheshire
716Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
717the CurrentServiceRecordSet mechanism to guard against services being deleted,
718just like the record deregistration loop uses m->CurrentRecord.
719
720Revision 1.763  2007/12/13 20:20:17  cheshire
721Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
722SameRData from functions to macros, which allows the code to be inlined (the compiler can't
723inline a function defined in a different compilation unit) and therefore optimized better.
724
725Revision 1.762  2007/12/13 00:13:03  cheshire
726Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
727
728Revision 1.761  2007/12/13 00:03:31  cheshire
729Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
730
731Revision 1.760  2007/12/08 00:36:19  cheshire
732<rdar://problem/5636422> Updating TXT records is too slow
733Remove unnecessary delays on announcing record updates, and on processing them on reception
734
735Revision 1.759  2007/12/07 22:41:29  cheshire
736<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
737Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
738
739Revision 1.758  2007/12/07 00:45:57  cheshire
740<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
741
742Revision 1.757  2007/12/06 00:22:27  mcguire
743<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
744
745Revision 1.756  2007/12/05 01:52:30  cheshire
746<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
747Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
748
749Revision 1.755  2007/12/03 23:36:45  cheshire
750<rdar://problem/5623140> mDNSResponder unicast DNS improvements
751Need to check GetServerForName() result is non-null before dereferencing pointer
752
753Revision 1.754  2007/12/01 01:21:27  jgraessley
754<rdar://problem/5623140> mDNSResponder unicast DNS improvements
755
756Revision 1.753  2007/12/01 00:44:15  cheshire
757Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
758
759Revision 1.752  2007/11/14 01:10:51  cheshire
760Fixed LogOperation() message wording
761
762Revision 1.751  2007/10/30 23:49:41  cheshire
763<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
764LLQ state was not being transferred properly between duplicate questions
765
766Revision 1.750  2007/10/29 23:58:52  cheshire
767<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
768Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
769
770Revision 1.749  2007/10/29 21:28:36  cheshire
771Change "Correcting TTL" log message to LogOperation to suppress it in customer build
772
773Revision 1.748  2007/10/29 20:02:50  cheshire
774<rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
775
776Revision 1.747  2007/10/26 22:53:50  cheshire
777Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
778instead of replicating the logic in both places
779
780Revision 1.746  2007/10/25 22:48:50  cheshire
781Added LogOperation message saying when we restart GetZoneData for record and service registrations
782
783Revision 1.745  2007/10/25 20:48:47  cheshire
784For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
785
786Revision 1.744  2007/10/25 20:06:14  cheshire
787Don't try to do SOA queries using private DNS (TLS over TCP) queries
788
789Revision 1.743  2007/10/25 00:12:46  cheshire
790<rdar://problem/5496734> BTMM: Need to retry registrations after failures
791Retrigger service registrations whenever a new network interface is added
792
793Revision 1.742  2007/10/24 22:40:06  cheshire
794Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
795Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
796
797Revision 1.741  2007/10/24 00:50:29  cheshire
798<rdar://problem/5496734> BTMM: Need to retry registrations after failures
799Retrigger record registrations whenever a new network interface is added
800
801Revision 1.740  2007/10/23 00:38:03  cheshire
802When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
803or code will spin sending the same cache expiration query repeatedly
804
805Revision 1.739  2007/10/22 23:46:41  cheshire
806<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
807Need to clear question->nta pointer after calling CancelGetZoneData()
808
809Revision 1.738  2007/10/19 22:08:49  cheshire
810<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
811Additional fixes and refinements
812
813Revision 1.737  2007/10/18 23:06:42  cheshire
814<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
815Additional fixes and refinements
816
817Revision 1.736  2007/10/18 20:23:17  cheshire
818Moved SuspendLLQs into mDNS.c, since it's only called from one place
819
820Revision 1.735  2007/10/18 00:12:34  cheshire
821Fixed "unused variable" compiler warning
822
823Revision 1.734  2007/10/17 22:49:54  cheshire
824<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
825
826Revision 1.733  2007/10/17 22:37:23  cheshire
827<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
828
829Revision 1.732  2007/10/17 21:53:51  cheshire
830Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
831
832Revision 1.731  2007/10/17 18:37:50  cheshire
833<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
834Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
835
836Revision 1.730  2007/10/16 21:16:07  cheshire
837<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
838
839Revision 1.729  2007/10/05 17:56:10  cheshire
840Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
841
842Revision 1.728  2007/10/04 23:18:14  cheshire
843<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
844
845Revision 1.727  2007/10/04 22:51:57  cheshire
846Added debugging LogOperation message to show when we're sending cache expiration queries
847
848Revision 1.726  2007/10/03 00:14:24  cheshire
849Removed write to null to generate stack trace for SetNextQueryTime locking failure
850
851Revision 1.725  2007/10/02 21:11:08  cheshire
852<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
853
854Revision 1.724  2007/10/02 20:10:23  cheshire
855Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
856
857Revision 1.723  2007/10/02 19:56:54  cheshire
858<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
859
860Revision 1.722  2007/10/01 22:59:46  cheshire
861<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
862Need to shut down NATTraversals on exit
863
864Revision 1.721  2007/10/01 18:42:07  cheshire
865To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
866
867Revision 1.720  2007/09/29 20:40:19  cheshire
868<rdar://problem/5513378> Crash in ReissueBlockedQuestions
869
870Revision 1.719  2007/09/27 22:23:56  cheshire
871<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
872Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
873
874Revision 1.718  2007/09/27 22:02:33  cheshire
875<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
876
877Revision 1.717  2007/09/27 21:21:39  cheshire
878Export CompleteDeregistration so it's callable from other files
879
880Revision 1.716  2007/09/27 02:12:21  cheshire
881Updated GrantCacheExtensions degugging message to show new record lifetime
882
883Revision 1.715  2007/09/27 01:20:06  cheshire
884<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
885
886Revision 1.714  2007/09/27 00:37:01  cheshire
887<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
888
889Revision 1.713  2007/09/27 00:25:39  cheshire
890Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
891<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
892
893Revision 1.712  2007/09/26 23:16:58  cheshire
894<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
895
896Revision 1.711  2007/09/26 22:06:02  cheshire
897<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
898
899Revision 1.710  2007/09/26 00:49:46  cheshire
900Improve packet logging to show sent and received packets,
901transport protocol (UDP/TCP/TLS) and source/destination address:port
902
903Revision 1.709  2007/09/21 21:12:36  cheshire
904<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
905
906Revision 1.708  2007/09/20 23:13:37  cheshire
907<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
908Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
909
910Revision 1.707  2007/09/20 02:29:37  cheshire
911<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
912
913Revision 1.706  2007/09/20 01:13:19  cheshire
914Export CacheGroupForName so it's callable from other files
915
916Revision 1.705  2007/09/20 01:12:06  cheshire
917Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
918
919Revision 1.704  2007/09/19 22:47:25  cheshire
920<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
921
922Revision 1.703  2007/09/14 01:46:59  cheshire
923Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
924
925Revision 1.702  2007/09/13 22:06:46  cheshire
926<rdar://problem/5480643> Tully's Free WiFi: DNS fails
927Need to accept DNS responses where the query ID field matches, even if the source address does not
928
929Revision 1.701  2007/09/12 23:22:32  cheshire
930<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
931
932Revision 1.700  2007/09/12 23:03:08  cheshire
933<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
934
935Revision 1.699  2007/09/12 22:19:28  cheshire
936<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
937
938Revision 1.698  2007/09/12 22:13:27  cheshire
939Remove DynDNSHostNames cleanly on shutdown
940
941Revision 1.697  2007/09/12 01:44:47  cheshire
942<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
943
944Revision 1.696  2007/09/12 01:26:08  cheshire
945Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
946
947Revision 1.695  2007/09/11 19:19:16  cheshire
948Correct capitalization of "uPNP" to "UPnP"
949
950Revision 1.694  2007/09/10 22:06:51  cheshire
951Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
952
953Revision 1.693  2007/09/07 22:24:36  vazquez
954<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
955
956Revision 1.692  2007/09/07 00:12:09  cheshire
957<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
958
959Revision 1.691  2007/09/05 22:25:01  vazquez
960<rdar://problem/5400521> update_record mDNSResponder leak
961
962Revision 1.690  2007/09/05 21:48:01  cheshire
963<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
964Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
965to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
966otherwise those records will expire and vanish from the cache.
967
968Revision 1.689  2007/09/05 02:29:06  cheshire
969<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
970Additional fixes to code implementing "NoAnswer" logic
971
972Revision 1.688  2007/08/31 22:56:39  cheshire
973<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
974
975Revision 1.687  2007/08/31 19:53:14  cheshire
976<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
977If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
978
979Revision 1.686  2007/08/30 00:01:56  cheshire
980Added comment about SetTargetToHostName()
981
982Revision 1.685  2007/08/29 01:19:24  cheshire
983<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
984Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
985
986Revision 1.684  2007/08/28 23:58:42  cheshire
987Rename HostTarget -> AutoTarget
988
989Revision 1.683  2007/08/28 23:53:21  cheshire
990Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
991
992Revision 1.682  2007/08/27 20:28:19  cheshire
993Improve "suspect uDNS response" log message
994
995Revision 1.681  2007/08/24 23:37:23  cheshire
996Added debugging message to show when ExtraResourceRecord callback gets invoked
997
998Revision 1.680  2007/08/24 00:15:19  cheshire
999Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
1000
1001Revision 1.679  2007/08/23 21:47:09  vazquez
1002<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
1003make sure we clean up port mappings on base stations by sending a lease value of 0,
1004and only send NAT-PMP packets on private networks; also save some memory by
1005not using packet structs in NATTraversals.
1006
1007Revision 1.678  2007/08/01 16:09:13  cheshire
1008Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
1009
1010Revision 1.677  2007/08/01 01:58:24  cheshire
1011Added RecordType sanity check in mDNS_Register_internal
1012
1013Revision 1.676  2007/08/01 00:04:13  cheshire
1014<rdar://problem/5261696> Crash in tcpKQSocketCallback
1015Half-open TCP connections were not being cancelled properly
1016
1017Revision 1.675  2007/07/31 02:28:35  vazquez
1018<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
1019
1020Revision 1.674  2007/07/31 01:57:23  cheshire
1021Adding code to respect TTL received in uDNS responses turned out to
1022expose other problems; backing out change for now.
1023
1024Revision 1.673  2007/07/30 23:31:26  cheshire
1025Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
1026
1027Revision 1.672  2007/07/28 01:25:56  cheshire
1028<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
1029
1030Revision 1.671  2007/07/27 22:32:54  cheshire
1031When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
1032of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
1033
1034Revision 1.670  2007/07/27 20:54:43  cheshire
1035Fixed code to respect real record TTL received in uDNS responses
1036
1037Revision 1.669  2007/07/27 20:09:32  cheshire
1038Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
1039
1040Revision 1.668  2007/07/27 19:58:47  cheshire
1041Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
1042
1043Revision 1.667  2007/07/27 19:52:10  cheshire
1044Don't increment m->rrcache_active for no-cache add events
1045
1046Revision 1.666  2007/07/27 19:30:39  cheshire
1047Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
1048to properly reflect tri-state nature of the possible responses
1049
1050Revision 1.665  2007/07/27 18:44:01  cheshire
1051Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
1052
1053Revision 1.664  2007/07/27 18:38:56  cheshire
1054Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
1055
1056Revision 1.663  2007/07/25 03:05:02  vazquez
1057Fixes for:
1058<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
1059<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
1060and a myriad of other security problems
1061
1062Revision 1.662  2007/07/24 20:22:46  cheshire
1063Make sure all fields of main mDNS object are initialized correctly
1064
1065Revision 1.661  2007/07/21 00:54:45  cheshire
1066<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
1067
1068Revision 1.660  2007/07/20 20:00:45  cheshire
1069"Legacy Browse" is better called "Automatic Browse"
1070
1071Revision 1.659  2007/07/20 00:54:18  cheshire
1072<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
1073
1074Revision 1.658  2007/07/18 02:28:57  cheshire
1075Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
1076
1077Revision 1.657  2007/07/18 00:57:10  cheshire
1078<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1079Only need to call AddNewClientTunnel() for IPv6 addresses
1080
1081Revision 1.656  2007/07/16 23:54:48  cheshire
1082<rdar://problem/5338850> Crash when removing or changing DNS keys
1083
1084Revision 1.655  2007/07/16 20:11:37  vazquez
1085<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
1086Init LNT stuff and handle SSDP packets
1087
1088Revision 1.654  2007/07/12 23:30:23  cheshire
1089Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
1090
1091Revision 1.653  2007/07/12 02:51:27  cheshire
1092<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
1093
1094Revision 1.652  2007/07/11 23:43:42  cheshire
1095Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
1096
1097Revision 1.651  2007/07/11 22:44:40  cheshire
1098<rdar://problem/5328801> SIGHUP should purge the cache
1099
1100Revision 1.650  2007/07/11 21:34:09  cheshire
1101<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
1102Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
1103
1104Revision 1.649  2007/07/11 02:52:52  cheshire
1105<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
1106In uDNS_RegisterService, set HostTarget for AutoTunnel services
1107
1108Revision 1.648  2007/07/09 23:48:12  cheshire
1109Add parentheses around bitwise operation for clarity
1110
1111Revision 1.647  2007/07/06 21:17:55  cheshire
1112Initialize m->retryGetAddr to timenow + 0x78000000;
1113
1114Revision 1.646  2007/07/06 18:55:49  cheshire
1115Initialize m->NextScheduledNATOp
1116
1117Revision 1.645  2007/06/29 22:55:54  cheshire
1118Move declaration of DNSServer *s; Fixed incomplete comment.
1119
1120Revision 1.644  2007/06/29 00:07:29  vazquez
1121<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
1122
1123Revision 1.643  2007/06/20 01:10:12  cheshire
1124<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
1125
1126Revision 1.642  2007/06/15 21:54:50  cheshire
1127<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
1128
1129Revision 1.641  2007/05/25 00:30:24  cheshire
1130When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
1131status matches. This is particularly important when doing a private query for an SOA record,
1132which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
1133If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
1134
1135Revision 1.640  2007/05/25 00:25:44  cheshire
1136<rdar://problem/5227737> Need to enhance putRData to output all current known types
1137
1138Revision 1.639  2007/05/23 00:51:33  cheshire
1139Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
1140each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
1141days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
1142
1143Revision 1.638  2007/05/23 00:43:16  cheshire
1144If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
1145
1146Revision 1.637  2007/05/14 23:53:00  cheshire
1147Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
1148
1149Revision 1.636  2007/05/10 23:27:15  cheshire
1150Update mDNS_Deregister_internal debugging messages
1151
1152Revision 1.635  2007/05/07 20:43:45  cheshire
1153<rdar://problem/4241419> Reduce the number of queries and announcements
1154
1155Revision 1.634  2007/05/04 22:09:08  cheshire
1156Only do "restarting exponential backoff sequence" for mDNS questions
1157In mDNS_RegisterInterface, only retrigger mDNS questions
1158In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
1159
1160Revision 1.633  2007/05/04 21:45:12  cheshire
1161Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
1162
1163Revision 1.632  2007/05/04 20:20:50  cheshire
1164<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1165Need to set srs->nta = mDNSNULL; when regState_NoTarget
1166
1167Revision 1.631  2007/05/04 00:39:42  cheshire
1168<rdar://problem/4410011> Eliminate looping SOA lookups
1169When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
1170each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
1171
1172Revision 1.630  2007/05/03 22:40:38  cheshire
1173<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
1174
1175Revision 1.629  2007/05/03 00:15:51  cheshire
1176<rdar://problem/4410011> Eliminate looping SOA lookups
1177
1178Revision 1.628  2007/05/02 22:21:33  cheshire
1179<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
1180
1181Revision 1.627  2007/04/30 19:29:13  cheshire
1182Fix display of port number in "Updating DNS Server" message
1183
1184Revision 1.626  2007/04/30 04:21:13  cheshire
1185Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
1186
1187Revision 1.625  2007/04/28 01:34:21  cheshire
1188Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
1189(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
1190
1191Revision 1.624  2007/04/27 21:04:30  cheshire
1192On network configuration change, need to call uDNS_RegisterSearchDomains
1193
1194Revision 1.623  2007/04/27 19:28:01  cheshire
1195Any code that calls StartGetZoneData needs to keep a handle to the structure, so
1196it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
1197-- it would start a query and then quickly cancel it, and then when
1198StartGetZoneData completed, it had a dangling pointer and crashed.)
1199
1200Revision 1.622  2007/04/26 16:09:22  cheshire
1201mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
1202
1203Revision 1.621  2007/04/26 15:43:22  cheshire
1204Make sure DNSServer *s is non-null before using value in LogOperation
1205
1206Revision 1.620  2007/04/26 13:11:05  cheshire
1207Fixed crash when logging out of VPN
1208
1209Revision 1.619  2007/04/26 00:35:15  cheshire
1210<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
1211Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
1212inside the firewall may give answers where a public one gives none, and vice versa.)
1213
1214Revision 1.618  2007/04/25 19:26:01  cheshire
1215m->NextScheduledQuery was getting set too early in SendQueries()
1216Improved "SendQueries didn't send all its queries" debugging message
1217
1218Revision 1.617  2007/04/25 17:48:22  cheshire
1219Update debugging message
1220
1221Revision 1.616  2007/04/25 16:38:32  cheshire
1222If negative cache entry already exists, reactivate it instead of creating a new one
1223
1224Revision 1.615  2007/04/25 02:14:38  cheshire
1225<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
1226Additional fixes to make LLQs work properly
1227
1228Revision 1.614  2007/04/23 21:52:45  cheshire
1229<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
1230
1231Revision 1.613  2007/04/23 04:58:20  cheshire
1232<rdar://problem/5072548> Crash when setting extremely large TXT records
1233
1234Revision 1.612  2007/04/22 20:39:38  cheshire
1235<rdar://problem/4633194> Add 20 to 120ms random delay to browses
1236
1237Revision 1.611  2007/04/22 18:16:29  cheshire
1238Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
1239
1240Revision 1.610  2007/04/22 06:02:02  cheshire
1241<rdar://problem/4615977> Query should immediately return failure when no server
1242
1243Revision 1.609  2007/04/20 21:17:24  cheshire
1244For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
1245
1246Revision 1.608  2007/04/20 19:45:31  cheshire
1247In LogClientOperations mode, dump out unknown DNS packets in their entirety
1248
1249Revision 1.607  2007/04/19 23:56:25  cheshire
1250Don't do cache-flush processing for LLQ answers
1251
1252Revision 1.606  2007/04/19 22:50:53  cheshire
1253<rdar://problem/4246187> Identical client queries should reference a single shared core query
1254
1255Revision 1.605  2007/04/19 20:06:41  cheshire
1256Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
1257
1258Revision 1.604  2007/04/19 18:03:04  cheshire
1259Add "const" declaration
1260
1261Revision 1.603  2007/04/06 21:00:25  cheshire
1262Fix log message typo
1263
1264Revision 1.602  2007/04/05 22:55:35  cheshire
1265<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
1266
1267Revision 1.601  2007/04/04 21:48:52  cheshire
1268<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
1269
1270Revision 1.600  2007/04/04 01:31:33  cheshire
1271Improve debugging message
1272
1273Revision 1.599  2007/04/04 00:03:26  cheshire
1274<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
1275
1276Revision 1.598  2007/04/03 19:43:16  cheshire
1277Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
1278
1279Revision 1.597  2007/03/31 00:32:32  cheshire
1280After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
1281
1282Revision 1.596  2007/03/28 20:59:26  cheshire
1283<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
1284
1285Revision 1.595  2007/03/26 23:48:16  cheshire
1286<rdar://problem/4848295> Advertise model information via Bonjour
1287Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
1288
1289Revision 1.594  2007/03/26 23:05:05  cheshire
1290<rdar://problem/5089257> Don't cache TSIG records
1291
1292Revision 1.593  2007/03/23 17:40:08  cheshire
1293<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
1294
1295Revision 1.592  2007/03/22 18:31:48  cheshire
1296Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
1297
1298Revision 1.591  2007/03/22 00:49:19  cheshire
1299<rdar://problem/4848295> Advertise model information via Bonjour
1300
1301Revision 1.590  2007/03/21 23:05:59  cheshire
1302Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
1303
1304Revision 1.589  2007/03/20 15:37:19  cheshire
1305Delete unnecessary log message
1306
1307Revision 1.588  2007/03/20 00:24:44  cheshire
1308<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
1309
1310Revision 1.587  2007/03/16 22:10:56  cheshire
1311<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
1312
1313Revision 1.586  2007/03/10 03:26:44  cheshire
1314<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1315
1316Revision 1.585  2007/03/10 02:02:58  cheshire
1317<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
1318Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
1319
1320Revision 1.584  2007/02/28 01:51:27  cheshire
1321Added comment about reverse-order IP address
1322
1323Revision 1.583  2007/01/27 03:19:33  cheshire
1324Need to initialize question->sock
1325
1326Revision 1.582  2007/01/25 00:40:16  cheshire
1327Unified CNAME-following functionality into cache management code (which means CNAME-following
1328should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
1329
1330Revision 1.581  2007/01/23 02:56:11  cheshire
1331Store negative results in the cache, instead of generating them out of pktResponseHndlr()
1332
1333Revision 1.580  2007/01/19 21:17:33  cheshire
1334StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
1335
1336Revision 1.579  2007/01/19 18:39:10  cheshire
1337Fix a bunch of parameters that should have been declared "const"
1338
1339Revision 1.578  2007/01/10 22:51:57  cheshire
1340<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
1341
1342Revision 1.577  2007/01/10 02:05:21  cheshire
1343Delay uDNS_SetupDNSConfig() until *after* the platform layer
1344has set up the interface list and security credentials
1345
1346Revision 1.576  2007/01/09 02:40:57  cheshire
1347uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
1348moved it to mDNS_Init() in mDNS.c (core code)
1349
1350Revision 1.575  2007/01/09 00:17:25  cheshire
1351Improve "ERROR m->CurrentRecord already set" debugging messages
1352
1353Revision 1.574  2007/01/05 08:30:41  cheshire
1354Trim excessive "Log" checkin history from before 2006
1355(checkin history still available via "cvs log ..." of course)
1356
1357Revision 1.573  2007/01/05 06:34:03  cheshire
1358Improve "ERROR m->CurrentQuestion already set" debugging messages
1359
1360Revision 1.572  2007/01/04 23:11:11  cheshire
1361<rdar://problem/4720673> uDNS: Need to start caching unicast records
1362When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
1363
1364Revision 1.571  2007/01/04 21:45:20  cheshire
1365Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
1366to do additional lock sanity checking around callback invocations
1367
1368Revision 1.570  2007/01/04 20:57:47  cheshire
1369Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
1370
1371Revision 1.569  2007/01/04 20:27:27  cheshire
1372Change a LogMsg() to debugf()
1373
1374Revision 1.568  2007/01/04 02:39:53  cheshire
1375<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
1376
1377Revision 1.567  2006/12/21 00:01:37  cheshire
1378Tidy up code alignment
1379
1380Revision 1.566  2006/12/20 04:07:34  cheshire
1381Remove uDNS_info substructure from AuthRecord_struct
1382
1383Revision 1.565  2006/12/19 22:49:23  cheshire
1384Remove uDNS_info substructure from ServiceRecordSet_struct
1385
1386Revision 1.564  2006/12/19 02:38:20  cheshire
1387Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
1388
1389Revision 1.563  2006/12/19 02:18:48  cheshire
1390Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
1391
1392Revision 1.562  2006/12/16 01:58:31  cheshire
1393<rdar://problem/4720673> uDNS: Need to start caching unicast records
1394
1395Revision 1.561  2006/12/01 07:38:53  herscher
1396Only perform cache workaround fix if query is wide-area
1397
1398Revision 1.560  2006/11/30 23:07:56  herscher
1399<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
1400
1401Revision 1.559  2006/11/27 08:20:57  cheshire
1402Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
1403
1404Revision 1.558  2006/11/10 07:44:03  herscher
1405<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
1406
1407Revision 1.557  2006/11/10 01:12:51  cheshire
1408<rdar://problem/4829718> Incorrect TTL corrections
1409
1410Revision 1.556  2006/11/10 00:54:14  cheshire
1411<rdar://problem/4816598> Changing case of Computer Name doesn't work
1412
1413Revision 1.555  2006/10/30 20:03:37  cheshire
1414<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
1415
1416Revision 1.554  2006/10/20 05:35:04  herscher
1417<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
1418
1419Revision 1.553  2006/10/05 03:42:43  herscher
1420Remove embedded uDNS_info struct in DNSQuestion_struct
1421
1422Revision 1.552  2006/09/15 21:20:15  cheshire
1423Remove uDNS_info substructure from mDNS_struct
1424
1425Revision 1.551  2006/08/14 23:24:22  cheshire
1426Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
1427
1428Revision 1.550  2006/07/27 17:58:34  cheshire
1429Improved text of "SendQueries didn't send all its queries; will try again" debugging message
1430
1431Revision 1.549  2006/07/20 22:07:31  mkrochma
1432<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
1433More fixes for uninitialized variables
1434
1435Revision 1.548  2006/07/20 19:30:19  mkrochma
1436<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
1437
1438Revision 1.547  2006/07/15 02:31:30  cheshire
1439<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
1440
1441Revision 1.546  2006/07/07 01:09:09  cheshire
1442<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
1443Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
1444
1445Revision 1.545  2006/07/05 23:10:30  cheshire
1446<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
1447Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
1448
1449Revision 1.544  2006/06/29 07:42:14  cheshire
1450<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
1451
1452Revision 1.543  2006/06/29 01:38:43  cheshire
1453<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
1454
1455Revision 1.542  2006/06/27 23:40:29  cheshire
1456Fix typo in comment: mis-spelled "compile"
1457
1458Revision 1.541  2006/06/27 19:46:24  cheshire
1459Updated comments and debugging messages
1460
1461Revision 1.540  2006/06/15 21:35:16  cheshire
1462Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
1463from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
1464
1465Revision 1.539  2006/06/08 23:45:46  cheshire
1466Change SimultaneousProbe messages from debugf() to LogOperation()
1467
1468Revision 1.538  2006/03/19 17:13:06  cheshire
1469<rdar://problem/4483117> Need faster purging of stale records
1470Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
1471and reconfirm whole chain of antecedents ot once
1472
1473Revision 1.537  2006/03/19 02:00:07  cheshire
1474<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
1475
1476Revision 1.536  2006/03/08 23:29:53  cheshire
1477<rdar://problem/4468716> Improve "Service Renamed" log message
1478
1479Revision 1.535  2006/03/02 20:41:17  cheshire
1480<rdar://problem/4111464> After record update, old record sometimes remains in cache
1481Minor code tidying and comments to reduce the risk of similar programming errors in future
1482
1483Revision 1.534  2006/03/02 03:25:46  cheshire
1484<rdar://problem/4111464> After record update, old record sometimes remains in cache
1485Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
1486
1487Revision 1.533  2006/02/26 00:54:41  cheshire
1488Fixes to avoid code generation warning/error on FreeBSD 7
1489
1490*/
1491
1492#include "DNSCommon.h"                  // Defines general DNS untility routines
1493#include "uDNS.h"						// Defines entry points into unicast-specific routines
1494
1495// Disable certain benign warnings with Microsoft compilers
1496#if(defined(_MSC_VER))
1497	// Disable "conditional expression is constant" warning for debug macros.
1498	// Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1499	// If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1500	#pragma warning(disable:4127)
1501
1502	// Disable "assignment within conditional expression".
1503	// Other compilers understand the convention that if you place the assignment expression within an extra pair
1504	// of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1505	// The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1506	// to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1507	#pragma warning(disable:4706)
1508#endif
1509
1510// Forward declarations
1511mDNSlocal void BeginSleepProcessing(mDNS *const m);
1512mDNSlocal void RetrySPSRegistrations(mDNS *const m);
1513
1514// ***************************************************************************
1515#if COMPILER_LIKES_PRAGMA_MARK
1516#pragma mark - Program Constants
1517#endif
1518
1519#define NO_HINFO 1
1520
1521mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
1522
1523// Any records bigger than this are considered 'large' records
1524#define SmallRecordLimit 1024
1525
1526#define kMaxUpdateCredits 10
1527#define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1528
1529mDNSexport const char *const mDNS_DomainTypeNames[] =
1530	{
1531	 "b._dns-sd._udp.",		// Browse
1532	"db._dns-sd._udp.",		// Default Browse
1533	"lb._dns-sd._udp.",		// Automatic Browse
1534	 "r._dns-sd._udp.",		// Registration
1535	"dr._dns-sd._udp."		// Default Registration
1536	};
1537
1538#ifdef UNICAST_DISABLED
1539#define uDNS_IsActiveQuery(q, u) mDNSfalse
1540#endif
1541
1542// ***************************************************************************
1543#if COMPILER_LIKES_PRAGMA_MARK
1544#pragma mark -
1545#pragma mark - General Utility Functions
1546#endif
1547
1548#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
1549#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
1550
1551mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
1552	{
1553	if (m->mDNS_busy != m->mDNS_reentrancy+1)
1554		LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
1555
1556#if ForceAlerts
1557	if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0;
1558#endif
1559
1560	if (ActiveQuestion(q))
1561		{
1562		mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
1563
1564		// Don't allow sendtime to be earlier than SuppressStdPort53Queries
1565		if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
1566			sendtime = m->SuppressStdPort53Queries;
1567
1568		if (m->NextScheduledQuery - sendtime > 0)
1569			m->NextScheduledQuery = sendtime;
1570		}
1571	}
1572
1573mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
1574	{
1575	CacheGroup *cg;
1576	for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
1577		if (cg->namehash == namehash && SameDomainName(cg->name, name))
1578			break;
1579	return(cg);
1580	}
1581
1582mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
1583	{
1584	return(CacheGroupForName(m, slot, rr->namehash, rr->name));
1585	}
1586
1587mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
1588	{
1589	NetworkInterfaceInfo *intf;
1590
1591	if (addr->type == mDNSAddrType_IPv4)
1592		{
1593		// Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
1594		if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
1595		for (intf = m->HostInterfaces; intf; intf = intf->next)
1596			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
1597				if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
1598					return(mDNStrue);
1599		}
1600
1601	if (addr->type == mDNSAddrType_IPv6)
1602		{
1603		if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
1604		for (intf = m->HostInterfaces; intf; intf = intf->next)
1605			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
1606				if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
1607					(((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
1608					(((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
1609					(((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
1610						return(mDNStrue);
1611		}
1612
1613	return(mDNSfalse);
1614	}
1615
1616mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
1617	{
1618	NetworkInterfaceInfo *intf = m->HostInterfaces;
1619	while (intf && intf->InterfaceID != InterfaceID) intf = intf->next;
1620	return(intf);
1621	}
1622
1623mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID)
1624	{
1625	NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
1626	return(intf ? intf->ifname : "<NULL InterfaceID>");
1627	}
1628
1629// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1630// Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
1631mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
1632	{
1633	// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1634	if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
1635	mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
1636	if (q->QuestionCallback && !q->NoAnswer)
1637		{
1638		q->CurrentAnswers += AddRecord ? 1 : -1;
1639		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
1640		}
1641	mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
1642	}
1643
1644// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
1645// all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) delivering answers to each,
1646// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1647// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1648// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1649mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
1650	{
1651	if (m->CurrentQuestion)
1652		LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
1653
1654	m->CurrentQuestion = m->LocalOnlyQuestions;
1655	while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
1656		{
1657		DNSQuestion *q = m->CurrentQuestion;
1658		m->CurrentQuestion = q->next;
1659		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1660			AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord);			// MUST NOT dereference q again
1661		}
1662
1663	// If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1664	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
1665		{
1666		m->CurrentQuestion = m->Questions;
1667		while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
1668			{
1669			DNSQuestion *q = m->CurrentQuestion;
1670			m->CurrentQuestion = q->next;
1671			if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1672				AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord);		// MUST NOT dereference q again
1673			}
1674		}
1675
1676	m->CurrentQuestion = mDNSNULL;
1677	}
1678
1679// ***************************************************************************
1680#if COMPILER_LIKES_PRAGMA_MARK
1681#pragma mark -
1682#pragma mark - Resource Record Utility Functions
1683#endif
1684
1685#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1686
1687#define ResourceRecordIsValidAnswer(RR) ( ((RR)->             resrec.RecordType & kDNSRecordTypeActiveMask)  && \
1688		((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1689		((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1690		((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask))  )
1691
1692#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1693	(ResourceRecordIsValidAnswer(RR) && \
1694	((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1695
1696#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1697#define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1698
1699#define InitialAnnounceCount ((mDNSu8)8)
1700
1701// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1702// This means that because the announce interval is doubled after sending the first packet, the first
1703// observed on-the-wire inter-packet interval between announcements is actually one second.
1704// The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1705#define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1706#define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1707#define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1708
1709#define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
1710											(X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
1711											(X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1712
1713#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1714#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1715#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1716#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1717
1718#define MaxUnansweredQueries 4
1719
1720// SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1721// (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1722// TTL and rdata may differ.
1723// This is used for cache flush management:
1724// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1725// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1726
1727// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match
1728
1729#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B))
1730
1731mDNSlocal mDNSBool SameResourceRecordNameClassInterface(const AuthRecord *const r1, const AuthRecord *const r2)
1732	{
1733	if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
1734	if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
1735	if (r1->resrec.InterfaceID &&
1736		r2->resrec.InterfaceID &&
1737		r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
1738	return(mDNSBool)(
1739		r1->resrec.rrclass  == r2->resrec.rrclass &&
1740		r1->resrec.namehash == r2->resrec.namehash &&
1741		SameDomainName(r1->resrec.name, r2->resrec.name));
1742	}
1743
1744// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1745// authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1746// complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1747// In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1748// so a response of any type should match, even if it is not actually the type the client plans to use.
1749
1750// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records,
1751// and require the rrtypes to match for the rdata to be considered potentially conflicting
1752mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
1753	{
1754	if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
1755	if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
1756	if (pktrr->resrec.InterfaceID &&
1757		authrr->resrec.InterfaceID &&
1758		pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
1759	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0])
1760		if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
1761	return(mDNSBool)(
1762		pktrr->resrec.rrclass == authrr->resrec.rrclass &&
1763		pktrr->resrec.namehash == authrr->resrec.namehash &&
1764		SameDomainName(pktrr->resrec.name, authrr->resrec.name));
1765	}
1766
1767// CacheRecord *ka is the CacheRecord from the known answer list in the query.
1768// This is the information that the requester believes to be correct.
1769// AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1770// This is the information that we believe to be correct.
1771// We've already determined that we plan to give this answer on this interface
1772// (either the record is non-specific, or it is specific to this interface)
1773// so now we just need to check the name, type, class, rdata and TTL.
1774mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
1775	{
1776	// If RR signature is different, or data is different, then don't suppress our answer
1777	if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
1778
1779	// If the requester's indicated TTL is less than half the real TTL,
1780	// we need to give our answer before the requester's copy expires.
1781	// If the requester's indicated TTL is at least half the real TTL,
1782	// then we can suppress our answer this time.
1783	// If the requester's indicated TTL is greater than the TTL we believe,
1784	// then that's okay, and we don't need to do anything about it.
1785	// (If two responders on the network are offering the same information,
1786	// that's okay, and if they are offering the information with different TTLs,
1787	// the one offering the lower TTL should defer to the one offering the higher TTL.)
1788	return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
1789	}
1790
1791mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
1792	{
1793	if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1794		{
1795		//LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1796		if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1797			m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
1798		}
1799	else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
1800		{
1801		if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1802			m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
1803		}
1804	}
1805
1806mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
1807	{
1808	// For reverse-mapping Sleep Proxy PTR records, probe interval is one second
1809	rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
1810
1811	// To allow us to aggregate probes when a group of services are registered together,
1812	// the first probe is delayed 1/4 second. This means the common-case behaviour is:
1813	// 1/4 second wait; probe
1814	// 1/4 second wait; probe
1815	// 1/4 second wait; probe
1816	// 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1817
1818	if (rr->ProbeCount)
1819		{
1820		// If we have no probe suppression time set, or it is in the past, set it now
1821		if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
1822			{
1823			m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
1824			// If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1825			if (m->SuppressProbes - m->NextScheduledProbe >= 0)
1826				m->SuppressProbes = m->NextScheduledProbe;
1827			// If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1828			if (m->SuppressProbes - m->NextScheduledQuery >= 0)
1829				m->SuppressProbes = m->NextScheduledQuery;
1830			}
1831		}
1832
1833	rr->LastAPTime      = m->SuppressProbes - rr->ThisAPInterval;
1834	// Set LastMCTime to now, to inhibit multicast responses
1835	// (no need to send additional multicast responses when we're announcing anyway)
1836	rr->LastMCTime      = m->timenow;
1837	rr->LastMCInterface = mDNSInterfaceMark;
1838
1839	// If this is a record type that's not going to probe, then delay its first announcement so that
1840	// it will go out synchronized with the first announcement for the other records that *are* probing.
1841	// This is a minor performance tweak that helps keep groups of related records synchronized together.
1842	// The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1843	// delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1844	// When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1845	// because they will meet the criterion of being at least half-way to their scheduled announcement time.
1846	if (rr->resrec.RecordType != kDNSRecordTypeUnique)
1847		rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
1848
1849	// The exception is unique records that have already been verified and are just being updated
1850	// via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1851	if (rr->resrec.RecordType == kDNSRecordTypeVerified)
1852		rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1853
1854	// For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
1855	// wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing.
1856	// After three probes one second apart with no answer, we conclude the client is now sleeping
1857	// and we can begin broadcasting our announcements to take over ownership of that IP address.
1858	// If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk
1859	// (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
1860	if (rr->AddressProxy.type) rr->LastAPTime = m->timenow;
1861
1862	// For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
1863	if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
1864		rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
1865
1866	SetNextAnnounceProbeTime(m, rr);
1867	}
1868
1869// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1870// Eventually we should unify this with GetServiceTarget() in uDNS.c
1871mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
1872	{
1873	domainname *const target = GetRRDomainNameTarget(&rr->resrec);
1874	const domainname *newname = &m->MulticastHostname;
1875
1876	if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
1877
1878	if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage)))
1879		{
1880		const domainname *const n = GetServiceTarget(m, rr);
1881		if (n) newname = n;
1882		}
1883
1884	if (target && SameDomainName(target, newname))
1885		debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
1886
1887	if (target && !SameDomainName(target, newname))
1888		{
1889		AssignDomainName(target, newname);
1890		SetNewRData(&rr->resrec, mDNSNULL, 0);		// Update rdlength, rdestimate, rdatahash
1891
1892		// If we're in the middle of probing this record, we need to start again,
1893		// because changing its rdata may change the outcome of the tie-breaker.
1894		// (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1895		rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1896
1897		// If we've announced this record, we really should send a goodbye packet for the old rdata before
1898		// changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1899		// so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1900		if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
1901			debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1902				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1903
1904		rr->AnnounceCount  = InitialAnnounceCount;
1905		rr->RequireGoodbye = mDNSfalse;
1906		InitializeLastAPTime(m, rr);
1907		}
1908	}
1909
1910mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
1911	{
1912	if (rr->RecordCallback)
1913		{
1914		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1915		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1916		rr->Acknowledged = mDNStrue;
1917		mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
1918		rr->RecordCallback(m, rr, mStatus_NoError);
1919		mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
1920		}
1921	}
1922
1923mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
1924	{
1925	rr->ProbeCount     = 0;
1926	rr->AnnounceCount  = 0;
1927	rr->ThisAPInterval = 5 * mDNSPlatformOneSecond;		// After doubling, first retry will happen after ten seconds
1928	rr->LastAPTime     = m->timenow - rr->ThisAPInterval;
1929	rr->state = regState_FetchingZoneData;
1930	rr->uselease = mDNStrue;
1931	}
1932
1933// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1934#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1935	((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1936#define RecordIsLocalDuplicate(A,B) \
1937	((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1938
1939// Exported so uDNS.c can call this
1940mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
1941	{
1942	domainname *target = GetRRDomainNameTarget(&rr->resrec);
1943	AuthRecord *r;
1944	AuthRecord **p = &m->ResourceRecords;
1945	AuthRecord **d = &m->DuplicateRecords;
1946
1947	if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
1948		{ LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1949
1950	if (!rr->resrec.RecordType)
1951		{ LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1952
1953	if (m->ShutdownTime)
1954		{ LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); }
1955
1956	if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
1957		{
1958		mDNSInterfaceID previousID = rr->resrec.InterfaceID;
1959		if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1960		if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1961			{
1962			NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
1963			if (intf && !intf->Advertise) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
1964			}
1965		if (rr->resrec.InterfaceID != previousID)
1966			LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr));
1967		}
1968
1969	while (*p && *p != rr) p=&(*p)->next;
1970	while (*d && *d != rr) d=&(*d)->next;
1971	if (*d || *p)
1972		{
1973		LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1974			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1975		return(mStatus_AlreadyRegistered);
1976		}
1977
1978	if (rr->DependentOn)
1979		{
1980		if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1981			rr->resrec.RecordType =  kDNSRecordTypeVerified;
1982		else
1983			{
1984			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1985				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1986			return(mStatus_Invalid);
1987			}
1988		if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
1989			{
1990			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1991				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
1992			return(mStatus_Invalid);
1993			}
1994		}
1995
1996	// If this resource record is referencing a specific interface, make sure it exists
1997	if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1998		{
1999		NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
2000		if (!intf)
2001			{
2002			debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
2003			return(mStatus_BadReferenceErr);
2004			}
2005		}
2006
2007	rr->next = mDNSNULL;
2008
2009	// Field Group 1: The actual information pertaining to this resource record
2010	// Set up by client prior to call
2011
2012	// Field Group 2: Persistent metadata for Authoritative Records
2013//	rr->Additional1       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
2014//	rr->Additional2       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
2015//	rr->DependentOn       = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
2016//	rr->RRSet             = set to mDNSNULL  in mDNS_SetupResourceRecord; may be overridden by client
2017//	rr->Callback          = already set      in mDNS_SetupResourceRecord
2018//	rr->Context           = already set      in mDNS_SetupResourceRecord
2019//	rr->RecordType        = already set      in mDNS_SetupResourceRecord
2020//	rr->HostTarget        = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2021//	rr->AllowRemoteQuery  = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2022	// Make sure target is not uninitialized data, or we may crash writing debugging log messages
2023	if (rr->AutoTarget && target) target->c[0] = 0;
2024
2025	// Field Group 3: Transient state for Authoritative Records
2026	rr->Acknowledged      = mDNSfalse;
2027	rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2028	rr->AnnounceCount     = InitialAnnounceCount;
2029	rr->RequireGoodbye    = mDNSfalse;
2030	rr->AnsweredLocalQ    = mDNSfalse;
2031	rr->IncludeInProbe    = mDNSfalse;
2032	rr->ImmedUnicast      = mDNSfalse;
2033	rr->SendNSECNow       = mDNSNULL;
2034	rr->ImmedAnswer       = mDNSNULL;
2035	rr->ImmedAdditional   = mDNSNULL;
2036	rr->SendRNow          = mDNSNULL;
2037	rr->v4Requester       = zerov4Addr;
2038	rr->v6Requester       = zerov6Addr;
2039	rr->NextResponse      = mDNSNULL;
2040	rr->NR_AnswerTo       = mDNSNULL;
2041	rr->NR_AdditionalTo   = mDNSNULL;
2042	if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
2043//	rr->LastAPTime        = Set for us in InitializeLastAPTime()
2044//	rr->LastMCTime        = Set for us in InitializeLastAPTime()
2045//	rr->LastMCInterface   = Set for us in InitializeLastAPTime()
2046	rr->NewRData          = mDNSNULL;
2047	rr->newrdlength       = 0;
2048	rr->UpdateCallback    = mDNSNULL;
2049	rr->UpdateCredits     = kMaxUpdateCredits;
2050	rr->NextUpdateCredit  = 0;
2051	rr->UpdateBlocked     = 0;
2052
2053	// For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient
2054	if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2;
2055
2056	// Field Group 4: Transient uDNS state for Authoritative Records
2057	rr->state             = regState_Zero;
2058	rr->uselease          = 0;
2059	rr->expire            = 0;
2060	rr->Private           = 0;
2061	rr->updateid          = zeroID;
2062	rr->zone              = rr->resrec.name;
2063	rr->UpdateServer      = zeroAddr;
2064	rr->UpdatePort        = zeroIPPort;
2065	rr->nta               = mDNSNULL;
2066	rr->tcp               = mDNSNULL;
2067	rr->OrigRData         = 0;
2068	rr->OrigRDLen         = 0;
2069	rr->InFlightRData     = 0;
2070	rr->InFlightRDLen     = 0;
2071	rr->QueuedRData       = 0;
2072	rr->QueuedRDLen       = 0;
2073
2074//	rr->resrec.interface         = already set in mDNS_SetupResourceRecord
2075//	rr->resrec.name->c           = MUST be set by client
2076//	rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
2077//	rr->resrec.rrclass           = already set in mDNS_SetupResourceRecord
2078//	rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
2079//	rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2080
2081	if (rr->AutoTarget)
2082		SetTargetToHostName(m, rr);	// Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2083	else
2084		{
2085		rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
2086		rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2087		}
2088
2089	if (!ValidateDomainName(rr->resrec.name))
2090		{ LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2091
2092	// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2093	// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2094	// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2095	if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
2096
2097	// Don't do this until *after* we've set rr->resrec.rdlength
2098	if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2099		{ LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2100
2101	rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
2102	rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
2103
2104	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2105		{
2106		// If this is supposed to be unique, make sure we don't have any name conflicts
2107		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2108			{
2109			const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
2110			for (r = m->ResourceRecords; r; r=r->next)
2111				{
2112				const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
2113				if (s1 != s2 && SameResourceRecordSignature(r, rr) && !IdenticalSameNameRecord(&r->resrec, &rr->resrec))
2114					break;
2115				}
2116			if (r)	// If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2117				{
2118				debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2119				rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2120				rr->resrec.rroriginalttl = 0;
2121				rr->ImmedAnswer          = mDNSInterfaceMark;
2122				m->NextScheduledResponse = m->timenow;
2123				}
2124			}
2125		}
2126
2127	// Now that we've finished building our new record, make sure it's not identical to one we already have
2128	for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
2129
2130	if (r)
2131		{
2132		debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
2133		*d = rr;
2134		// If the previous copy of this record is already verified unique,
2135		// then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2136		// Setting ProbeCount to zero will cause SendQueries() to advance this record to
2137		// kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2138		if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
2139			rr->ProbeCount = 0;
2140		}
2141	else
2142		{
2143		debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
2144		if (!m->NewLocalRecords) m->NewLocalRecords = rr;
2145		*p = rr;
2146		}
2147
2148	if (!AuthRecord_uDNS(rr))
2149		{
2150		// For records that are not going to probe, acknowledge them right away
2151		if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
2152			AcknowledgeRecord(m, rr);
2153		}
2154#ifndef UNICAST_DISABLED
2155	else
2156		{
2157		if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
2158		ActivateUnicastRegistration(m, rr);
2159		}
2160#endif
2161
2162	return(mStatus_NoError);
2163	}
2164
2165mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
2166	{
2167	m->ProbeFailTime = m->timenow;
2168	m->NumFailedProbes++;
2169	// If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2170	// If a bunch of hosts have all been configured with the same name, then they'll all
2171	// conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2172	// up to name-10. After that they'll start adding random increments in the range 1-100,
2173	// so they're more likely to branch out in the available namespace and settle on a set of
2174	// unique names quickly. If after five more tries the host is still conflicting, then we
2175	// may have a serious problem, so we start rate-limiting so we don't melt down the network.
2176	if (m->NumFailedProbes >= 15)
2177		{
2178		m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
2179		LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2180			m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2181		}
2182	}
2183
2184mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
2185	{
2186	RData *OldRData = rr->resrec.rdata;
2187	SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);	// Update our rdata
2188	rr->NewRData = mDNSNULL;									// Clear the NewRData pointer ...
2189	if (rr->UpdateCallback)
2190		rr->UpdateCallback(m, rr, OldRData);					// ... and let the client know
2191	}
2192
2193// Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2194// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2195// Exported so uDNS.c can call this
2196mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
2197	{
2198	AuthRecord *r2;
2199	mDNSu8 RecordType = rr->resrec.RecordType;
2200	AuthRecord **p = &m->ResourceRecords;	// Find this record in our list of active records
2201
2202	while (*p && *p != rr) p=&(*p)->next;
2203
2204	if (*p)
2205		{
2206		// We found our record on the main list. See if there are any duplicates that need special handling.
2207		if (drt == mDNS_Dereg_conflict)		// If this was a conflict, see that all duplicates get the same treatment
2208			{
2209			// Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2210			// deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2211			for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
2212			}
2213		else
2214			{
2215			// Before we delete the record (and potentially send a goodbye packet)
2216			// first see if we have a record on the duplicate list ready to take over from it.
2217			AuthRecord **d = &m->DuplicateRecords;
2218			while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
2219			if (*d)
2220				{
2221				AuthRecord *dup = *d;
2222				debugf("Duplicate record %p taking over from %p %##s (%s)",
2223					dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2224				*d        = dup->next;		// Cut replacement record from DuplicateRecords list
2225				dup->next = rr->next;		// And then...
2226				rr->next  = dup;			// ... splice it in right after the record we're about to delete
2227				dup->resrec.RecordType        = rr->resrec.RecordType;
2228				dup->ProbeCount      = rr->ProbeCount;
2229				dup->AnnounceCount   = rr->AnnounceCount;
2230				dup->RequireGoodbye  = rr->RequireGoodbye;
2231				dup->AnsweredLocalQ  = rr->AnsweredLocalQ;
2232				dup->ImmedAnswer     = rr->ImmedAnswer;
2233				dup->ImmedUnicast    = rr->ImmedUnicast;
2234				dup->ImmedAdditional = rr->ImmedAdditional;
2235				dup->v4Requester     = rr->v4Requester;
2236				dup->v6Requester     = rr->v6Requester;
2237				dup->ThisAPInterval  = rr->ThisAPInterval;
2238				dup->LastAPTime      = rr->LastAPTime;
2239				dup->LastMCTime      = rr->LastMCTime;
2240				dup->LastMCInterface = rr->LastMCInterface;
2241				dup->UpdateServer    = rr->UpdateServer;
2242				dup->UpdatePort      = rr->UpdatePort;
2243				dup->Private         = rr->Private;
2244				dup->state           = rr->state;
2245				rr->RequireGoodbye = mDNSfalse;
2246				rr->AnsweredLocalQ = mDNSfalse;
2247				}
2248			}
2249		}
2250	else
2251		{
2252		// We didn't find our record on the main list; try the DuplicateRecords list instead.
2253		p = &m->DuplicateRecords;
2254		while (*p && *p != rr) p=&(*p)->next;
2255		// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2256		if (*p) rr->RequireGoodbye = mDNSfalse;
2257		if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2258			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2259		}
2260
2261	if (!*p)
2262		{
2263		// No need to log an error message if we already know this is a potentially repeated deregistration
2264		if (drt != mDNS_Dereg_repeat)
2265			LogMsg("mDNS_Deregister_internal: Record %p not found in list %s", rr, ARDisplayString(m,rr));
2266		return(mStatus_BadReferenceErr);
2267		}
2268
2269	// If this is a shared record and we've announced it at least once,
2270	// we need to retract that announcement before we delete the record
2271
2272	// If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
2273	// it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
2274	// The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
2275	// mechanism to cope with the client callback modifying the question list while that's happening.
2276	// However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
2277	// which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
2278	// More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
2279	// records, thereby invoking yet more callbacks, without limit.
2280	// The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
2281	// actual goodbye packets.
2282
2283#ifndef UNICAST_DISABLED
2284	if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
2285		{
2286		if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
2287		rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2288		uDNS_DeregisterRecord(m, rr);
2289		// At this point unconditionally we bail out
2290		// Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
2291		// which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
2292		// process and will complete asynchronously. Either way we don't need to do anything more here.
2293		return(mStatus_NoError);
2294		}
2295#endif // UNICAST_DISABLED
2296
2297	if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
2298		{
2299		verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
2300		rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2301		rr->resrec.rroriginalttl = 0;
2302		rr->ImmedAnswer          = mDNSInterfaceMark;
2303		if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2304			m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2305		}
2306	else
2307		{
2308		*p = rr->next;					// Cut this record from the list
2309		// If someone is about to look at this, bump the pointer forward
2310		if (m->CurrentRecord   == rr) m->CurrentRecord   = rr->next;
2311		if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2312		rr->next = mDNSNULL;
2313
2314		if      (RecordType == kDNSRecordTypeUnregistered)
2315			LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
2316		else if (RecordType == kDNSRecordTypeDeregistering)
2317			LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
2318		else
2319			{
2320			verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
2321			rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2322			}
2323
2324		if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2325			debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2326				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2327
2328		// If we have an update queued up which never executed, give the client a chance to free that memory
2329		if (rr->NewRData) CompleteRDataUpdate(m, rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
2330
2331		if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
2332		if (rr->tcp) { DisposeTCPConn(rr->tcp);       rr->tcp = mDNSNULL; }
2333
2334		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2335		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2336		// In this case the likely client action to the mStatus_MemFree message is to free the memory,
2337		// so any attempt to touch rr after this is likely to lead to a crash.
2338		if (drt != mDNS_Dereg_conflict)
2339			{
2340			mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
2341			if (rr->RecordCallback)
2342				rr->RecordCallback(m, rr, mStatus_MemFree);			// MUST NOT touch rr after this
2343			mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
2344			}
2345		else
2346			{
2347			RecordProbeFailure(m, rr);
2348			mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
2349			if (rr->RecordCallback)
2350				rr->RecordCallback(m, rr, mStatus_NameConflict);	// MUST NOT touch rr after this
2351			mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
2352			// Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2353			// Note that with all the client callbacks going on, by the time we get here all the
2354			// records we marked may have been explicitly deregistered by the client anyway.
2355			r2 = m->DuplicateRecords;
2356			while (r2)
2357				{
2358				if (r2->ProbeCount != 0xFF) r2 = r2->next;
2359				else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
2360				}
2361			}
2362		}
2363	return(mStatus_NoError);
2364	}
2365
2366// ***************************************************************************
2367#if COMPILER_LIKES_PRAGMA_MARK
2368#pragma mark -
2369#pragma mark - Packet Sending Functions
2370#endif
2371
2372mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2373	{
2374	if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2375		{
2376		**nrpp = rr;
2377		// NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2378		// If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2379		// The referenced record will definitely be acceptable (by recursive application of this rule)
2380		if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2381		rr->NR_AdditionalTo = add;
2382		*nrpp = &rr->NextResponse;
2383		}
2384	debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2385	}
2386
2387mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2388	{
2389	AuthRecord  *rr, *rr2;
2390	for (rr=ResponseRecords; rr; rr=rr->NextResponse)			// For each record we plan to put
2391		{
2392		// (Note: This is an "if", not a "while". If we add a record, we'll find it again
2393		// later in the "for" loop, and we will follow further "additional" links then.)
2394		if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2395			AddRecordToResponseList(nrpp, rr->Additional1, rr);
2396
2397		if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2398			AddRecordToResponseList(nrpp, rr->Additional2, rr);
2399
2400		// For SRV records, automatically add the Address record(s) for the target host
2401		if (rr->resrec.rrtype == kDNSType_SRV)
2402			{
2403			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
2404				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
2405					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
2406					rr->resrec.rdatahash == rr2->resrec.namehash &&			// ... whose name is the name of the SRV target
2407					SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2408					AddRecordToResponseList(nrpp, rr2, rr);
2409			}
2410		else if (RRTypeIsAddressType(rr->resrec.rrtype))	// For A or AAAA, put counterpart as additional
2411			{
2412			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
2413				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
2414					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
2415					rr->resrec.namehash == rr2->resrec.namehash &&				// ... and have the same name
2416					SameDomainName(rr->resrec.name, rr2->resrec.name))
2417					AddRecordToResponseList(nrpp, rr2, rr);
2418			}
2419		else if (rr->resrec.rrtype == kDNSType_PTR)			// For service PTR, see if we want to add DeviceInfo record
2420			{
2421			if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
2422				SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
2423				AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
2424			}
2425		}
2426	}
2427
2428mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2429	{
2430	AuthRecord *rr;
2431	AuthRecord  *ResponseRecords = mDNSNULL;
2432	AuthRecord **nrp             = &ResponseRecords;
2433
2434	// Make a list of all our records that need to be unicast to this destination
2435	for (rr = m->ResourceRecords; rr; rr=rr->next)
2436		{
2437		// If we find we can no longer unicast this answer, clear ImmedUnicast
2438		if (rr->ImmedAnswer == mDNSInterfaceMark               ||
2439			mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2440			mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr)  )
2441			rr->ImmedUnicast = mDNSfalse;
2442
2443		if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2444			if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2445				(dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2446				{
2447				rr->ImmedAnswer  = mDNSNULL;				// Clear the state fields
2448				rr->ImmedUnicast = mDNSfalse;
2449				rr->v4Requester  = zerov4Addr;
2450				rr->v6Requester  = zerov6Addr;
2451				if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse)	// rr->NR_AnswerTo
2452					{ rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
2453				}
2454		}
2455
2456	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2457
2458	while (ResponseRecords)
2459		{
2460		mDNSu8 *responseptr = m->omsg.data;
2461		mDNSu8 *newptr;
2462		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2463
2464		// Put answers in the packet
2465		while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2466			{
2467			rr = ResponseRecords;
2468			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2469				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2470			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2471			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2472			if (!newptr && m->omsg.h.numAnswers) break;	// If packet full, send it now
2473			if (newptr) responseptr = newptr;
2474			ResponseRecords = rr->NextResponse;
2475			rr->NextResponse    = mDNSNULL;
2476			rr->NR_AnswerTo     = mDNSNULL;
2477			rr->NR_AdditionalTo = mDNSNULL;
2478			rr->RequireGoodbye  = mDNStrue;
2479			}
2480
2481		// Add additionals, if there's space
2482		while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2483			{
2484			rr = ResponseRecords;
2485			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2486				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2487			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2488			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2489
2490			if (newptr) responseptr = newptr;
2491			if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2492			else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2493			ResponseRecords = rr->NextResponse;
2494			rr->NextResponse    = mDNSNULL;
2495			rr->NR_AnswerTo     = mDNSNULL;
2496			rr->NR_AdditionalTo = mDNSNULL;
2497			}
2498
2499		if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
2500		}
2501	}
2502
2503mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2504	{
2505	// Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
2506	// it should go ahead and immediately dispose of this registration
2507	rr->resrec.RecordType = kDNSRecordTypeShared;
2508	rr->RequireGoodbye    = mDNSfalse;
2509	if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
2510	mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);		// Don't touch rr after this
2511	}
2512
2513// Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2514// the record list and/or question list.
2515// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2516mDNSlocal void DiscardDeregistrations(mDNS *const m)
2517	{
2518	if (m->CurrentRecord)
2519		LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
2520	m->CurrentRecord = m->ResourceRecords;
2521
2522	while (m->CurrentRecord)
2523		{
2524		AuthRecord *rr = m->CurrentRecord;
2525		if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2526			CompleteDeregistration(m, rr);		// Don't touch rr after this
2527		else
2528			m->CurrentRecord = rr->next;
2529		}
2530	}
2531
2532mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
2533	{
2534	int i, val = 0;
2535	if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid);
2536	for (i=1; i<=src[0]; i++)
2537		{
2538		if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid);
2539		val = val * 10 + src[i] - '0';
2540		}
2541	if (val > 255) return(mStatus_Invalid);
2542	*dst = val;
2543	return(mStatus_NoError);
2544	}
2545
2546mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name)
2547	{
2548	int skip = CountLabels(name) - 6;
2549	if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; }
2550	if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) ||
2551		GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) ||
2552		GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) ||
2553		GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid;
2554	a->type = mDNSAddrType_IPv4;
2555	return(mStatus_NoError);
2556	}
2557
2558#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :   \
2559					((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) :   \
2560					((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
2561
2562mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name)
2563	{
2564	int i, h, l;
2565	const domainname *n;
2566
2567	int skip = CountLabels(name) - 34;
2568	if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; }
2569
2570	n = SkipLeadingLabels(name, skip);
2571	for (i=0; i<16; i++)
2572		{
2573		if (n->c[0] != 1) return mStatus_Invalid;
2574		l = HexVal(n->c[1]);
2575		n = (const domainname *)(n->c + 2);
2576
2577		if (n->c[0] != 1) return mStatus_Invalid;
2578		h = HexVal(n->c[1]);
2579		n = (const domainname *)(n->c + 2);
2580
2581		if (l<0 || h<0) return mStatus_Invalid;
2582		a->ip.v6.b[15-i] = (h << 4) | l;
2583		}
2584
2585	a->type = mDNSAddrType_IPv6;
2586	return(mStatus_NoError);
2587	}
2588
2589mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name)
2590	{
2591	int skip = CountLabels(name) - 2;
2592	if (skip >= 0)
2593		{
2594		const domainname *suffix = SkipLeadingLabels(name, skip);
2595		if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4;
2596		if (SameDomainName(suffix, (const domainname*)"\x3" "ip6"     "\x4" "arpa")) return mDNSAddrType_IPv6;
2597		}
2598	return(mDNSAddrType_None);
2599	}
2600
2601mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr,
2602	const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst)
2603	{
2604	int i;
2605	mDNSu8 *ptr = m->omsg.data;
2606	NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
2607	if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
2608
2609	// 0x00 Destination address
2610	for (i=0; i<6; i++) *ptr++ = dst[i];
2611
2612	// 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
2613	for (i=0; i<6; i++) *ptr++ = 0x0;
2614
2615	// 0x0C ARP Ethertype (0x0806)
2616	*ptr++ = 0x08; *ptr++ = 0x06;
2617
2618	// 0x0E ARP header
2619	*ptr++ = 0x00; *ptr++ = 0x01;	// Hardware address space; Ethernet = 1
2620	*ptr++ = 0x08; *ptr++ = 0x00;	// Protocol address space; IP = 0x0800
2621	*ptr++ = 6;						// Hardware address length
2622	*ptr++ = 4;						// Protocol address length
2623	*ptr++ = 0x00; *ptr++ = op;		// opcode; Request = 1, Response = 2
2624
2625	// 0x16 Sender hardware address (our MAC address)
2626	for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i];
2627
2628	// 0x1C Sender protocol address
2629	for (i=0; i<4; i++) *ptr++ = spa[i];
2630
2631	// 0x20 Target hardware address
2632	for (i=0; i<6; i++) *ptr++ = tha[i];
2633
2634	// 0x26 Target protocol address
2635	for (i=0; i<4; i++) *ptr++ = tpa[i];
2636
2637	// 0x2A Total ARP Packet length 42 bytes
2638	mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
2639	}
2640
2641mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner)
2642	{
2643	owner->u.owner.vers     = 0;
2644	owner->u.owner.seq      = m->SleepSeqNum;
2645	owner->u.owner.HMAC     = m->PrimaryMAC;
2646	owner->u.owner.IMAC     = intf->MAC;
2647	owner->u.owner.password = zeroEthAddr;
2648
2649	// Don't try to compute the optlen until *after* we've set up the data fields
2650	owner->opt              = kDNSOpt_Owner;
2651	owner->optlen           = DNSOpt_Owner_Space(owner) - 4;
2652	}
2653
2654mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
2655	{
2656	if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
2657	else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
2658	}
2659
2660// Note about acceleration of announcements to facilitate automatic coalescing of
2661// multiple independent threads of announcements into a single synchronized thread:
2662// The announcements in the packet may be at different stages of maturity;
2663// One-second interval, two-second interval, four-second interval, and so on.
2664// After we've put in all the announcements that are due, we then consider
2665// whether there are other nearly-due announcements that are worth accelerating.
2666// To be eligible for acceleration, a record MUST NOT be older (further along
2667// its timeline) than the most mature record we've already put in the packet.
2668// In other words, younger records can have their timelines accelerated to catch up
2669// with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
2670// Older records cannot have their timelines accelerated; this would just widen
2671// the gap between them and their younger bretheren and get them even more out of sync.
2672
2673// Note: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
2674// the record list and/or question list.
2675// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2676mDNSlocal void SendResponses(mDNS *const m)
2677	{
2678	int pktcount = 0;
2679	AuthRecord *rr, *r2;
2680	mDNSs32 maxExistingAnnounceInterval = 0;
2681	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
2682
2683	m->NextScheduledResponse = m->timenow + 0x78000000;
2684
2685	if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m);
2686
2687	for (rr = m->ResourceRecords; rr; rr=rr->next)
2688		if (rr->ImmedUnicast)
2689			{
2690			mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
2691			mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
2692			v4.ip.v4 = rr->v4Requester;
2693			v6.ip.v6 = rr->v6Requester;
2694			if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
2695			if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
2696			if (rr->ImmedUnicast)
2697				{
2698				LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
2699				rr->ImmedUnicast = mDNSfalse;
2700				}
2701			}
2702
2703	// ***
2704	// *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
2705	// ***
2706
2707	// Run through our list of records, and decide which ones we're going to announce on all interfaces
2708	for (rr = m->ResourceRecords; rr; rr=rr->next)
2709		{
2710		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
2711		if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
2712			{
2713			if (rr->AddressProxy.type)
2714				{
2715				rr->AnnounceCount--;
2716				rr->ThisAPInterval *= 2;
2717				rr->LastAPTime = m->timenow;
2718				if (rr->AddressProxy.type == mDNSAddrType_IPv4)
2719					{
2720					LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
2721					SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2722					}
2723				else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
2724					{
2725					//LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
2726					//SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
2727					}
2728				}
2729			else
2730				{
2731				rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
2732				if (maxExistingAnnounceInterval < rr->ThisAPInterval)
2733					maxExistingAnnounceInterval = rr->ThisAPInterval;
2734				if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
2735				}
2736			}
2737		}
2738
2739	// Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
2740	// Eligible records that are more than half-way to their announcement time are accelerated
2741	for (rr = m->ResourceRecords; rr; rr=rr->next)
2742		if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
2743			(rr->ThisAPInterval <= maxExistingAnnounceInterval &&
2744			TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
2745			!rr->AddressProxy.type && 					// Don't include ARP Annoucements when considering which records to accelerate
2746			ResourceRecordIsValidAnswer(rr)))
2747			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
2748
2749	// When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
2750	// Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
2751	// which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
2752	// then all that means is that it won't get sent -- which would not be the end of the world.
2753	for (rr = m->ResourceRecords; rr; rr=rr->next)
2754		{
2755		if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
2756			for (r2=m->ResourceRecords; r2; r2=r2->next)				// Scan list of resource records
2757				if (RRTypeIsAddressType(r2->resrec.rrtype) &&			// For all address records (A/AAAA) ...
2758					ResourceRecordIsValidAnswer(r2) &&					// ... which are valid for answer ...
2759					rr->LastMCTime - r2->LastMCTime >= 0 &&				// ... which we have not sent recently ...
2760					rr->resrec.rdatahash == r2->resrec.namehash &&		// ... whose name is the name of the SRV target
2761					SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
2762					(rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
2763					r2->ImmedAdditional = r2->resrec.InterfaceID;		// ... then mark this address record for sending too
2764		// We also make sure we send the DeviceInfo TXT record too, if necessary
2765		// We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
2766		// DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
2767		if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR)
2768			if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
2769				{
2770				if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer;
2771				else                            m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark;
2772				}
2773		}
2774
2775	// If there's a record which is supposed to be unique that we're going to send, then make sure that we give
2776	// the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
2777	// then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
2778	// record, then other RRSet members that have not been sent recently will get flushed out of client caches.
2779	// -- If a record is marked to be sent on a certain interface, make sure the whole set is marked to be sent on that interface
2780	// -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
2781	for (rr = m->ResourceRecords; rr; rr=rr->next)
2782		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2783			{
2784			if (rr->ImmedAnswer)			// If we're sending this as answer, see that its whole RRSet is similarly marked
2785				{
2786				for (r2 = m->ResourceRecords; r2; r2=r2->next)
2787					if (ResourceRecordIsValidAnswer(r2))
2788						if (r2->ImmedAnswer != mDNSInterfaceMark &&
2789							r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
2790							r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark;
2791				}
2792			else if (rr->ImmedAdditional)	// If we're sending this as additional, see that its whole RRSet is similarly marked
2793				{
2794				for (r2 = m->ResourceRecords; r2; r2=r2->next)
2795					if (ResourceRecordIsValidAnswer(r2))
2796						if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
2797							r2->ImmedAdditional = rr->ImmedAdditional;
2798				}
2799			}
2800
2801	// Now set SendRNow state appropriately
2802	for (rr = m->ResourceRecords; rr; rr=rr->next)
2803		{
2804		if (rr->ImmedAnswer == mDNSInterfaceMark)		// Sending this record on all appropriate interfaces
2805			{
2806			rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
2807			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional if sending as answer
2808			rr->LastMCTime      = m->timenow;
2809			rr->LastMCInterface = rr->ImmedAnswer;
2810			// If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
2811			if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
2812				{
2813				rr->AnnounceCount--;
2814				rr->ThisAPInterval *= 2;
2815				rr->LastAPTime = m->timenow;
2816				debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
2817				}
2818			}
2819		else if (rr->ImmedAnswer)						// Else, just respond to a single query on single interface:
2820			{
2821			rr->SendRNow        = rr->ImmedAnswer;		// Just respond on that interface
2822			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional too
2823			rr->LastMCTime      = m->timenow;
2824			rr->LastMCInterface = rr->ImmedAnswer;
2825			}
2826		SetNextAnnounceProbeTime(m, rr);
2827		//if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2828		}
2829
2830	// ***
2831	// *** 2. Loop through interface list, sending records as appropriate
2832	// ***
2833
2834	while (intf)
2835		{
2836		int numDereg    = 0;
2837		int numAnnounce = 0;
2838		int numAnswer   = 0;
2839		mDNSu8 *responseptr = m->omsg.data;
2840		mDNSu8 *newptr;
2841		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2842
2843		// First Pass. Look for:
2844		// 1. Deregistering records that need to send their goodbye packet
2845		// 2. Updated records that need to retract their old data
2846		// 3. Answers and announcements we need to send
2847		for (rr = m->ResourceRecords; rr; rr=rr->next)
2848			{
2849			if (rr->SendRNow == intf->InterfaceID)
2850				{
2851				newptr = mDNSNULL;
2852				if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2853					{
2854					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2855					if (newptr) { responseptr = newptr; numDereg++; }
2856					}
2857				else if (rr->NewRData && !m->SleepState)					// If we have new data for this record
2858					{
2859					RData *OldRData     = rr->resrec.rdata;
2860					mDNSu16 oldrdlength = rr->resrec.rdlength;
2861					// See if we should send a courtesy "goodbye" for the old data before we replace it.
2862					if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
2863						{
2864						newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2865						if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
2866						}
2867					// Now try to see if we can fit the update in the same packet (not fatal if we can't)
2868					SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
2869					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2870						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2871					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2872					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2873					if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
2874					SetNewRData(&rr->resrec, OldRData, oldrdlength);
2875					}
2876				else
2877					{
2878					mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type);
2879					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2880						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2881					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
2882					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2883					if (newptr)
2884						{
2885						responseptr = newptr;
2886						rr->RequireGoodbye = active;
2887						if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
2888						}
2889
2890					// The first time through (pktcount==0), if this record is verified unique
2891					// (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2892					if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
2893					}
2894
2895				if (newptr)		// If succeeded in sending, advance to next interface
2896					{
2897					// If sending on all interfaces, go to next interface; else we're finished now
2898					if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
2899						rr->SendRNow = GetNextActiveInterfaceID(intf);
2900					else
2901						rr->SendRNow = mDNSNULL;
2902					}
2903				}
2904			}
2905
2906		// Second Pass. Add additional records, if there's space.
2907		newptr = responseptr;
2908		for (rr = m->ResourceRecords; rr; rr=rr->next)
2909			if (rr->ImmedAdditional == intf->InterfaceID)
2910				if (ResourceRecordIsValidAnswer(rr))
2911					{
2912					// If we have at least one answer already in the packet, then plan to add additionals too
2913					mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
2914
2915					// If we're not planning to send any additionals, but this record is a unique one, then
2916					// make sure we haven't already sent any other members of its RRSet -- if we have, then they
2917					// will have had the cache flush bit set, so now we need to finish the job and send the rest.
2918					if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
2919						{
2920						const AuthRecord *a;
2921						for (a = m->ResourceRecords; a; a=a->next)
2922							if (a->LastMCTime      == m->timenow &&
2923								a->LastMCInterface == intf->InterfaceID &&
2924								SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; }
2925						}
2926					if (!SendAdditional)					// If we don't want to send this after all,
2927						rr->ImmedAdditional = mDNSNULL;		// then cancel its ImmedAdditional field
2928					else if (newptr)						// Else, try to add it if we can
2929						{
2930						// The first time through (pktcount==0), if this record is verified unique
2931						// (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
2932						if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1;
2933
2934						if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2935							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
2936						newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
2937						rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear cache flush bit back to normal state
2938						if (newptr)
2939							{
2940							responseptr = newptr;
2941							rr->ImmedAdditional = mDNSNULL;
2942							rr->RequireGoodbye = mDNStrue;
2943							// If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2944							// This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2945							// when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2946							// all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2947							rr->LastMCTime      = m->timenow;
2948							rr->LastMCInterface = intf->InterfaceID;
2949							}
2950						}
2951					}
2952
2953		// Third Pass. Add NSEC records, if there's space.
2954		for (rr = m->ResourceRecords; rr; rr=rr->next)
2955			if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID)
2956				{
2957				AuthRecord nsec;
2958				mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
2959				nsec.resrec.rrclass |= kDNSClass_UniqueRRSet;
2960				AssignDomainName(&nsec.namestorage, rr->resrec.name);
2961				mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap));
2962				for (r2 = m->ResourceRecords; r2; r2=r2->next)
2963					if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr))
2964						{
2965						if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; }
2966						else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7);
2967						}
2968				newptr = responseptr;
2969				if (!r2)	// If we successfully built our NSEC record, add it to the packet now
2970					{
2971					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec);
2972					if (newptr) responseptr = newptr;
2973					}
2974
2975				// If we successfully put the NSEC record, clear the SendNSECNow flag
2976				// If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record
2977				if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1)
2978					{
2979					rr->SendNSECNow = mDNSNULL;
2980					// Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC
2981					for (r2 = rr->next; r2; r2=r2->next)
2982						if (SameResourceRecordNameClassInterface(r2, rr))
2983							if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID)
2984								r2->SendNSECNow = mDNSNULL;
2985					}
2986				}
2987
2988		if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
2989			{
2990			debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2991				numDereg,                 numDereg                 == 1 ? "" : "s",
2992				numAnnounce,              numAnnounce              == 1 ? "" : "s",
2993				numAnswer,                numAnswer                == 1 ? "" : "s",
2994				m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
2995			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
2996			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
2997			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
2998			if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
2999			// There might be more things to send on this interface, so go around one more time and try again.
3000			}
3001		else	// Nothing more to send on this interface; go to next
3002			{
3003			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3004			#if MDNS_DEBUGMSGS && 0
3005			const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3006			debugf(msg, intf, next);
3007			#endif
3008			intf = next;
3009			pktcount = 0;		// When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it
3010			}
3011		}
3012
3013	// ***
3014	// *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3015	// ***
3016
3017	if (m->CurrentRecord)
3018		LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3019	m->CurrentRecord = m->ResourceRecords;
3020	while (m->CurrentRecord)
3021		{
3022		rr = m->CurrentRecord;
3023		m->CurrentRecord = rr->next;
3024
3025		if (rr->SendRNow)
3026			{
3027			if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
3028				LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
3029			rr->SendRNow = mDNSNULL;
3030			}
3031
3032		if (rr->ImmedAnswer)
3033			{
3034			if (rr->NewRData) CompleteRDataUpdate(m, rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
3035
3036			if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3037				CompleteDeregistration(m, rr);		// Don't touch rr after this
3038			else
3039				{
3040				rr->ImmedAnswer  = mDNSNULL;
3041				rr->ImmedUnicast = mDNSfalse;
3042				rr->v4Requester  = zerov4Addr;
3043				rr->v6Requester  = zerov6Addr;
3044				}
3045			}
3046		}
3047	verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
3048	}
3049
3050// Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3051// so we want to be lazy about how frequently we do it.
3052// 1. If a cache record is currently referenced by *no* active questions,
3053//    then we don't mind expiring it up to a minute late (who will know?)
3054// 2. Else, if a cache record is due for some of its final expiration queries,
3055//    we'll allow them to be late by up to 2% of the TTL
3056// 3. Else, if a cache record has completed all its final expiration queries without success,
3057//    and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3058// 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3059//    so allow at most 1/10 second lateness
3060// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
3061//    (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
3062#define CacheCheckGracePeriod(RR) (                                                   \
3063	((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
3064	((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
3065	((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
3066	((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : \
3067	((RR)->resrec.rroriginalttl > 0                ) ? (mDNSPlatformOneSecond/10)   : 0)
3068
3069// Note: MUST call SetNextCacheCheckTime any time we change:
3070// rr->TimeRcvd
3071// rr->resrec.rroriginalttl
3072// rr->UnansweredQueries
3073// rr->CRActiveQuestion
3074// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3075// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
3076mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
3077	{
3078	rr->NextRequiredQuery = RRExpireTime(rr);
3079
3080	// If we have an active question, then see if we want to schedule a refresher query for this record.
3081	// Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3082	if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3083		{
3084		rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
3085		rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
3086		verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3087			rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
3088			(rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
3089		}
3090
3091	if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
3092		m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
3093
3094	if (rr->DelayDelivery)
3095		if (m->NextCacheCheck - rr->DelayDelivery > 0)
3096			m->NextCacheCheck = rr->DelayDelivery;
3097	}
3098
3099#define kMinimumReconfirmTime                     ((mDNSu32)mDNSPlatformOneSecond *  5)
3100#define kDefaultReconfirmTimeForWake              ((mDNSu32)mDNSPlatformOneSecond *  5)
3101#define kDefaultReconfirmTimeForNoAnswer          ((mDNSu32)mDNSPlatformOneSecond *  5)
3102#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3103
3104mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
3105	{
3106	if (interval < kMinimumReconfirmTime)
3107		interval = kMinimumReconfirmTime;
3108	if (interval > 0x10000000)	// Make sure interval doesn't overflow when we multiply by four below
3109		interval = 0x10000000;
3110
3111	// If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3112	if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
3113		{
3114		// Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3115		// For all the reconfirmations in a given batch, we want to use the same random value
3116		// so that the reconfirmation questions can be grouped into a single query packet
3117		if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
3118		interval += m->RandomReconfirmDelay % ((interval/3) + 1);
3119		rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
3120		rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
3121		SetNextCacheCheckTime(m, rr);
3122		}
3123	debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
3124		RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
3125	return(mStatus_NoError);
3126	}
3127
3128#define MaxQuestionInterval         (3600 * mDNSPlatformOneSecond)
3129
3130// BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3131// It also appends to the list of known answer records that need to be included,
3132// and updates the forcast for the size of the known answer section.
3133mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
3134	CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
3135	{
3136	mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
3137	mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3138	const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
3139	mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
3140	if (!newptr)
3141		{
3142		debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3143		return(mDNSfalse);
3144		}
3145	else if (newptr + *answerforecast >= limit)
3146		{
3147		verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3148			q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
3149		query->h.numQuestions--;
3150		return(mDNSfalse);
3151		}
3152	else
3153		{
3154		mDNSu32 forecast = *answerforecast;
3155		const mDNSu32 slot = HashSlot(&q->qname);
3156		const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3157		CacheRecord *rr;
3158		CacheRecord **ka = *kalistptrptr;	// Make a working copy of the pointer we're going to update
3159
3160		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3161			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3162				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not already in the known answer list
3163				rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3164				SameNameRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3165				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >				// and its half-way-to-expiry time is at least 1 second away
3166												mDNSPlatformOneSecond)		// (also ensures we never include goodbye records with TTL=1)
3167				{
3168				*ka = rr;	// Link this record into our known answer chain
3169				ka = &rr->NextInKAList;
3170				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3171				forecast += 12 + rr->resrec.rdestimate;
3172				// If we're trying to put more than one question in this packet, and it doesn't fit
3173				// then undo that last question and try again next time
3174				if (query->h.numQuestions > 1 && newptr + forecast >= limit)
3175					{
3176					debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3177						q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
3178					query->h.numQuestions--;
3179					ka = *kalistptrptr;		// Go back to where we started and retract these answer records
3180					while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; }
3181					return(mDNSfalse);		// Return false, so we'll try again in the next packet
3182					}
3183				}
3184
3185		// Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3186		*queryptr        = newptr;				// Update the packet pointer
3187		*answerforecast  = forecast;			// Update the forecast
3188		*kalistptrptr    = ka;					// Update the known answer list pointer
3189		if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
3190
3191		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// For every resource record in our cache,
3192			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3193				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not in the known answer list
3194				SameNameRecordAnswersQuestion(&rr->resrec, q))				// which answers our question
3195					{
3196					rr->UnansweredQueries++;								// indicate that we're expecting a response
3197					rr->LastUnansweredTime = m->timenow;
3198					SetNextCacheCheckTime(m, rr);
3199					}
3200
3201		return(mDNStrue);
3202		}
3203	}
3204
3205// When we have a query looking for a specified name, but there appear to be no answers with
3206// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
3207// for any records in our cache that reference the given name (e.g. PTR and SRV records).
3208// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
3209// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
3210// A typical reconfirmation scenario might go like this:
3211// Depth 0: Name "myhost.local" has no address records
3212// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
3213// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
3214// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
3215// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
3216// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
3217mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth)
3218	{
3219	mDNSu32 slot;
3220	CacheGroup *cg;
3221	CacheRecord *cr;
3222	debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c);
3223	FORALL_CACHERECORDS(slot, cg, cr)
3224		{
3225		domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
3226		if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
3227			{
3228			LogInfo("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
3229			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
3230			if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1);
3231			}
3232		}
3233	}
3234
3235// If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
3236// we check if we have an address record for the same name. If we do have an IPv4 address for a given
3237// name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
3238// to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
3239mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
3240	{
3241	CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name);
3242	const CacheRecord *cr = cg ? cg->members : mDNSNULL;
3243	while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next;
3244	return(cr);
3245	}
3246
3247mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1)
3248	{
3249	CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname);
3250	const CacheRecord *cr, *bestcr = mDNSNULL;
3251	mDNSu32 bestmetric = 1000000;
3252	for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
3253		if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6)						// If record is PTR type, with long enough name,
3254			if (cr != c0 && cr != c1)															// that's not one we've seen before,
3255				if (SameNameRecordAnswersQuestion(&cr->resrec, q))								// and answers our browse query,
3256					if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec))	// and is not our own advertised service...
3257						{
3258						mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c);
3259						if (bestmetric > metric) { bestmetric = metric; bestcr = cr; }
3260						}
3261	return(bestcr);
3262	}
3263
3264// Finds the three best Sleep Proxies we currently have in our cache
3265mDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3])
3266	{
3267	sps[0] =                      FindSPSInCache1(m, q, mDNSNULL, mDNSNULL);
3268	sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0],   mDNSNULL);
3269	sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0],   sps[1]);
3270	}
3271
3272// Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
3273mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
3274	{
3275	int i;
3276	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3277	}
3278
3279mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
3280	{
3281	int i;
3282	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3283	}
3284
3285mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
3286	{
3287	int i;
3288	mDNSBool v4 = !intf->IPv4Available;		// If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3289	mDNSBool v6 = !intf->IPv6Available;		// If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3290	for (i=0; i<DupSuppressInfoSize; i++)
3291		if (ds[i].InterfaceID == intf->InterfaceID)
3292			{
3293			if      (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
3294			else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
3295			if (v4 && v6) return(mDNStrue);
3296			}
3297	return(mDNSfalse);
3298	}
3299
3300mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
3301	{
3302	int i, j;
3303
3304	// See if we have this one in our list somewhere already
3305	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
3306
3307	// If not, find a slot we can re-use
3308	if (i >= DupSuppressInfoSize)
3309		{
3310		i = 0;
3311		for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
3312			if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
3313				i = j;
3314		}
3315
3316	// Record the info about this query we saw
3317	ds[i].Time        = Time;
3318	ds[i].InterfaceID = InterfaceID;
3319	ds[i].Type        = Type;
3320
3321	return(i);
3322	}
3323
3324mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
3325	{
3326	// If more than 90% of the way to the query time, we should unconditionally accelerate it
3327	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
3328		return(mDNStrue);
3329
3330	// If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3331	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
3332		{
3333		// We forecast: qname (n) type (2) class (2)
3334		mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
3335		const mDNSu32 slot = HashSlot(&q->qname);
3336		const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3337		const CacheRecord *rr;
3338		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3339			if (rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3340				SameNameRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3341				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 &&			// and it is less than half-way to expiry
3342				rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
3343				{
3344				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3345				forecast += 12 + rr->resrec.rdestimate;
3346				if (forecast >= 512) return(mDNSfalse);	// If this would add 512 bytes or more to the packet, don't accelerate
3347				}
3348		return(mDNStrue);
3349		}
3350
3351	return(mDNSfalse);
3352	}
3353
3354// How Standard Queries are generated:
3355// 1. The Question Section contains the question
3356// 2. The Additional Section contains answers we already know, to suppress duplicate responses
3357
3358// How Probe Queries are generated:
3359// 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3360// if some other host is already using *any* records with this name, we want to know about it.
3361// 2. The Authority Section contains the proposed values we intend to use for one or more
3362// of our records with that name (analogous to the Update section of DNS Update packets)
3363// because if some other host is probing at the same time, we each want to know what the other is
3364// planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3365
3366mDNSlocal void SendQueries(mDNS *const m)
3367	{
3368	mDNSu32 slot;
3369	CacheGroup *cg;
3370	CacheRecord *cr;
3371	AuthRecord *ar;
3372	int pktcount = 0;
3373	DNSQuestion *q;
3374	// For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3375	mDNSs32 maxExistingQuestionInterval = 0;
3376	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3377	CacheRecord *KnownAnswerList = mDNSNULL;
3378
3379	// 1. If time for a query, work out what we need to do
3380	if (m->timenow - m->NextScheduledQuery >= 0)
3381		{
3382		CacheRecord *rr;
3383
3384		// We're expecting to send a query anyway, so see if any expiring cache records are close enough
3385		// to their NextRequiredQuery to be worth batching them together with this one
3386		FORALL_CACHERECORDS(slot, cg, rr)
3387			if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3388				if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
3389					{
3390					debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
3391					q = rr->CRActiveQuestion;
3392					ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
3393					// For uDNS queries (TargetQID non-zero) we adjust LastQTime,
3394					// and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
3395					if      (q->Target.type)                        q->SendQNow = mDNSInterfaceMark;	// If targeted query, mark it
3396					else if (!mDNSOpaque16IsZero(q->TargetQID))     { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; }
3397					else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
3398					else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
3399					}
3400
3401		if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
3402			m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
3403
3404		// Scan our list of questions to see which:
3405		//     *WideArea*  queries need to be sent
3406		//     *unicast*   queries need to be sent
3407		//     *multicast* queries we're definitely going to send
3408		if (m->CurrentQuestion)
3409			LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3410		m->CurrentQuestion = m->Questions;
3411		while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3412			{
3413			q = m->CurrentQuestion;
3414			if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
3415			else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
3416				{
3417				mDNSu8       *qptr        = m->omsg.data;
3418				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
3419
3420				// If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
3421				if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
3422				if (q->LocalSocket)
3423					{
3424					InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
3425					qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
3426					mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
3427					q->ThisQInterval    *= QuestionIntervalStep;
3428					}
3429				if (q->ThisQInterval > MaxQuestionInterval)
3430					q->ThisQInterval = MaxQuestionInterval;
3431				q->LastQTime         = m->timenow;
3432				q->LastQTxTime       = m->timenow;
3433				q->RecentAnswerPkts  = 0;
3434				q->SendQNow          = mDNSNULL;
3435				q->ExpectUnicastResp = NonZeroTime(m->timenow);
3436				}
3437			else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
3438				{
3439				//LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3440				q->SendQNow = mDNSInterfaceMark;		// Mark this question for sending on all interfaces
3441				if (maxExistingQuestionInterval < q->ThisQInterval)
3442					maxExistingQuestionInterval = q->ThisQInterval;
3443				}
3444			// If m->CurrentQuestion wasn't modified out from under us, advance it now
3445			// We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
3446			// m->CurrentQuestion point to the right question
3447			if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
3448			}
3449		m->CurrentQuestion = mDNSNULL;
3450
3451		// Scan our list of questions
3452		// (a) to see if there are any more that are worth accelerating, and
3453		// (b) to update the state variables for *all* the questions we're going to send
3454		// Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
3455		// which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
3456		// next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
3457		m->NextScheduledQuery = m->timenow + 0x78000000;
3458		for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3459			{
3460			if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
3461				(!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
3462				{
3463				// If at least halfway to next query time, advance to next interval
3464				// If less than halfway to next query time, then
3465				// treat this as logically a repeat of the last transmission, without advancing the interval
3466				if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
3467					{
3468					//LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
3469					q->SendQNow = mDNSInterfaceMark;	// Mark this question for sending on all interfaces
3470					debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
3471						q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
3472					q->ThisQInterval *= QuestionIntervalStep;
3473					if (q->ThisQInterval > MaxQuestionInterval)
3474						q->ThisQInterval = MaxQuestionInterval;
3475					else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
3476							!(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
3477						{
3478						// Generally don't need to log this.
3479						// It's not especially noteworthy if a query finds no results -- this usually happens for domain
3480						// enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
3481						// and when there simply happen to be no instances of the service the client is looking
3482						// for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
3483						debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3484							q->qname.c, DNSTypeName(q->qtype));
3485						// Sending third query, and no answers yet; time to begin doubting the source
3486						ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
3487						}
3488					}
3489
3490				// Mark for sending. (If no active interfaces, then don't even try.)
3491				q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
3492				if (q->SendOnAll)
3493					{
3494					q->SendQNow  = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
3495					q->LastQTime = m->timenow;
3496					}
3497
3498				// If we recorded a duplicate suppression for this question less than half an interval ago,
3499				// then we consider it recent enough that we don't need to do an identical query ourselves.
3500				ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
3501
3502				q->LastQTxTime      = m->timenow;
3503				q->RecentAnswerPkts = 0;
3504				if (q->RequestUnicast) q->RequestUnicast--;
3505				}
3506			// For all questions (not just the ones we're sending) check what the next scheduled event will be
3507			SetNextQueryTime(m,q);
3508			}
3509		}
3510
3511	// 2. Scan our authoritative RR list to see what probes we might need to send
3512	if (m->timenow - m->NextScheduledProbe >= 0)
3513		{
3514		m->NextScheduledProbe = m->timenow + 0x78000000;
3515
3516		if (m->CurrentRecord)
3517			LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3518		m->CurrentRecord = m->ResourceRecords;
3519		while (m->CurrentRecord)
3520			{
3521			AuthRecord *rr = m->CurrentRecord;
3522			m->CurrentRecord = rr->next;
3523			if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique)	// For all records that are still probing...
3524				{
3525				// 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3526				if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
3527					{
3528					SetNextAnnounceProbeTime(m, rr);
3529					}
3530				// 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3531				else if (rr->ProbeCount)
3532					{
3533					if (rr->AddressProxy.type == mDNSAddrType_IPv4)
3534						{
3535						LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr));
3536						SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b);
3537						}
3538					else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
3539						{
3540						//LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
3541						//SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
3542						}
3543					// Mark for sending. (If no active interfaces, then don't even try.)
3544					rr->SendRNow   = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID;
3545					rr->LastAPTime = m->timenow;
3546					// When we have a late conflict that resets a record to probing state we use a special marker value greater
3547					// than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
3548					if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
3549						rr->ProbeCount = DefaultProbeCountForTypeUnique;
3550					rr->ProbeCount--;
3551					SetNextAnnounceProbeTime(m, rr);
3552					if (rr->ProbeCount == 0)
3553						{
3554						// If this is the last probe for this record, then see if we have any matching records
3555						// on our duplicate list which should similarly have their ProbeCount cleared to zero...
3556						AuthRecord *r2;
3557						for (r2 = m->DuplicateRecords; r2; r2=r2->next)
3558							if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
3559								r2->ProbeCount = 0;
3560						// ... then acknowledge this record to the client.
3561						// We do this optimistically, just as we're about to send the third probe.
3562						// This helps clients that both advertise and browse, and want to filter themselves
3563						// from the browse results list, because it helps ensure that the registration
3564						// confirmation will be delivered 1/4 second *before* the browse "add" event.
3565						// A potential downside is that we could deliver a registration confirmation and then find out
3566						// moments later that there's a name conflict, but applications have to be prepared to handle
3567						// late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
3568						if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
3569						}
3570					}
3571				// else, if it has now finished probing, move it to state Verified,
3572				// and update m->NextScheduledResponse so it will be announced
3573				else
3574					{
3575					if (!rr->Acknowledged) AcknowledgeRecord(m, rr);	// Defensive, just in case it got missed somehow
3576					rr->resrec.RecordType     = kDNSRecordTypeVerified;
3577					rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
3578					rr->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
3579					SetNextAnnounceProbeTime(m, rr);
3580					}
3581				}
3582			}
3583		m->CurrentRecord = m->DuplicateRecords;
3584		while (m->CurrentRecord)
3585			{
3586			AuthRecord *rr = m->CurrentRecord;
3587			m->CurrentRecord = rr->next;
3588			if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
3589				AcknowledgeRecord(m, rr);
3590			}
3591		}
3592
3593	// 3. Now we know which queries and probes we're sending,
3594	// go through our interface list sending the appropriate queries on each interface
3595	while (intf)
3596		{
3597		const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + (mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space);
3598		int OwnerRecordSpace = 0;
3599		AuthRecord *rr;
3600		mDNSu8 *queryptr = m->omsg.data;
3601		mDNSu8 *limit    = m->omsg.data + AbsoluteMaxDNSMessageData;
3602		InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
3603		if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
3604		if (!KnownAnswerList)
3605			{
3606			// Start a new known-answer list
3607			CacheRecord **kalistptr = &KnownAnswerList;
3608			mDNSu32 answerforecast = 0;
3609
3610			// Put query questions in this packet
3611			for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3612				{
3613				if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID))
3614					{
3615					debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3616						SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
3617						q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
3618
3619					// If we're suppressing this question, or we successfully put it, update its SendQNow state
3620					if (SuppressOnThisInterface(q->DupSuppress, intf) ||
3621						BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
3622						q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3623
3624					// Once we've put at least one question, cut back our limit to the normal single-packet size
3625					if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData;
3626					}
3627				}
3628
3629			// Put probe questions in this packet
3630			for (rr = m->ResourceRecords; rr; rr=rr->next)
3631				if (rr->SendRNow == intf->InterfaceID)
3632					{
3633					mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
3634					mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3635					mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
3636					// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3637					mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
3638					if (newptr && newptr + forecast + os < limit)
3639						{
3640						queryptr         = newptr;
3641						limit            = m->omsg.data + NormalMaxDNSMessageData;
3642						answerforecast   = forecast;
3643						OwnerRecordSpace = os;
3644						rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3645						rr->IncludeInProbe = mDNStrue;
3646						verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
3647							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
3648						}
3649					else
3650						{
3651						verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3652						m->omsg.h.numQuestions--;
3653						}
3654					}
3655			}
3656
3657		if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
3658
3659		// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3660		while (KnownAnswerList)
3661			{
3662			CacheRecord *ka = KnownAnswerList;
3663			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
3664			mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit);
3665			if (newptr)
3666				{
3667				verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
3668					ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
3669				queryptr = newptr;
3670				limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace;
3671				KnownAnswerList = ka->NextInKAList;
3672				ka->NextInKAList = mDNSNULL;
3673				}
3674			else
3675				{
3676				// If we ran out of space and we have more than one question in the packet, that's an error --
3677				// we shouldn't have put more than one question if there was a risk of us running out of space.
3678				if (m->omsg.h.numQuestions > 1)
3679					LogMsg("SendQueries:   Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
3680				m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
3681				break;
3682				}
3683			}
3684
3685		for (rr = m->ResourceRecords; rr; rr=rr->next)
3686			if (rr->IncludeInProbe)
3687				{
3688				mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
3689				rr->IncludeInProbe = mDNSfalse;
3690				if (newptr) queryptr = newptr;
3691				else LogMsg("SendQueries:   How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
3692				}
3693
3694		if (OwnerRecordSpace)
3695			{
3696			AuthRecord opt;
3697			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
3698			opt.resrec.rrclass    = NormalMaxDNSMessageData;
3699			opt.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
3700			opt.resrec.rdestimate = sizeof(rdataOPT);
3701			SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
3702			LogSPS("SendQueries putting %s", ARDisplayString(m, &opt));
3703			queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals,
3704				&opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
3705			if (!queryptr)
3706				LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
3707					m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
3708			}
3709
3710		if (queryptr > m->omsg.data)
3711			{
3712			if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
3713				LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
3714			debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
3715				m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
3716				m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
3717				m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
3718			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
3719			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
3720			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3721			if (++pktcount >= 1000)
3722				{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
3723			// There might be more records left in the known answer list, or more questions to send
3724			// on this interface, so go around one more time and try again.
3725			}
3726		else	// Nothing more to send on this interface; go to next
3727			{
3728			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3729			#if MDNS_DEBUGMSGS && 0
3730			const char *const msg = next ? "SendQueries:   Nothing more on %p; moving to %p" : "SendQueries:   Nothing more on %p";
3731			debugf(msg, intf, next);
3732			#endif
3733			intf = next;
3734			}
3735		}
3736
3737	// 4. Final housekeeping
3738
3739	// 4a. Debugging check: Make sure we announced all our records
3740	for (ar = m->ResourceRecords; ar; ar=ar->next)
3741		if (ar->SendRNow)
3742			{
3743			if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
3744				LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
3745			ar->SendRNow = mDNSNULL;
3746			}
3747
3748	// 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3749	// that their interface which went away might come back again, the logic will want to send queries
3750	// for those records, but we can't because their interface isn't here any more, so to keep the
3751	// state machine ticking over we just pretend we did so.
3752	// If the interface does not come back in time, the cache record will expire naturally
3753	FORALL_CACHERECORDS(slot, cg, cr)
3754		if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
3755			{
3756			cr->UnansweredQueries++;
3757			cr->CRActiveQuestion->SendQNow = mDNSNULL;
3758			SetNextCacheCheckTime(m, cr);
3759			}
3760
3761	// 4c. Debugging check: Make sure we sent all our planned questions
3762	// Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3763	// we legitimately couldn't send because the interface is no longer available
3764	for (q = m->Questions; q; q=q->next)
3765		if (q->SendQNow)
3766			{
3767			LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3768			q->SendQNow = mDNSNULL;
3769			}
3770	}
3771
3772mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password)
3773	{
3774	int i, j;
3775	mDNSu8 *ptr = m->omsg.data;
3776
3777	if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
3778
3779	// 0x00 Destination address
3780	for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
3781
3782	// 0x06 Source address (we just use zero -- BPF will fill in real interface address)
3783	for (i=0; i<6; i++) *ptr++ = 0x0;
3784
3785	// 0x0C Ethertype (0x0842)
3786	*ptr++ = 0x08;
3787	*ptr++ = 0x42;
3788
3789	// 0x0E Wakeup sync sequence
3790	for (i=0; i<6; i++) *ptr++ = 0xFF;
3791
3792	// 0x14 Wakeup data
3793	for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
3794
3795	// 0x74 Password
3796	for (i=0; i<6; i++) *ptr++ = password->b[i];
3797
3798	mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
3799
3800	// For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses,
3801	// broadcast is the only reliable way to get a wakeup packet to the intended target machine.
3802	// For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast
3803	// key rotation, unicast is the only way to get a wakeup packet to the intended target machine.
3804	// So, we send one of each, unicast first, then broadcast second.
3805	for (i=0; i<6; i++) m->omsg.data[i] = 0xFF;
3806	mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID);
3807	}
3808
3809// ***************************************************************************
3810#if COMPILER_LIKES_PRAGMA_MARK
3811#pragma mark -
3812#pragma mark - RR List Management & Task Management
3813#endif
3814
3815// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3816// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
3817// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
3818// which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
3819mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
3820	{
3821	DNSQuestion *const q = m->CurrentQuestion;
3822	mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
3823							rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
3824	verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
3825
3826	// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
3827	// may be called twice, once when the record is received, and again when it's time to notify local clients.
3828	// If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3829
3830	rr->LastUsed = m->timenow;
3831	if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
3832		{
3833		if (!rr->CRActiveQuestion) m->rrcache_active++;	// If not previously active, increment rrcache_active count
3834		debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
3835		rr->CRActiveQuestion = q;						// We know q is non-null
3836		SetNextCacheCheckTime(m, rr);
3837		}
3838
3839	// If this is:
3840	// (a) a no-cache add, where we've already done at least one 'QM' query, or
3841	// (b) a normal add, where we have at least one unique-type answer,
3842	// then there's no need to keep polling the network.
3843	// (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3844	// We do this for mDNS questions and uDNS one-shot questions, but not for
3845	// uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
3846	if ((AddRecord == QC_addnocache && !q->RequestUnicast) ||
3847		(AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
3848		if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
3849			{
3850			q->LastQTime        = m->timenow;
3851			q->LastQTxTime      = m->timenow;
3852			q->RecentAnswerPkts = 0;
3853			q->ThisQInterval    = MaxQuestionInterval;
3854			q->RequestUnicast   = mDNSfalse;
3855			debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3856			}
3857
3858	if (rr->DelayDelivery) return;		// We'll come back later when CacheRecordDeferredAdd() calls us
3859
3860	// Only deliver negative answers if client has explicitly requested them
3861	if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)))
3862		if (!AddRecord || !q->ReturnIntermed) return;
3863
3864	// For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
3865	if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed))
3866		{
3867		mDNS_DropLockBeforeCallback();		// Allow client (and us) to legally make mDNS API calls
3868		if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))
3869			{
3870			CacheRecord neg;
3871			MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID);
3872			q->QuestionCallback(m, q, &neg.resrec, AddRecord);
3873			}
3874		else
3875			q->QuestionCallback(m, q, &rr->resrec, AddRecord);
3876		mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
3877		}
3878	// Note: Proceed with caution here because client callback function is allowed to do anything,
3879	// including starting/stopping queries, registering/deregistering records, etc.
3880
3881	if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
3882		{
3883		const mDNSu32 c = q->CNAMEReferrals + 1;
3884		// Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
3885		// and track CNAMEs coming and going, we should really create a subordinate query here,
3886		// which we would subsequently cancel and retract if the CNAME referral record were removed.
3887		// In reality this is such a corner case we'll ignore it until someone actually needs it.
3888		LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
3889		mDNS_StopQuery_internal(m, q);								// Stop old query
3890		AssignDomainName(&q->qname, &rr->resrec.rdata->u.name);		// Update qname
3891		q->qnamehash = DomainNameHashValue(&q->qname);				// and namehash
3892		mDNS_StartQuery_internal(m, q);								// start new query
3893		q->CNAMEReferrals = c;										// and keep count of how many times we've done this
3894		}
3895	}
3896
3897mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
3898	{
3899	rr->DelayDelivery = 0;		// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3900	if (m->CurrentQuestion)
3901		LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3902	m->CurrentQuestion = m->Questions;
3903	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3904		{
3905		DNSQuestion *q = m->CurrentQuestion;
3906		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3907			AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3908		if (m->CurrentQuestion == q)	// If m->CurrentQuestion was not auto-advanced, do it ourselves now
3909			m->CurrentQuestion = q->next;
3910		}
3911	m->CurrentQuestion = mDNSNULL;
3912	}
3913
3914mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
3915	{
3916	const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond;	// See if there are any records expiring within one second
3917	const mDNSs32 start      = m->timenow - 0x10000000;
3918	mDNSs32 delay = start;
3919	CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
3920	const CacheRecord *rr;
3921	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3922		if (threshhold - RRExpireTime(rr) >= 0)		// If we have records about to expire within a second
3923			if (delay - RRExpireTime(rr) < 0)		// then delay until after they've been deleted
3924				delay = RRExpireTime(rr);
3925	if (delay - start > 0) return(NonZeroTime(delay));
3926	else return(0);
3927	}
3928
3929// CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3930// If new questions are created as a result of invoking client callbacks, they will be added to
3931// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3932// rr is a new CacheRecord just received into our cache
3933// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3934// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3935// which may change the record list and/or question list.
3936// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3937mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
3938	{
3939	DNSQuestion *q;
3940
3941	// We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
3942	// counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
3943	for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3944		{
3945		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3946			{
3947			// If this question is one that's actively sending queries, and it's received ten answers within one
3948			// second of sending the last query packet, then that indicates some radical network topology change,
3949			// so reset its exponential backoff back to the start. We must be at least at the eight-second interval
3950			// to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
3951			// because we will anyway send another query within a few seconds. The first reset query is sent out
3952			// randomized over the next four seconds to reduce possible synchronization between machines.
3953			if (q->LastAnswerPktNum != m->PktNum)
3954				{
3955				q->LastAnswerPktNum = m->PktNum;
3956				if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
3957					q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
3958					{
3959					LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
3960						q->qname.c, DNSTypeName(q->qtype), q->RecentAnswerPkts, q->ThisQInterval);
3961					q->LastQTime      = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
3962					q->ThisQInterval  = InitialQuestionInterval;
3963					SetNextQueryTime(m,q);
3964					}
3965				}
3966			verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
3967				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
3968			q->CurrentAnswers++;
3969			q->unansweredQueries = 0;
3970			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
3971			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
3972			if (q->CurrentAnswers > 4000)
3973				{
3974				static int msgcount = 0;
3975				if (msgcount++ < 10)
3976					LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
3977						q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
3978				rr->resrec.rroriginalttl = 0;
3979				rr->UnansweredQueries = MaxUnansweredQueries;
3980				}
3981			}
3982		}
3983
3984	if (!rr->DelayDelivery)
3985		{
3986		if (m->CurrentQuestion)
3987			LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3988		m->CurrentQuestion = m->Questions;
3989		while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3990			{
3991			q = m->CurrentQuestion;
3992			if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3993				AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3994			if (m->CurrentQuestion == q)	// If m->CurrentQuestion was not auto-advanced, do it ourselves now
3995				m->CurrentQuestion = q->next;
3996			}
3997		m->CurrentQuestion = mDNSNULL;
3998		}
3999
4000	SetNextCacheCheckTime(m, rr);
4001	}
4002
4003// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4004// If new questions are created as a result of invoking client callbacks, they will be added to
4005// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4006// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4007// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4008// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4009// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4010// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4011// which may change the record list and/or question list.
4012// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4013mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
4014	{
4015	LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
4016	if (m->CurrentQuestion)
4017		LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4018	m->CurrentQuestion = m->Questions;
4019	// We do this for *all* questions, not stopping when we get to m->NewQuestions,
4020	// since we're not caching the record and we'll get no opportunity to do this later
4021	while (m->CurrentQuestion)
4022		{
4023		DNSQuestion *q = m->CurrentQuestion;
4024		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4025			AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache);	// QC_addnocache means "don't expect remove events for this"
4026		if (m->CurrentQuestion == q)	// If m->CurrentQuestion was not auto-advanced, do it ourselves now
4027			m->CurrentQuestion = q->next;
4028		}
4029	m->CurrentQuestion = mDNSNULL;
4030	}
4031
4032// CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
4033// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
4034// If new questions are created as a result of invoking client callbacks, they will be added to
4035// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4036// rr is an existing cache CacheRecord that just expired and is being deleted
4037// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4038// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
4039// which may change the record list and/or question list.
4040// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4041mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
4042	{
4043	if (m->CurrentQuestion)
4044		LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4045	m->CurrentQuestion = m->Questions;
4046
4047	// We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
4048	// will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
4049	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4050		{
4051		DNSQuestion *q = m->CurrentQuestion;
4052		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4053			{
4054			verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
4055			q->FlappingInterface1 = mDNSNULL;
4056			q->FlappingInterface2 = mDNSNULL;
4057			if (q->CurrentAnswers == 0)
4058				LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4059					q, q->qname.c, DNSTypeName(q->qtype));
4060			else
4061				{
4062				q->CurrentAnswers--;
4063				if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
4064				if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
4065				}
4066			if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
4067				{
4068				if (q->CurrentAnswers == 0)
4069					{
4070					LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
4071						q->qname.c, DNSTypeName(q->qtype));
4072					ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
4073					}
4074				AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
4075				}
4076			}
4077		if (m->CurrentQuestion == q)	// If m->CurrentQuestion was not auto-advanced, do it ourselves now
4078			m->CurrentQuestion = q->next;
4079		}
4080	m->CurrentQuestion = mDNSNULL;
4081	}
4082
4083mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
4084	{
4085#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4086	unsigned int i;
4087	for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
4088#endif
4089	e->next = m->rrcache_free;
4090	m->rrcache_free = e;
4091	m->rrcache_totalused--;
4092	}
4093
4094mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
4095	{
4096	CacheEntity *e = (CacheEntity *)(*cp);
4097	//LogMsg("ReleaseCacheGroup:  Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4098	if ((*cp)->rrcache_tail != &(*cp)->members)
4099		LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4100	//if ((*cp)->name != (domainname*)((*cp)->namestorage))
4101	//	LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4102	if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
4103	(*cp)->name = mDNSNULL;
4104	*cp = (*cp)->next;			// Cut record from list
4105	ReleaseCacheEntity(m, e);
4106	}
4107
4108mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
4109	{
4110	//LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
4111	if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
4112	r->resrec.rdata = mDNSNULL;
4113	ReleaseCacheEntity(m, (CacheEntity *)r);
4114	}
4115
4116// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4117// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4118// callbacks for old records are delivered before callbacks for newer records.
4119mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
4120	{
4121	CacheRecord **rp = &cg->members;
4122
4123	if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4124	m->lock_rrcache = 1;
4125
4126	while (*rp)
4127		{
4128		CacheRecord *const rr = *rp;
4129		mDNSs32 event = RRExpireTime(rr);
4130		if (m->timenow - event >= 0)	// If expired, delete it
4131			{
4132			*rp = rr->next;				// Cut it from the list
4133			verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
4134				m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
4135			if (rr->CRActiveQuestion)	// If this record has one or more active questions, tell them it's going away
4136				{
4137				CacheRecordRmv(m, rr);
4138				m->rrcache_active--;
4139				}
4140			ReleaseCacheRecord(m, rr);
4141			}
4142		else							// else, not expired; see if we need to query
4143			{
4144			if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
4145				event = rr->DelayDelivery;
4146			else
4147				{
4148				if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
4149				if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
4150					{
4151					if (m->timenow - rr->NextRequiredQuery < 0)		// If not yet time for next query
4152						event = rr->NextRequiredQuery;				// then just record when we want the next query
4153					else											// else trigger our question to go out now
4154						{
4155						// Set NextScheduledQuery to timenow so that SendQueries() will run.
4156						// SendQueries() will see that we have records close to expiration, and send FEQs for them.
4157						m->NextScheduledQuery = m->timenow;
4158						// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4159						// which will correctly update m->NextCacheCheck for us.
4160						event = m->timenow + 0x3FFFFFFF;
4161						}
4162					}
4163				}
4164			verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4165				(event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
4166			if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
4167				m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
4168			rp = &rr->next;
4169			}
4170		}
4171	if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
4172	cg->rrcache_tail = rp;
4173	m->lock_rrcache = 0;
4174	}
4175
4176mDNSlocal void AnswerNewQuestion(mDNS *const m)
4177	{
4178	mDNSBool ShouldQueryImmediately = mDNStrue;
4179	DNSQuestion *q = m->NewQuestions;		// Grab the question we're going to answer
4180	const mDNSu32 slot = HashSlot(&q->qname);
4181	CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4182
4183	verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4184
4185	if (cg) CheckCacheExpiration(m, cg);
4186	m->NewQuestions = q->next;				// Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4187
4188	if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4189	// This should be safe, because calling the client's question callback may cause the
4190	// question list to be modified, but should not ever cause the rrcache list to be modified.
4191	// If the client's question callback deletes the question, then m->CurrentQuestion will
4192	// be advanced, and we'll exit out of the loop
4193	m->lock_rrcache = 1;
4194	if (m->CurrentQuestion)
4195		LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4196	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4197
4198	if (q->NoAnswer == NoAnswer_Fail)
4199		{
4200		LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4201		MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
4202		q->NoAnswer = NoAnswer_Normal;		// Temporarily turn off answer suppression
4203		AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
4204		q->NoAnswer = NoAnswer_Fail;		// Restore NoAnswer state
4205		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
4206		}
4207
4208	// If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4209	if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
4210		{
4211		if (m->CurrentRecord)
4212			LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4213		m->CurrentRecord = m->ResourceRecords;
4214		while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4215			{
4216			AuthRecord *rr = m->CurrentRecord;
4217			m->CurrentRecord = rr->next;
4218			if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
4219				if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4220					{
4221					AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
4222					if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4223					}
4224			}
4225		m->CurrentRecord = mDNSNULL;
4226		}
4227
4228	if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
4229
4230	if (m->CurrentQuestion == q)
4231		{
4232		CacheRecord *rr;
4233		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4234			if (SameNameRecordAnswersQuestion(&rr->resrec, q))
4235				{
4236				// SecsSinceRcvd is whole number of elapsed seconds, rounded down
4237				mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
4238				if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
4239					{
4240					LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d",
4241						rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd);
4242					continue;	// Go to next one in loop
4243					}
4244
4245				// If this record set is marked unique, then that means we can reasonably assume we have the whole set
4246				// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4247				if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
4248					ShouldQueryImmediately = mDNSfalse;
4249				q->CurrentAnswers++;
4250				if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4251				if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4252				AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
4253				if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4254				}
4255			else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
4256				ShouldQueryImmediately = mDNSfalse;
4257		}
4258
4259	if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
4260
4261	if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
4262		{
4263		debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4264		q->ThisQInterval  = InitialQuestionInterval;
4265		q->LastQTime      = m->timenow - q->ThisQInterval;
4266		if (mDNSOpaque16IsZero(q->TargetQID))		// For mDNS, spread packets to avoid a burst of simultaneous queries
4267			{
4268			// Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
4269			if (!m->RandomQueryDelay)
4270				m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
4271			q->LastQTime += m->RandomQueryDelay;
4272			}
4273
4274		if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
4275			m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
4276		}
4277
4278	m->CurrentQuestion = mDNSNULL;
4279	m->lock_rrcache = 0;
4280	}
4281
4282// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4283// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
4284mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
4285	{
4286	DNSQuestion *q = m->NewLocalOnlyQuestions;		// Grab the question we're going to answer
4287	m->NewLocalOnlyQuestions = q->next;				// Advance NewLocalOnlyQuestions to the next (if any)
4288
4289	debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4290
4291	if (m->CurrentQuestion)
4292		LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4293	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4294
4295	if (m->CurrentRecord)
4296		LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4297	m->CurrentRecord = m->ResourceRecords;
4298
4299	while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4300		{
4301		AuthRecord *rr = m->CurrentRecord;
4302		m->CurrentRecord = rr->next;
4303		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4304			{
4305			AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
4306			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4307			}
4308		}
4309
4310	m->CurrentQuestion = mDNSNULL;
4311	m->CurrentRecord   = mDNSNULL;
4312	}
4313
4314mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4315	{
4316	CacheEntity *e = mDNSNULL;
4317
4318	if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4319	m->lock_rrcache = 1;
4320
4321	// If we have no free records, ask the client layer to give us some more memory
4322	if (!m->rrcache_free && m->MainCallback)
4323		{
4324		if (m->rrcache_totalused != m->rrcache_size)
4325			LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4326				m->rrcache_totalused, m->rrcache_size);
4327
4328		// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4329		// number of bogus records so that we keep growing our cache until the machine runs out of memory.
4330		// To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
4331		// and we're actively using less than 1/32 of that cache, then we purge all the unused records
4332		// and recycle them, instead of allocating more memory.
4333		if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active)
4334			LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4335				m->rrcache_size, m->rrcache_active);
4336		else
4337			{
4338			mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
4339			m->MainCallback(m, mStatus_GrowCache);
4340			mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
4341			}
4342		}
4343
4344	// If we still have no free records, recycle all the records we can.
4345	// Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4346	if (!m->rrcache_free)
4347		{
4348		mDNSu32 oldtotalused = m->rrcache_totalused;
4349		mDNSu32 slot;
4350		for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4351			{
4352			CacheGroup **cp = &m->rrcache_hash[slot];
4353			while (*cp)
4354				{
4355				CacheRecord **rp = &(*cp)->members;
4356				while (*rp)
4357					{
4358					// Records that answer still-active questions are not candidates for recycling
4359					// Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4360					if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4361						rp=&(*rp)->next;
4362					else
4363						{
4364						CacheRecord *rr = *rp;
4365						*rp = (*rp)->next;			// Cut record from list
4366						ReleaseCacheRecord(m, rr);
4367						}
4368					}
4369				if ((*cp)->rrcache_tail != rp)
4370					verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4371				(*cp)->rrcache_tail = rp;
4372				if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4373				else ReleaseCacheGroup(m, cp);
4374				}
4375			}
4376		LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
4377			oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
4378		}
4379
4380	if (m->rrcache_free)	// If there are records in the free list, take one
4381		{
4382		e = m->rrcache_free;
4383		m->rrcache_free = e->next;
4384		if (++m->rrcache_totalused >= m->rrcache_report)
4385			{
4386			LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
4387			if      (m->rrcache_report <  100) m->rrcache_report += 10;
4388			else if (m->rrcache_report < 1000) m->rrcache_report += 100;
4389			else                               m->rrcache_report += 1000;
4390			}
4391		mDNSPlatformMemZero(e, sizeof(*e));
4392		}
4393
4394	m->lock_rrcache = 0;
4395
4396	return(e);
4397	}
4398
4399mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4400	{
4401	CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4402	if (r)
4403		{
4404		r->resrec.rdata = (RData*)&r->smallrdatastorage;	// By default, assume we're usually going to be using local storage
4405		if (RDLength > InlineCacheRDSize)			// If RDLength is too big, allocate extra storage
4406			{
4407			r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4408			if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4409			else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4410			}
4411		}
4412	return(r);
4413	}
4414
4415mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4416	{
4417	mDNSu16 namelen = DomainNameLength(rr->name);
4418	CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4419	if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4420	cg->next         = m->rrcache_hash[slot];
4421	cg->namehash     = rr->namehash;
4422	cg->members      = mDNSNULL;
4423	cg->rrcache_tail = &cg->members;
4424	cg->name         = (domainname*)cg->namestorage;
4425	//LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4426	//	(namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4427	if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4428	if (!cg->name)
4429		{
4430		LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4431		ReleaseCacheEntity(m, (CacheEntity*)cg);
4432		return(mDNSNULL);
4433		}
4434	AssignDomainName(cg->name, rr->name);
4435
4436	if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4437	m->rrcache_hash[slot] = cg;
4438	if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4439
4440	return(cg);
4441	}
4442
4443mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4444	{
4445	if (m->mDNS_busy != m->mDNS_reentrancy+1)
4446		LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
4447	// Make sure we mark this record as thoroughly expired -- we don't ever want to give
4448	// a positive answer using an expired record (e.g. from an interface that has gone away).
4449	// We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4450	// summary deletion without giving the proper callback to any questions that are monitoring it.
4451	// By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4452	rr->TimeRcvd          = m->timenow - mDNSPlatformOneSecond * 60;
4453	rr->UnansweredQueries = MaxUnansweredQueries;
4454	rr->resrec.rroriginalttl     = 0;
4455	SetNextCacheCheckTime(m, rr);
4456	}
4457
4458mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4459	{
4460	mDNSs32 time;
4461	mDNSPlatformLock(m);
4462	if (m->mDNS_busy)
4463		{
4464		LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4465		if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4466		}
4467
4468	if (m->timenow) time = m->timenow;
4469	else            time = mDNS_TimeNow_NoLock(m);
4470	mDNSPlatformUnlock(m);
4471	return(time);
4472	}
4473
4474// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that
4475// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
4476// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
4477#define SetSPSProxyListChanged(X) do { \
4478	if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
4479	m->SPSProxyListChanged = (X); } while(0)
4480
4481// Called from mDNS_Execute() to expire stale proxy records
4482mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
4483	{
4484	m->CurrentRecord = list;
4485	while (m->CurrentRecord)
4486		{
4487		AuthRecord *rr = m->CurrentRecord;
4488		if (rr->WakeUp.HMAC.l[0])
4489			{
4490			if (m->timenow - rr->TimeExpire < 0)		// If proxy record not expired yet, update m->NextScheduledSPS
4491				{
4492				if (m->NextScheduledSPS - rr->TimeExpire > 0)
4493					m->NextScheduledSPS = rr->TimeExpire;
4494				}
4495			else										// else proxy record expired, so remove it
4496				{
4497				LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
4498					m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr));
4499				SetSPSProxyListChanged(rr->resrec.InterfaceID);
4500				mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
4501				// Don't touch rr after this -- memory may have been free'd
4502				}
4503			}
4504		// Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
4505		// because the list may have been changed in that call.
4506		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
4507			m->CurrentRecord = rr->next;
4508		}
4509	}
4510
4511mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4512	{
4513	mDNS_Lock(m);	// Must grab lock before trying to read m->timenow
4514
4515	if (m->timenow - m->NextScheduledEvent >= 0)
4516		{
4517		int i;
4518
4519		verbosedebugf("mDNS_Execute");
4520		if (m->CurrentQuestion)
4521			LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4522
4523		// 1. If we're past the probe suppression time, we can clear it
4524		if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4525
4526		// 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4527		if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4528
4529		// 3. Purge our cache of stale old records
4530		if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4531			{
4532			mDNSu32 slot;
4533			m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4534			for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4535				{
4536				CacheGroup **cp = &m->rrcache_hash[slot];
4537				while (*cp)
4538					{
4539					CheckCacheExpiration(m, *cp);
4540					if ((*cp)->members) cp=&(*cp)->next;
4541					else ReleaseCacheGroup(m, cp);
4542					}
4543				}
4544			}
4545
4546		if (m->timenow - m->NextScheduledSPS >= 0)
4547			{
4548			m->NextScheduledSPS = m->timenow + 0x3FFFFFFF;
4549			CheckProxyRecords(m, m->DuplicateRecords);	// Clear m->DuplicateRecords first, then m->ResourceRecords
4550			CheckProxyRecords(m, m->ResourceRecords);
4551			}
4552
4553		SetSPSProxyListChanged(mDNSNULL);		// Perform any deferred BPF reconfiguration now
4554
4555		if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
4556			{
4557			m->DelaySleep = 0;
4558			if (m->SleepState == SleepState_Transferring)
4559				{
4560				LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers");
4561				BeginSleepProcessing(m);
4562				}
4563			}
4564
4565		// 4. See if we can answer any of our new local questions from the cache
4566		for (i=0; m->NewQuestions && i<1000; i++)
4567			{
4568			if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4569			AnswerNewQuestion(m);
4570			}
4571		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4572
4573		for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4574		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4575
4576		for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
4577			{
4578			AuthRecord *rr = m->NewLocalRecords;
4579			m->NewLocalRecords = m->NewLocalRecords->next;
4580			AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
4581			}
4582		if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4583
4584		// 5. See what packets we need to send
4585		if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
4586			DiscardDeregistrations(m);
4587		if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
4588			{
4589			// If the platform code is ready, and we're not suppressing packet generation right now
4590			// then send our responses, probes, and questions.
4591			// We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4592			// We send queries next, because there might be final-stage probes that complete their probing here, causing
4593			// them to advance to announcing state, and we want those to be included in any announcements we send out.
4594			// Finally, we send responses, including the previously mentioned records that just completed probing.
4595			m->SuppressSending = 0;
4596
4597			// 6. Send Query packets. This may cause some probing records to advance to announcing state
4598			if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4599			if (m->timenow - m->NextScheduledQuery >= 0)
4600				{
4601				DNSQuestion *q;
4602				LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
4603					m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
4604				m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4605				for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
4606					if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
4607						LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4608				}
4609			if (m->timenow - m->NextScheduledProbe >= 0)
4610				{
4611				LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
4612					m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
4613				m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4614				}
4615
4616			// 7. Send Response packets, including probing records just advanced to announcing state
4617			if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4618			if (m->timenow - m->NextScheduledResponse >= 0)
4619				{
4620				LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4621				m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4622				}
4623			}
4624
4625		// Clear RandomDelay values, ready to pick a new different value next time
4626		m->RandomQueryDelay     = 0;
4627		m->RandomReconfirmDelay = 0;
4628		}
4629
4630	// Note about multi-threaded systems:
4631	// On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4632	// performing mDNS API operations that change our next scheduled event time.
4633	//
4634	// On multi-threaded systems (like the current Windows implementation) that have a single main thread
4635	// calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4636	// of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4637	// signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4638	// more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4639	// in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4640	// does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4641	// without blocking. This avoids the race condition between the signal from the other thread arriving
4642	// just *before* or just *after* the main thread enters the blocking primitive.
4643	//
4644	// On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4645	// with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4646	// set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4647	// callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4648	// by the time it gets to the timer callback function).
4649
4650#ifndef UNICAST_DISABLED
4651	uDNS_Execute(m);
4652#endif
4653	mDNS_Unlock(m);		// Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4654	return(m->NextScheduledEvent);
4655	}
4656
4657mDNSlocal void SuspendLLQs(mDNS *m)
4658	{
4659	DNSQuestion *q;
4660	for (q = m->Questions; q; q = q->next)
4661		if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established)
4662			{ q->ReqLease = 0; sendLLQRefresh(m, q); }
4663	}
4664
4665// ActivateUnicastQuery() is called from three places:
4666// 1. When a new question is created
4667// 2. On wake from sleep
4668// 3. When the DNS configuration changes
4669// In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
4670// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
4671mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
4672	{
4673	// For now this AutoTunnel stuff is specific to Mac OS X.
4674	// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
4675#if APPLE_OSX_mDNSResponder
4676	// Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
4677	// Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
4678	// caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
4679	// To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
4680	// returns results for both at the same time.
4681	if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
4682		{
4683		question->NoAnswer = NoAnswer_Suspended;
4684		AddNewClientTunnel(m, question);
4685		return;
4686		}
4687#endif // APPLE_OSX_mDNSResponder
4688
4689	if (!question->DuplicateOf)
4690		{
4691		debugf("ActivateUnicastQuery: %##s %s%s%s",
4692			question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
4693		if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
4694		if (question->LongLived)
4695			{
4696			question->state = LLQ_InitialRequest;
4697			question->id = zeroOpaque64;
4698			question->servPort = zeroIPPort;
4699			if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
4700			}
4701		if (ScheduleImmediately)
4702			{
4703			question->ThisQInterval = InitialQuestionInterval;
4704			question->LastQTime     = m->timenow - question->ThisQInterval;
4705			SetNextQueryTime(m, question);
4706			}
4707		}
4708	}
4709
4710mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
4711	{
4712	DNSQuestion *q;
4713
4714#ifndef UNICAST_DISABLED
4715	// Retrigger all our uDNS questions
4716	if (m->CurrentQuestion)
4717		LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
4718	m->CurrentQuestion = m->Questions;
4719	while (m->CurrentQuestion)
4720		{
4721		q = m->CurrentQuestion;
4722		m->CurrentQuestion = m->CurrentQuestion->next;
4723		if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
4724		}
4725#endif
4726
4727	// Retrigger all our mDNS questions
4728	for (q = m->Questions; q; q=q->next)				// Scan our list of questions
4729		if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
4730			{
4731			q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
4732			q->RequestUnicast   = 2;						// Set to 2 because is decremented once *before* we check it
4733			q->LastQTime        = m->timenow - q->ThisQInterval;
4734			q->RecentAnswerPkts = 0;
4735			ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4736			m->NextScheduledQuery = m->timenow;
4737			}
4738	}
4739
4740// ***************************************************************************
4741#if COMPILER_LIKES_PRAGMA_MARK
4742#pragma mark -
4743#pragma mark - Power Management (Sleep/Wake)
4744#endif
4745
4746mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
4747	{
4748	const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space;
4749	const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace;
4750	const int sps = intf->NextSPSAttempt / 3;
4751	AuthRecord *rr;
4752
4753	if (!intf->SPSAddr[sps].type)
4754		{
4755		intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
4756		if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
4757			m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
4758		LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c);
4759		goto exit;
4760		}
4761
4762	// Mark our mDNS records (not unicast records) for transfer to SPS
4763	if (mDNSOpaque16IsZero(id))
4764		for (rr = m->ResourceRecords; rr; rr=rr->next)
4765			if (rr->resrec.RecordType > kDNSRecordTypeDeregistering)
4766				if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
4767					rr->SendRNow = mDNSInterfaceMark;	// mark it now
4768
4769	while (1)
4770		{
4771		mDNSu8 *p = m->omsg.data;
4772		// To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates.
4773		// For now we follow that same logic for SPS registrations too.
4774		// If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our
4775		// initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet.
4776		InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags);
4777
4778		for (rr = m->ResourceRecords; rr; rr=rr->next)
4779			if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0))
4780				{
4781				mDNSu8 *newptr;
4782				const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace;
4783				if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
4784					rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the 'unique' bit so PutResourceRecord will set it
4785				newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
4786				rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear 'unique' bit back to normal state
4787				if (!newptr)
4788					LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr));
4789				else
4790					{
4791					LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr));
4792					rr->SendRNow       = mDNSNULL;
4793					rr->ThisAPInterval = mDNSPlatformOneSecond;
4794					rr->LastAPTime     = m->timenow;
4795					rr->updateid       = m->omsg.h.id;
4796					if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4797						m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
4798					p = newptr;
4799					}
4800				}
4801
4802		if (!m->omsg.h.mDNS_numUpdates) break;
4803		else
4804			{
4805			AuthRecord opt;
4806			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
4807			opt.resrec.rrclass    = NormalMaxDNSMessageData;
4808			opt.resrec.rdlength   = sizeof(rdataOPT) * 2;	// Two options in this OPT record
4809			opt.resrec.rdestimate = sizeof(rdataOPT) * 2;
4810			opt.resrec.rdata->u.opt[0].opt              = kDNSOpt_Lease;
4811			opt.resrec.rdata->u.opt[0].optlen           = DNSOpt_LeaseData_Space - 4;
4812			opt.resrec.rdata->u.opt[0].u.updatelease    = DEFAULT_UPDATE_LEASE;
4813			SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]);
4814			LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt));
4815			p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
4816			if (!p)
4817				LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt));
4818			else
4819				{
4820				mStatus err;
4821				LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
4822					mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
4823				// if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID;	// For simulating packet loss
4824				err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL);
4825				if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
4826				if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1)
4827					{
4828					LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c);
4829					intf->NetWakeResolve[sps].qtype = kDNSType_A;
4830					mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]);
4831					return;
4832					}
4833				}
4834			}
4835		}
4836
4837	intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10;		// If successful, update NextSPSAttemptTime
4838
4839exit:
4840	if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++;
4841	}
4842
4843// RetrySPSRegistrations is called from SendResponses, with the lock held
4844mDNSlocal void RetrySPSRegistrations(mDNS *const m)
4845	{
4846	AuthRecord *rr;
4847	NetworkInterfaceInfo *intf;
4848
4849	// First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10
4850	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4851		if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10)
4852			intf->NextSPSAttemptTime++;
4853
4854	// Retry any record registrations that are due
4855	for (rr = m->ResourceRecords; rr; rr=rr->next)
4856		if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
4857			for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4858				if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID)
4859					{
4860					LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr));
4861					SendSPSRegistration(m, intf, rr->updateid);
4862					}
4863
4864	// For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt
4865	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4866		if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8)
4867			intf->NextSPSAttempt++;
4868	}
4869
4870mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
4871	{
4872	NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext;
4873	int sps = question - intf->NetWakeResolve;
4874	(void)m;			// Unused
4875	LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer));
4876
4877	if (!AddRecord) return;												// Don't care about REMOVE events
4878	if (answer->rrtype != question->qtype) return;						// Don't care about CNAMEs
4879
4880	mDNS_StopQuery(m, question);
4881	question->ThisQInterval = -1;
4882
4883	if (answer->rrtype == kDNSType_SRV)
4884		{
4885		intf->SPSPort[sps] = answer->rdata->u.srv.port;
4886		AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
4887		question->qtype = kDNSType_AAAA;
4888		mDNS_StartQuery(m, question);
4889		}
4890	else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
4891		{
4892		intf->SPSAddr[sps].type = mDNSAddrType_IPv6;
4893		intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6;
4894		mDNS_Lock(m);
4895		if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID);	// If we're ready for this result, use it now
4896		mDNS_Unlock(m);
4897		}
4898	else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0)	// If negative answer for IPv6, look for IPv4 addresses instead
4899		{
4900		LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c);
4901		question->qtype = kDNSType_A;
4902		mDNS_StartQuery(m, question);
4903		}
4904	else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr))
4905		{
4906		intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
4907		intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
4908		mDNS_Lock(m);
4909		if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID);	// If we're ready for this result, use it now
4910		mDNS_Unlock(m);
4911		}
4912	}
4913
4914mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m)
4915	{
4916	AuthRecord *rr;
4917	for (rr = m->ResourceRecords; rr; rr=rr->next)
4918		if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort))
4919			return mDNStrue;
4920	return mDNSfalse;
4921	}
4922
4923// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep
4924mDNSlocal void BeginSleepProcessing(mDNS *const m)
4925	{
4926	const CacheRecord *sps[3] = { mDNSNULL };
4927
4928	m->NextScheduledSPRetry = m->timenow;
4929
4930	if      (!m->SystemWakeOnLANEnabled)                  LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
4931	else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services");
4932	else	// If we have at least one advertised service
4933		{
4934		NetworkInterfaceInfo *intf;
4935		for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
4936			{
4937			if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname);
4938			else
4939				{
4940				FindSPSInCache(m, &intf->NetWakeBrowse, sps);
4941				if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval);
4942				else
4943					{
4944					int i;
4945					intf->NextSPSAttempt = 0;
4946					intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond;
4947					// Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above
4948					for (i=0; i<3; i++)
4949						{
4950#if ForceAlerts
4951						if (intf->SPSAddr[i].type)
4952							{ LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; }
4953						if (intf->NetWakeResolve[i].ThisQInterval >= 0)
4954							{ LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; }
4955#endif
4956						intf->SPSAddr[i].type = mDNSAddrType_None;
4957						if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]);
4958						intf->NetWakeResolve[i].ThisQInterval = -1;
4959						if (sps[i])
4960							{
4961							LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i]));
4962							mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf);
4963							intf->NetWakeResolve[i].ReturnIntermed = mDNStrue;
4964							mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]);
4965							}
4966						}
4967					}
4968				}
4969			}
4970		}
4971
4972	if (!sps[0])	// If we didn't find even one Sleep Proxy
4973		{
4974		AuthRecord *rr;
4975		LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server");
4976		m->SleepState = SleepState_Sleeping;
4977
4978#ifndef UNICAST_DISABLED
4979		SleepServiceRegistrations(m);
4980		SleepRecordRegistrations(m);	// If we have no SPS, need to deregister our uDNS records
4981#endif
4982
4983		// Mark all the records we need to deregister and send them
4984		for (rr = m->ResourceRecords; rr; rr=rr->next)
4985			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
4986				rr->ImmedAnswer = mDNSInterfaceMark;
4987		SendResponses(m);
4988		}
4989	}
4990
4991// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
4992// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
4993// Normally, the platform support layer below mDNSCore should call this, not the client layer above.
4994mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
4995	{
4996	AuthRecord *rr;
4997
4998	mDNS_Lock(m);
4999
5000	LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
5001
5002	if (sleep && !m->SleepState)		// Going to sleep
5003		{
5004		// If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
5005		if (m->SPSSocket)
5006			{
5007			mDNSu8 oldstate = m->SPSState;
5008			mDNS_DropLockBeforeCallback();		// mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5009			m->SPSState = 2;
5010			if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords);
5011			mDNS_ReclaimLockAfterCallback();
5012			}
5013
5014		m->SleepState = SleepState_Transferring;
5015		if (m->SystemWakeOnLANEnabled && m->DelaySleep)
5016			{
5017			// If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
5018			LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
5019			m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10;
5020			}
5021		else
5022			{
5023			m->DelaySleep = 0;
5024			m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10;
5025			BeginSleepProcessing(m);
5026			}
5027
5028#ifndef UNICAST_DISABLED
5029		SuspendLLQs(m);
5030#endif
5031		LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
5032			m->SleepState == SleepState_Transferring ? "Transferring" :
5033			m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?", m->SleepSeqNum);
5034		}
5035	else if (!sleep)		// Waking up
5036		{
5037		mDNSu32 slot;
5038		CacheGroup *cg;
5039		CacheRecord *cr;
5040		NetworkInterfaceInfo *intf;
5041
5042		// If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
5043		if (m->SleepState != SleepState_Awake)
5044			{
5045			m->SleepState = SleepState_Awake;
5046			m->SleepSeqNum++;
5047			// If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake)
5048			// then we enforce a minimum delay of 16 seconds before we begin sleep processing.
5049			// This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc.,
5050			// before we make our determination of whether there's a Sleep Proxy out there we should register with.
5051			m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16);
5052			}
5053
5054		if (m->SPSState == 3)
5055			{
5056			mDNS_DropLockBeforeCallback();		// mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
5057			m->SPSState = 0;
5058			mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
5059			mDNS_ReclaimLockAfterCallback();
5060			}
5061
5062		// In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
5063		// on wake we go through our record list and clear updateid back to zero
5064		for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID;
5065
5066		// ... and the same for NextSPSAttempt
5067		for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
5068
5069		// Restart unicast and multicast queries
5070		mDNSCoreRestartQueries(m);
5071
5072		// and reactivtate service registrations
5073		m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
5074		LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
5075
5076		// 2. Re-validate our cache records
5077		m->NextCacheCheck  = m->timenow;
5078		FORALL_CACHERECORDS(slot, cg, cr)
5079			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
5080
5081		// 3. Retrigger probing and announcing for all our authoritative records
5082		for (rr = m->ResourceRecords; rr; rr=rr->next)
5083			if (AuthRecord_uDNS(rr))
5084				{
5085				ActivateUnicastRegistration(m, rr);
5086				}
5087			else
5088				{
5089				if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
5090				rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
5091				rr->AnnounceCount  = InitialAnnounceCount;
5092				InitializeLastAPTime(m, rr);
5093				}
5094
5095		// 4. Refresh NAT mappings
5096		// We don't want to have to assume that all hardware can necessarily keep accurate
5097		// track of passage of time while asleep, so on wake we refresh our NAT mappings
5098		m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
5099		m->retryGetAddr         = m->timenow;
5100		RecreateNATMappings(m);
5101		}
5102
5103	mDNS_Unlock(m);
5104	}
5105
5106mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m)
5107	{
5108	DNSQuestion *q;
5109	AuthRecord *rr;
5110	ServiceRecordSet *srs;
5111	NetworkInterfaceInfo *intf;
5112
5113	mDNS_Lock(m);
5114
5115	if (m->NextScheduledSPRetry - m->timenow > 0) goto notready;
5116
5117	m->NextScheduledSPRetry = m->timenow + 0x40000000UL;
5118
5119	if (m->DelaySleep) goto notready;
5120
5121	// See if we might need to retransmit any lost Sleep Proxy Registrations
5122	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5123		if (intf->NextSPSAttempt >= 0)
5124			{
5125			if (m->timenow - intf->NextSPSAttemptTime >= 0)
5126				{
5127				LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt);
5128				SendSPSRegistration(m, intf, zeroID);
5129				}
5130			else
5131				if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0)
5132					m->NextScheduledSPRetry = intf->NextSPSAttemptTime;
5133			}
5134
5135	// Scan list of private LLQs, and make sure they've all completed their handshake with the server
5136	for (q = m->Questions; q; q = q->next)
5137		if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
5138			{
5139			LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5140			goto notready;
5141			}
5142
5143	// Scan list of interfaces
5144	for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
5145		if (intf->NetWakeResolve[0].ThisQInterval >= 0)
5146			{
5147			LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
5148			goto notready;
5149			}
5150
5151	// Scan list of registered records
5152	for (rr = m->ResourceRecords; rr; rr = rr->next)
5153		{
5154		if (AuthRecord_uDNS(rr))
5155			{
5156			if (rr->state == regState_Refresh && rr->tcp)
5157				{ LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
5158			}
5159		else
5160			{
5161			if (!mDNSOpaque16IsZero(rr->updateid))
5162				{ LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
5163			}
5164		}
5165
5166	// Scan list of registered services
5167	for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
5168		if (srs->state == regState_NoTarget && srs->tcp) goto notready;
5169
5170	mDNS_Unlock(m);
5171	return mDNStrue;
5172
5173notready:
5174	mDNS_Unlock(m);
5175	return mDNSfalse;
5176	}
5177
5178mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
5179	{
5180	AuthRecord *ar;
5181
5182	// Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other
5183	// failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed.
5184	// E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
5185	// and if that happens we don't want to just give up and go back to sleep and never try again.
5186	mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond);		// Sleep for at most 120 minutes
5187
5188	NATTraversalInfo *nat;
5189	for (nat = m->NATTraversals; nat; nat=nat->next)
5190		if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4)
5191			{
5192			mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10;		// Wake up when 90% of the way to the expiry time
5193			if (e - t > 0) e = t;
5194			LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
5195				nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
5196				mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
5197				nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
5198				nat->retryInterval / mDNSPlatformOneSecond,
5199				nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
5200				(t - now) / mDNSPlatformOneSecond);
5201			}
5202
5203	// This loop checks both the time we need to renew wide-area registrations,
5204	// and the time we need to renew Sleep Proxy registrations
5205	for (ar = m->ResourceRecords; ar; ar = ar->next)
5206		if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4)
5207			{
5208			mDNSs32 t = ar->expire - (ar->expire - now) / 10;		// Wake up when 90% of the way to the expiry time
5209			if (e - t > 0) e = t;
5210			LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
5211				ar, ar->ThisAPInterval / mDNSPlatformOneSecond,
5212				(ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
5213				ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
5214				(t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar));
5215			}
5216
5217	return(e - now);
5218	}
5219
5220// ***************************************************************************
5221#if COMPILER_LIKES_PRAGMA_MARK
5222#pragma mark -
5223#pragma mark - Packet Reception Functions
5224#endif
5225
5226#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
5227
5228mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
5229	const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
5230	{
5231	mDNSu8          *responseptr     = response->data;
5232	const mDNSu8    *const limit     = response->data + sizeof(response->data);
5233	const mDNSu8    *ptr             = query->data;
5234	AuthRecord  *rr;
5235	mDNSu32          maxttl = 0x70000000;
5236	int i;
5237
5238	// Initialize the response fields so we can answer the questions
5239	InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
5240
5241	// ***
5242	// *** 1. Write out the list of questions we are actually going to answer with this packet
5243	// ***
5244	if (LegacyQuery)
5245		{
5246		maxttl = 10;
5247		for (i=0; i<query->h.numQuestions; i++)						// For each question...
5248			{
5249			DNSQuestion q;
5250			ptr = getQuestion(query, ptr, end, InterfaceID, &q);	// get the question...
5251			if (!ptr) return(mDNSNULL);
5252
5253			for (rr=ResponseRecords; rr; rr=rr->NextResponse)		// and search our list of proposed answers
5254				{
5255				if (rr->NR_AnswerTo == ptr)							// If we're going to generate a record answering this question
5256					{												// then put the question in the question section
5257					responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
5258					if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
5259					break;		// break out of the ResponseRecords loop, and go on to the next question
5260					}
5261				}
5262			}
5263
5264		if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
5265		}
5266
5267	// ***
5268	// *** 2. Write Answers
5269	// ***
5270	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5271		if (rr->NR_AnswerTo)
5272			{
5273			mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec,
5274				maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5275			if (p) responseptr = p;
5276			else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
5277			}
5278
5279	// ***
5280	// *** 3. Write Additionals
5281	// ***
5282	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5283		if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
5284			{
5285			mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec,
5286				maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl);
5287			if (p) responseptr = p;
5288			else debugf("GenerateUnicastResponse: No more space for additionals");
5289			}
5290
5291	return(responseptr);
5292	}
5293
5294// AuthRecord *our is our Resource Record
5295// CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
5296// Returns 0 if there is no conflict
5297// Returns +1 if there was a conflict and we won
5298// Returns -1 if there was a conflict and we lost and have to rename
5299mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt)
5300	{
5301	mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
5302	mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
5303	if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
5304	if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
5305
5306	ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
5307	pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
5308	while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
5309	if (ourptr >= ourend && pktptr >= pktend) return(0);			// If data identical, not a conflict
5310
5311	if (ourptr >= ourend) return(-1);								// Our data ran out first; We lost
5312	if (pktptr >= pktend) return(+1);								// Packet data ran out first; We won
5313	if (*pktptr > *ourptr) return(-1);								// Our data is numerically lower; We lost
5314	if (*pktptr < *ourptr) return(+1);								// Packet data is numerically lower; We won
5315
5316	LogMsg("CompareRData ERROR: Invalid state");
5317	return(-1);
5318	}
5319
5320// See if we have an authoritative record that's identical to this packet record,
5321// whose canonical DependentOn record is the specified master record.
5322// The DependentOn pointer is typically used for the TXT record of service registrations
5323// It indicates that there is no inherent conflict detection for the TXT record
5324// -- it depends on the SRV record to resolve name conflicts
5325// If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
5326// pointer chain (if any) to make sure we reach the canonical DependentOn record
5327// If the record has no DependentOn, then just return that record's pointer
5328// Returns NULL if we don't have any local RRs that are identical to the one from the packet
5329mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
5330	{
5331	const AuthRecord *r1;
5332	for (r1 = m->ResourceRecords; r1; r1=r1->next)
5333		{
5334		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
5335			{
5336			const AuthRecord *r2 = r1;
5337			while (r2->DependentOn) r2 = r2->DependentOn;
5338			if (r2 == master) return(mDNStrue);
5339			}
5340		}
5341	for (r1 = m->DuplicateRecords; r1; r1=r1->next)
5342		{
5343		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
5344			{
5345			const AuthRecord *r2 = r1;
5346			while (r2->DependentOn) r2 = r2->DependentOn;
5347			if (r2 == master) return(mDNStrue);
5348			}
5349		}
5350	return(mDNSfalse);
5351	}
5352
5353// Find the canonical RRSet pointer for this RR received in a packet.
5354// If we find any identical AuthRecord in our authoritative list, then follow its RRSet
5355// pointers (if any) to make sure we return the canonical member of this name/type/class
5356// Returns NULL if we don't have any local RRs that are identical to the one from the packet
5357mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
5358	{
5359	const AuthRecord *rr;
5360	for (rr = m->ResourceRecords; rr; rr=rr->next)
5361		{
5362		if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
5363			{
5364			while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
5365			return(rr);
5366			}
5367		}
5368	return(mDNSNULL);
5369	}
5370
5371// PacketRRConflict is called when we've received an RR (pktrr) which has the same name
5372// as one of our records (our) but different rdata.
5373// 1. If our record is not a type that's supposed to be unique, we don't care.
5374// 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
5375// 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
5376//     points to our record, ignore this conflict (e.g. the packet record matches one of our
5377//     TXT records, and that record is marked as dependent on 'our', its SRV record).
5378// 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
5379//    are members of the same RRSet, then this is not a conflict.
5380mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
5381	{
5382	// If not supposed to be unique, not a conflict
5383	if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
5384
5385	// If a dependent record, not a conflict
5386	if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
5387	else
5388		{
5389		// If the pktrr matches a member of ourset, not a conflict
5390		const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
5391		const AuthRecord *pktset = FindRRSet(m, pktrr);
5392		if (pktset == ourset) return(mDNSfalse);
5393
5394		// For records we're proxying, where we don't know the full
5395		// relationship between the records, having any matching record
5396		// in our AuthRecords list is sufficient evidence of non-conflict
5397		if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse);
5398		}
5399
5400	// Okay, this is a conflict
5401	return(mDNStrue);
5402	}
5403
5404// Note: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
5405// the record list and/or question list.
5406// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
5407mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
5408	DNSQuestion *q, AuthRecord *our)
5409	{
5410	int i;
5411	const mDNSu8 *ptr = LocateAuthorities(query, end);
5412	mDNSBool FoundUpdate = mDNSfalse;
5413
5414	for (i = 0; i < query->h.numAuthorities; i++)
5415		{
5416		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
5417		if (!ptr) break;
5418		if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5419			{
5420			FoundUpdate = mDNStrue;
5421			if (PacketRRConflict(m, our, &m->rec.r))
5422				{
5423				int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
5424				if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
5425				if (!result) result = CompareRData(our, &m->rec.r);
5426				if (result)
5427					{
5428					const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: ";
5429					LogMsg("ResolveSimultaneousProbe: Pkt Record:        %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5430					LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s",   our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
5431					}
5432				// If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network.
5433				// Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
5434				// If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
5435				if (result < 0)
5436					{
5437					m->SuppressProbes   = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
5438					our->ProbeCount     = DefaultProbeCountForTypeUnique;
5439					our->AnnounceCount  = InitialAnnounceCount;
5440					InitializeLastAPTime(m, our);
5441					goto exit;
5442					}
5443				}
5444#if 0
5445			else
5446				{
5447				LogMsg("ResolveSimultaneousProbe: Pkt Record:      %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5448				LogMsg("ResolveSimultaneousProbe: Our Record ign:  %08lX %s", our->resrec.rdatahash,     ARDisplayString(m, our));
5449				}
5450#endif
5451			}
5452		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5453		}
5454	if (!FoundUpdate)
5455		LogInfo("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
5456exit:
5457	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5458	}
5459
5460mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr)
5461	{
5462	mDNSu32 slot = HashSlot(pktrr->name);
5463	CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
5464	CacheRecord *rr;
5465	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5466		if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
5467	return(rr);
5468	}
5469
5470// Called from ProcessQuery when we get an mDNS packet with an owner record in it
5471mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
5472	{
5473	m->CurrentRecord = thelist;
5474	while (m->CurrentRecord)
5475		{
5476		AuthRecord *const rr = m->CurrentRecord;
5477		if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
5478			if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60)
5479				{
5480				LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
5481					m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
5482				mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
5483				SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
5484				}
5485		// Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
5486		// because the list may have been changed in that call.
5487		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
5488			m->CurrentRecord = rr->next;
5489		}
5490	}
5491
5492// ProcessQuery examines a received query to see if we have any answers to give
5493mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
5494	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
5495	mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
5496	{
5497	mDNSBool      FromLocalSubnet    = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5498	AuthRecord   *ResponseRecords    = mDNSNULL;
5499	AuthRecord  **nrp                = &ResponseRecords;
5500	CacheRecord  *ExpectedAnswers    = mDNSNULL;			// Records in our cache we expect to see updated
5501	CacheRecord **eap                = &ExpectedAnswers;
5502	DNSQuestion  *DupQuestions       = mDNSNULL;			// Our questions that are identical to questions in this packet
5503	DNSQuestion **dqp                = &DupQuestions;
5504	mDNSs32       delayresponse      = 0;
5505	mDNSBool      SendLegacyResponse = mDNSfalse;
5506	const mDNSu8 *ptr;
5507	mDNSu8       *responseptr        = mDNSNULL;
5508	AuthRecord   *rr;
5509	int i;
5510
5511	// ***
5512	// *** 1. Look in Additional Section for an OPT record
5513	// ***
5514	ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space);
5515	if (ptr)
5516		{
5517		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec);
5518		if (m->rec.r.resrec.rrtype == kDNSType_OPT)
5519			{
5520			const rdataOPT *opt;
5521			const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
5522			// Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
5523			// delete all our own AuthRecords (which are identified by having zero MAC tags on them).
5524			for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++)
5525				if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0])
5526					{
5527					ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords);
5528					ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords);
5529					}
5530			}
5531		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5532		}
5533
5534	// ***
5535	// *** 2. Parse Question Section and mark potential answers
5536	// ***
5537	ptr = query->data;
5538	for (i=0; i<query->h.numQuestions; i++)						// For each question...
5539		{
5540		mDNSBool QuestionNeedsMulticastResponse;
5541		int NumAnswersForThisQuestion = 0;
5542		AuthRecord *NSECAnswer = mDNSNULL;
5543		DNSQuestion pktq, *q;
5544		ptr = getQuestion(query, ptr, end, InterfaceID, &pktq);	// get the question...
5545		if (!ptr) goto exit;
5546
5547		// The only queries that *need* a multicast response are:
5548		// * Queries sent via multicast
5549		// * from port 5353
5550		// * that don't have the kDNSQClass_UnicastResponse bit set
5551		// These queries need multicast responses because other clients will:
5552		// * suppress their own identical questions when they see these questions, and
5553		// * expire their cache records if they don't see the expected responses
5554		// For other queries, we may still choose to send the occasional multicast response anyway,
5555		// to keep our neighbours caches warm, and for ongoing conflict detection.
5556		QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
5557		// Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
5558		pktq.qclass &= ~kDNSQClass_UnicastResponse;
5559
5560		// Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
5561		// can result in user callbacks which may change the record list and/or question list.
5562		// Also note: we just mark potential answer records here, without trying to build the
5563		// "ResponseRecords" list, because we don't want to risk user callbacks deleting records
5564		// from that list while we're in the middle of trying to build it.
5565		if (m->CurrentRecord)
5566			LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
5567		m->CurrentRecord = m->ResourceRecords;
5568		while (m->CurrentRecord)
5569			{
5570			rr = m->CurrentRecord;
5571			m->CurrentRecord = rr->next;
5572			if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
5573				{
5574				if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
5575					{
5576					if (rr->resrec.RecordType == kDNSRecordTypeUnique)
5577						ResolveSimultaneousProbe(m, query, end, &pktq, rr);
5578					else if (ResourceRecordIsValidAnswer(rr))
5579						{
5580						NumAnswersForThisQuestion++;
5581						// Note: We should check here if this is a probe-type query, and if so, generate an immediate
5582						// unicast answer back to the source, because timeliness in answering probes is important.
5583
5584						// Notes:
5585						// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
5586						// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
5587						// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
5588						// If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
5589						// but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link)
5590						// then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
5591						if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
5592							{
5593							// We only mark this question for sending if it is at least one second since the last time we multicast it
5594							// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
5595							// This is to guard against the case where someone blasts us with queries as fast as they can.
5596							if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
5597								(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
5598								rr->NR_AnswerTo = (mDNSu8*)~0;
5599							}
5600						else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
5601						}
5602					}
5603				else if (rr->resrec.RecordType == kDNSRecordTypeVerified)
5604					{
5605					// If we don't have any answers for this question, but we do own another record with the same name,
5606					// then mark it to generate an NSEC record on this interface
5607					if (!NSECAnswer) NSECAnswer = rr;
5608					}
5609				}
5610			}
5611
5612		if (NumAnswersForThisQuestion == 0 && NSECAnswer)
5613			{
5614			NumAnswersForThisQuestion++;
5615			NSECAnswer->SendNSECNow = InterfaceID;
5616			m->NextScheduledResponse = m->timenow;
5617			}
5618
5619		// If we couldn't answer this question, someone else might be able to,
5620		// so use random delay on response to reduce collisions
5621		if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
5622
5623#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5624		if (QuestionNeedsMulticastResponse)
5625#else
5626		// We only do the following accelerated cache expiration and duplicate question suppression processing
5627		// for non-truncated multicast queries with multicast responses.
5628		// For any query generating a unicast response we don't do this because we can't assume we will see the response.
5629		// For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
5630		// known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
5631		if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC))
5632#endif
5633			{
5634			const mDNSu32 slot = HashSlot(&pktq.qname);
5635			CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
5636			CacheRecord *cr;
5637
5638			// Make a list indicating which of our own cache records we expect to see updated as a result of this query
5639			// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5640#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5641			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5642#endif
5643				for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
5644					if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
5645						if (!cr->NextInKAList && eap != &cr->NextInKAList)
5646							{
5647							*eap = cr;
5648							eap = &cr->NextInKAList;
5649#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5650							if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
5651								{
5652								// Although MPUnansweredQ is only really used for multi-packet query processing,
5653								// we increment it for both single-packet and multi-packet queries, so that it stays in sync
5654								// with the MPUnansweredKA value, which by necessity is incremented for both query types.
5655								cr->MPUnansweredQ++;
5656								cr->MPLastUnansweredQT = m->timenow;
5657								cr->MPExpectingKA = mDNStrue;
5658								}
5659#endif
5660							}
5661
5662			// Check if this question is the same as any of mine.
5663			// We only do this for non-truncated queries. Right now it would be too complicated to try
5664			// to keep track of duplicate suppression state between multiple packets, especially when we
5665			// can't guarantee to receive all of the Known Answer packets that go with a particular query.
5666#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5667			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5668#endif
5669				for (q = m->Questions; q; q=q->next)
5670					if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
5671						if (!q->InterfaceID || q->InterfaceID == InterfaceID)
5672							if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
5673								if (q->qtype == pktq.qtype &&
5674									q->qclass == pktq.qclass &&
5675									q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
5676									{ *dqp = q; dqp = &q->NextInDQList; }
5677			}
5678		}
5679
5680	// ***
5681	// *** 3. Now we can safely build the list of marked answers
5682	// ***
5683	for (rr = m->ResourceRecords; rr; rr=rr->next)				// Now build our list of potential answers
5684		if (rr->NR_AnswerTo)									// If we marked the record...
5685			AddRecordToResponseList(&nrp, rr, mDNSNULL);		// ... add it to the list
5686
5687	// ***
5688	// *** 4. Add additional records
5689	// ***
5690	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
5691
5692	// ***
5693	// *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list
5694	// ***
5695	for (i=0; i<query->h.numAnswers; i++)						// For each record in the query's answer section...
5696		{
5697		// Get the record...
5698		CacheRecord *ourcacherr;
5699		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
5700		if (!ptr) goto exit;
5701
5702		// See if this Known-Answer suppresses any of our currently planned answers
5703		for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5704			if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5705				{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5706
5707		// See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5708		for (rr=m->ResourceRecords; rr; rr=rr->next)
5709			{
5710			// If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5711			if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5712				{
5713				if (srcaddr->type == mDNSAddrType_IPv4)
5714					{
5715					if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
5716					}
5717				else if (srcaddr->type == mDNSAddrType_IPv6)
5718					{
5719					if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
5720					}
5721				if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
5722					{
5723					rr->ImmedAnswer  = mDNSNULL;
5724					rr->ImmedUnicast = mDNSfalse;
5725#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5726					LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
5727#endif
5728					}
5729				}
5730			}
5731
5732		ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
5733
5734#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5735		// See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5736		// even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
5737		if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
5738			{
5739			ourcacherr->MPUnansweredKA++;
5740			ourcacherr->MPExpectingKA = mDNSfalse;
5741			}
5742#endif
5743
5744		// Having built our ExpectedAnswers list from the questions in this packet, we then remove
5745		// any records that are suppressed by the Known Answer list in this packet.
5746		eap = &ExpectedAnswers;
5747		while (*eap)
5748			{
5749			CacheRecord *cr = *eap;
5750			if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
5751				{ *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
5752			else eap = &cr->NextInKAList;
5753			}
5754
5755		// See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5756		if (!ourcacherr)
5757			{
5758			dqp = &DupQuestions;
5759			while (*dqp)
5760				{
5761				DNSQuestion *q = *dqp;
5762				if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5763					{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
5764				else dqp = &q->NextInDQList;
5765				}
5766			}
5767		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5768		}
5769
5770	// ***
5771	// *** 6. Cancel any additionals that were added because of now-deleted records
5772	// ***
5773	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5774		if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
5775			{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5776
5777	// ***
5778	// *** 7. Mark the send flags on the records we plan to send
5779	// ***
5780	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5781		{
5782		if (rr->NR_AnswerTo)
5783			{
5784			mDNSBool SendMulticastResponse = mDNSfalse;		// Send modern multicast response
5785			mDNSBool SendUnicastResponse   = mDNSfalse;		// Send modern unicast response (not legacy unicast response)
5786
5787			// If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5788			if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
5789				{
5790				SendMulticastResponse = mDNStrue;
5791				// If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5792				// multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5793				// If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5794				if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
5795				}
5796
5797			// If the client insists on a multicast response, then we'd better send one
5798			if      (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
5799			else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse   = mDNStrue;
5800			else if (rr->NR_AnswerTo)                SendLegacyResponse    = mDNStrue;
5801
5802			if (SendMulticastResponse || SendUnicastResponse)
5803				{
5804#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5805				rr->ImmedAnswerMarkTime = m->timenow;
5806#endif
5807				m->NextScheduledResponse = m->timenow;
5808				// If we're already planning to send this on another interface, just send it on all interfaces
5809				if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
5810					rr->ImmedAnswer = mDNSInterfaceMark;
5811				else
5812					{
5813					rr->ImmedAnswer = InterfaceID;			// Record interface to send it on
5814					if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
5815					if (srcaddr->type == mDNSAddrType_IPv4)
5816						{
5817						if      (mDNSIPv4AddressIsZero(rr->v4Requester))                rr->v4Requester = srcaddr->ip.v4;
5818						else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
5819						}
5820					else if (srcaddr->type == mDNSAddrType_IPv6)
5821						{
5822						if      (mDNSIPv6AddressIsZero(rr->v6Requester))                rr->v6Requester = srcaddr->ip.v6;
5823						else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
5824						}
5825					}
5826				}
5827			// If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5828			// so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5829			// else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5830			// else, for a simple unique record reply, we can reply immediately; no need for delay
5831			if      (query->h.flags.b[0] & kDNSFlag0_TC)            delayresponse = mDNSPlatformOneSecond * 20;	// Divided by 50 = 400ms
5832			else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond;		// Divided by 50 = 20ms
5833			}
5834		else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
5835			{
5836			// Since additional records are an optimization anyway, we only ever send them on one interface at a time
5837			// If two clients on different interfaces do queries that invoke the same optional additional answer,
5838			// then the earlier client is out of luck
5839			rr->ImmedAdditional = InterfaceID;
5840			// No need to set m->NextScheduledResponse here
5841			// We'll send these additional records when we send them, or not, as the case may be
5842			}
5843		}
5844
5845	// ***
5846	// *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer
5847	// ***
5848	if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
5849		{
5850#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5851		mDNSs32 oldss = m->SuppressSending;
5852		if (oldss && delayresponse)
5853			LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
5854#endif
5855		// Pick a random delay:
5856		// We start with the base delay chosen above (typically either 1 second or 20 seconds),
5857		// and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5858		// This is an integer value, with resolution determined by the platform clock rate.
5859		// We then divide that by 50 to get the delay value in ticks. We defer the division until last
5860		// to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5861		// The +49 before dividing is to ensure we round up, not down, to ensure that even
5862		// on platforms where the native clock rate is less than fifty ticks per second,
5863		// we still guarantee that the final calculated delay is at least one platform tick.
5864		// We want to make sure we don't ever allow the delay to be zero ticks,
5865		// because if that happens we'll fail the Bonjour Conformance Test.
5866		// Our final computed delay is 20-120ms for normal delayed replies,
5867		// or 400-500ms in the case of multi-packet known-answer lists.
5868		m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
5869		if (m->SuppressSending == 0) m->SuppressSending = 1;
5870#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5871		if (oldss && delayresponse)
5872			LogMsg("Set     SuppressSending to   %5ld", m->SuppressSending - m->timenow);
5873#endif
5874		}
5875
5876	// ***
5877	// *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5878	// ***
5879	if (SendLegacyResponse)
5880		responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
5881
5882exit:
5883	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5884
5885	// ***
5886	// *** 10. Finally, clear our link chains ready for use next time
5887	// ***
5888	while (ResponseRecords)
5889		{
5890		rr = ResponseRecords;
5891		ResponseRecords = rr->NextResponse;
5892		rr->NextResponse    = mDNSNULL;
5893		rr->NR_AnswerTo     = mDNSNULL;
5894		rr->NR_AdditionalTo = mDNSNULL;
5895		}
5896
5897	while (ExpectedAnswers)
5898		{
5899		CacheRecord *cr = ExpectedAnswers;
5900		ExpectedAnswers = cr->NextInKAList;
5901		cr->NextInKAList = mDNSNULL;
5902
5903		// For non-truncated queries, we can definitively say that we should expect
5904		// to be seeing a response for any records still left in the ExpectedAnswers list
5905		if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5906			if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond)
5907				{
5908				cr->UnansweredQueries++;
5909				cr->LastUnansweredTime = m->timenow;
5910#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5911				if (cr->UnansweredQueries > 1)
5912					debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5913						cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
5914#endif
5915				SetNextCacheCheckTime(m, cr);
5916				}
5917
5918		// If we've seen multiple unanswered queries for this record,
5919		// then mark it to expire in five seconds if we don't get a response by then.
5920		if (cr->UnansweredQueries >= MaxUnansweredQueries)
5921			{
5922#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5923			// Only show debugging message if this record was not about to expire anyway
5924			if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
5925				debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5926					cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
5927#endif
5928			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5929			}
5930#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
5931		// Make a guess, based on the multi-packet query / known answer counts, whether we think we
5932		// should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
5933		// possible packet loss of up to 20% of the additional KA packets.)
5934		else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8)
5935			{
5936			// We want to do this conservatively.
5937			// If there are so many machines on the network that they have to use multi-packet known-answer lists,
5938			// then we don't want them to all hit the network simultaneously with their final expiration queries.
5939			// By setting the record to expire in four minutes, we achieve two things:
5940			// (a) the 90-95% final expiration queries will be less bunched together
5941			// (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
5942			mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4;
5943			if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
5944				remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
5945
5946			// Only show debugging message if this record was not about to expire anyway
5947			if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
5948				debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5949					cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
5950
5951			if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
5952				cr->UnansweredQueries++;	// Treat this as equivalent to one definite unanswered query
5953			cr->MPUnansweredQ  = 0;			// Clear MPQ/MPKA statistics
5954			cr->MPUnansweredKA = 0;
5955			cr->MPExpectingKA  = mDNSfalse;
5956
5957			if (remain < kDefaultReconfirmTimeForNoAnswer)
5958				remain = kDefaultReconfirmTimeForNoAnswer;
5959			mDNS_Reconfirm_internal(m, cr, remain);
5960			}
5961#endif
5962		}
5963
5964	while (DupQuestions)
5965		{
5966		DNSQuestion *q = DupQuestions;
5967		DupQuestions = q->NextInDQList;
5968		q->NextInDQList = mDNSNULL;
5969		i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
5970		debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
5971			srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
5972		}
5973
5974	return(responseptr);
5975	}
5976
5977mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
5978	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5979	const mDNSInterfaceID InterfaceID)
5980	{
5981	mDNSu8    *responseend = mDNSNULL;
5982	mDNSBool   QueryWasLocalUnicast = srcaddr && dstaddr &&
5983		!mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5984
5985	if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
5986		{
5987		LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5988			"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
5989			srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5990			msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
5991			msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
5992			msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
5993			msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5994		return;
5995		}
5996
5997	verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5998		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5999		srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
6000		msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
6001		msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
6002		msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
6003		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
6004
6005	responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
6006		!mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
6007
6008	if (responseend)	// If responseend is non-null, that means we built a unicast response packet
6009		{
6010		debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
6011			m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
6012			m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
6013			m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
6014			srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
6015		mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL);
6016		}
6017	}
6018
6019#if 0
6020mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
6021	{
6022	DNSServer *s;
6023	(void)m; // Unused
6024	(void)srcaddr; // Unused
6025	for (s = m->DNSServers; s; s = s->next)
6026		if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
6027	return(mDNSfalse);
6028	}
6029#endif
6030
6031struct UDPSocket_struct
6032	{
6033	mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
6034	};
6035
6036mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question)
6037	{
6038	DNSQuestion *q;
6039	for (q = m->Questions; q; q=q->next)
6040		if (q->LocalSocket &&
6041			mDNSSameIPPort  (q->LocalSocket->port, port)     &&
6042			mDNSSameOpaque16(q->TargetQID,         id)       &&
6043			q->qtype                  == question->qtype     &&
6044			q->qclass                 == question->qclass    &&
6045			q->qnamehash              == question->qnamehash &&
6046			SameDomainName(&q->qname, &question->qname))
6047			return(q);
6048	return(mDNSNULL);
6049	}
6050
6051mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr)
6052	{
6053	DNSQuestion *q;
6054	(void)id;
6055	(void)srcaddr;
6056	for (q = m->Questions; q; q=q->next)
6057		if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q))
6058			{
6059			if (!mDNSOpaque16IsZero(q->TargetQID))
6060				{
6061				debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr));
6062				if (mDNSSameOpaque16(q->TargetQID, id))
6063					{
6064					if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue);
6065				//	if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
6066				//	if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
6067				//	if (TrustedSource(m, srcaddr))                              return(mDNStrue);
6068					LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
6069						q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
6070					return(mDNSfalse);
6071					}
6072				}
6073			else
6074				{
6075				if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
6076					return(mDNStrue);
6077				}
6078			}
6079	return(mDNSfalse);
6080	}
6081
6082// Certain data types need more space for in-memory storage than their in-packet rdlength would imply
6083// Currently this applies only to rdata types containing more than one domainname,
6084// or types where the domainname is not the last item in the structure.
6085// In addition, NSEC currently requires less space for in-memory storage than its in-packet representation.
6086mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr)
6087	{
6088	switch (rr->rrtype)
6089		{
6090		case kDNSType_SOA: return sizeof(rdataSOA);
6091		case kDNSType_RP:  return sizeof(rdataRP);
6092		case kDNSType_PX:  return sizeof(rdataPX);
6093		case kDNSType_NSEC:return sizeof(rdataNSEC);
6094		default:           return rr->rdlength;
6095		}
6096	}
6097
6098mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
6099	{
6100	CacheRecord *rr = mDNSNULL;
6101	mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec);
6102
6103	if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r));
6104
6105	//if (RDLength > InlineCacheRDSize)
6106	//	LogInfo("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
6107
6108	if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);	// If we don't have a CacheGroup for this name, make one now
6109	if (cg)  rr = GetCacheRecord(m, cg, RDLength);	// Make a cache record, being careful not to recycle cg
6110	if (!rr) NoCacheAnswer(m, &m->rec.r);
6111	else
6112		{
6113		RData *saveptr = rr->resrec.rdata;		// Save the rr->resrec.rdata pointer
6114		*rr = m->rec.r;							// Block copy the CacheRecord object
6115		rr->resrec.rdata = saveptr;				// Restore rr->resrec.rdata after the structure assignment
6116		rr->resrec.name  = cg->name;			// And set rr->resrec.name to point into our CacheGroup header
6117
6118		// If this is an oversized record with external storage allocated, copy rdata to external storage
6119		if      (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize)
6120			LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
6121		else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && RDLength <= InlineCacheRDSize)
6122			LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
6123		if (RDLength > InlineCacheRDSize)
6124			mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
6125
6126		rr->next = mDNSNULL;					// Clear 'next' pointer
6127		*(cg->rrcache_tail) = rr;				// Append this record to tail of cache slot list
6128		cg->rrcache_tail = &(rr->next);			// Advance tail pointer
6129		if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
6130			rr->DelayDelivery = NonZeroTime(m->timenow);
6131		else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask &&			// If marked unique,
6132			rr->resrec.rdata->MaxRDLength != 0)										// and non-negative, assume we may have
6133			rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond);	// to delay delivery of this 'add' event
6134		else
6135			rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
6136
6137		CacheRecordAdd(m, rr);	// CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
6138		}
6139	return(rr);
6140	}
6141
6142mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
6143	{
6144	rr->TimeRcvd             = m->timenow;
6145	rr->resrec.rroriginalttl = ttl;
6146	rr->UnansweredQueries = 0;
6147#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6148	rr->MPUnansweredQ     = 0;
6149	rr->MPUnansweredKA    = 0;
6150	rr->MPExpectingKA     = mDNSfalse;
6151#endif
6152	SetNextCacheCheckTime(m, rr);
6153	}
6154
6155mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
6156	{
6157	CacheRecord *rr;
6158	const mDNSu32 slot = HashSlot(&q->qname);
6159	CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
6160	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6161		if (rr->CRActiveQuestion == q)
6162			{
6163			//LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
6164			RefreshCacheRecord(m, rr, lease);
6165			}
6166	}
6167
6168mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl)		// TTL in seconds
6169	{
6170	if      (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease;
6171	else if (LLQType == uDNS_LLQ_Events)
6172		{
6173		// If the TTL is -1 for uDNS LLQ event packet, that means "remove"
6174		if (ttl == 0xFFFFFFFF) ttl = 0;
6175		else                   ttl = kLLQ_DefLease;
6176		}
6177	else	// else not LLQ (standard uDNS response)
6178		{
6179		// The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
6180		// also do this check here to make sure we can't get integer overflow below
6181		if (ttl > 0x8000000UL) ttl = 0x8000000UL;
6182
6183		// Adjustment factor to avoid race condition:
6184		// Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
6185		// If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
6186		// 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
6187		// To avoid this, we extend the record's effective TTL to give it a little extra grace period.
6188		// We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
6189		// the cached copy at our local caching server will already have expired, so the server will be forced
6190		// to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
6191		ttl += ttl/4 + 2;
6192
6193		// For mDNS, TTL zero means "delete this record"
6194		// For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
6195		// For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
6196		// If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
6197		// In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
6198		if (ttl < 15) ttl = 15;
6199		}
6200
6201	return ttl;
6202	}
6203
6204// Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
6205// the record list and/or question list.
6206// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6207// InterfaceID non-NULL tells us the interface this multicast response was received on
6208// InterfaceID NULL tells us this was a unicast response
6209// dstaddr NULL tells us we received this over an outgoing TCP connection we made
6210mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
6211	const DNSMessage *const response, const mDNSu8 *end,
6212	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
6213	const mDNSInterfaceID InterfaceID)
6214	{
6215	int i;
6216	mDNSBool ResponseMCast    = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
6217	mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
6218	uDNS_LLQType LLQType      = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
6219
6220	// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
6221	// We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
6222	// set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
6223	CacheRecord *CacheFlushRecords = (CacheRecord*)1;
6224	CacheRecord **cfp = &CacheFlushRecords;
6225
6226	// All records in a DNS response packet are treated as equally valid statements of truth. If we want
6227	// to guard against spoof responses, then the only credible protection against that is cryptographic
6228	// security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
6229	int firstauthority  =                   response->h.numAnswers;
6230	int firstadditional = firstauthority  + response->h.numAuthorities;
6231	int totalrecords    = firstadditional + response->h.numAdditionals;
6232	const mDNSu8 *ptr   = response->data;
6233
6234	debugf("Received Response from %#-15a addressed to %#-15a on %p with "
6235		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
6236		srcaddr, dstaddr, InterfaceID,
6237		response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
6238		response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
6239		response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
6240		response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
6241
6242	// According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
6243	//    When a DNS client receives a reply with TC
6244	//    set, it should ignore that response, and query again, using a
6245	//    mechanism, such as a TCP connection, that will permit larger replies.
6246	// It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but
6247	// delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing
6248	// failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once.
6249	// <rdar://problem/6690034> Can't bind to Active Directory
6250	// In addition, if the client immediately canceled its query after getting the initial partial response, then we'll
6251	// abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache.
6252	// Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already,
6253	// and not even do the TCP query.
6254	// Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet.
6255	if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return;
6256
6257	if (LLQType == uDNS_LLQ_Ignore) return;
6258
6259	// 1. We ignore questions (if any) in mDNS response packets
6260	// 2. If this is an LLQ response, we handle it much the same
6261	// 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
6262	//    answer as being the authoritative complete RRSet, and respond by deleting all other
6263	//    matching cache records that don't appear in this packet.
6264	// Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
6265	if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC))
6266		ptr = LocateAnswers(response, end);
6267	// Otherwise, for one-shot queries, any answers in our cache that are not also contained
6268	// in this response packet are immediately deemed to be invalid.
6269	else
6270		{
6271		mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask);
6272		mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth);
6273		mDNSBool returnEarly = mDNSfalse;
6274		// We could possibly combine this with the similar loop at the end of this function --
6275		// instead of tagging cache records here and then rescuing them if we find them in the answer section,
6276		// we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
6277		// which it was received (or refreshed), and then at the end if we find any cache records which
6278		// answer questions in this packet's question section, but which aren't tagged with this packet's
6279		// packet number, then we deduce they are old and delete them
6280		for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
6281			{
6282			DNSQuestion q, *qptr = mDNSNULL;
6283			ptr = getQuestion(response, ptr, end, InterfaceID, &q);
6284			if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))))
6285				{
6286				if (!failure)
6287					{
6288					CacheRecord *rr;
6289					const mDNSu32 slot = HashSlot(&q.qname);
6290					CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
6291					for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6292						if (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q))
6293							{
6294							debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
6295								rr->resrec.InterfaceID, CRDisplayString(m, rr));
6296							// Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
6297							rr->TimeRcvd          = m->timenow - TicksTTL(rr) - 1;
6298							rr->UnansweredQueries = MaxUnansweredQueries;
6299							}
6300					}
6301				else
6302					{
6303					if (qptr)
6304						{
6305						LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
6306						PushDNSServerToEnd(m, qptr);
6307						}
6308					returnEarly = mDNStrue;
6309					}
6310				}
6311			}
6312		if (returnEarly)
6313			{
6314			LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
6315				response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
6316				response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
6317				response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
6318			// not goto exit because we won't have any CacheFlushRecords and we do not want to
6319			// generate negative cache entries (we want to query the next server)
6320			return;
6321			}
6322		}
6323
6324	for (i = 0; i < totalrecords && ptr && ptr < end; i++)
6325		{
6326		// All responses sent via LL multicast are acceptable for caching
6327		// All responses received over our outbound TCP connections are acceptable for caching
6328		mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
6329		// (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
6330		// to any specific question -- any code reading records from the cache needs to make that determination for itself.)
6331
6332		const mDNSu8 RecordType =
6333			(i < firstauthority ) ? (mDNSu8)kDNSRecordTypePacketAns  :
6334			(i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd;
6335		ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
6336		if (!ptr) goto exit;		// Break out of the loop and clean up our CacheFlushRecords list before exiting
6337
6338		// Don't want to cache OPT or TSIG pseudo-RRs
6339		if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
6340			{ m->rec.r.resrec.RecordType = 0; continue; }
6341
6342		// When we receive uDNS LLQ responses, we assume a long cache lifetime --
6343		// In the case of active LLQs, we'll get remove events when the records actually do go away
6344		// In the case of polling LLQs, we assume the record remains valid until the next poll
6345		if (!mDNSOpaque16IsZero(response->h.id))
6346			m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
6347
6348		// If response was not sent via LL multicast,
6349		// then see if it answers a recent query of ours, which would also make it acceptable for caching.
6350		if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
6351
6352		// 1. Check that this packet resource record does not conflict with any of ours
6353		if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
6354			{
6355			if (m->CurrentRecord)
6356				LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
6357			m->CurrentRecord = m->ResourceRecords;
6358			while (m->CurrentRecord)
6359				{
6360				AuthRecord *rr = m->CurrentRecord;
6361				m->CurrentRecord = rr->next;
6362				// We accept all multicast responses, and unicast responses resulting from queries we issued
6363				// For other unicast responses, this code accepts them only for responses with an
6364				// (apparently) local source address that pertain to a record of our own that's in probing state
6365				if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue;
6366
6367				if (PacketRRMatchesSignature(&m->rec.r, rr))		// If interface, name, type (if shared record) and class match...
6368					{
6369					// ... check to see if type and rdata are identical
6370					if (IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
6371						{
6372						// If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
6373						if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
6374							{
6375							// If we were planning to send on this -- and only this -- interface, then we don't need to any more
6376							if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
6377							}
6378						else
6379							{
6380							if      (rr->ImmedAnswer == mDNSNULL)    { rr->ImmedAnswer = InterfaceID;       m->NextScheduledResponse = m->timenow; }
6381							else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
6382							}
6383						}
6384					// else, the packet RR has different type or different rdata -- check to see if this is a conflict
6385					else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
6386						{
6387						LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
6388						LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
6389
6390						// If this record is marked DependentOn another record for conflict detection purposes,
6391						// then *that* record has to be bumped back to probing state to resolve the conflict
6392						if (rr->DependentOn)
6393							{
6394							while (rr->DependentOn) rr = rr->DependentOn;
6395							LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
6396							}
6397
6398						// If we've just whacked this record's ProbeCount, don't need to do it again
6399						if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
6400							LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr));
6401						else if (rr->ProbeCount == DefaultProbeCountForTypeUnique)
6402							LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr));
6403						else
6404							{
6405							LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r));
6406							// If we'd previously verified this record, put it back to probing state and try again
6407							if (rr->resrec.RecordType == kDNSRecordTypeVerified)
6408								{
6409								LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m, rr));
6410								rr->resrec.RecordType     = kDNSRecordTypeUnique;
6411								// We set ProbeCount to one more than the usual value so we know we've already touched this record.
6412								// This is because our single probe for "example-name.local" could yield a response with (say) two A records and
6413								// three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts.
6414								// This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries().
6415								rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
6416								rr->AnnounceCount  = InitialAnnounceCount;
6417								InitializeLastAPTime(m, rr);
6418								RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
6419								}
6420							// If we're probing for this record, we just failed
6421							else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
6422								{
6423								LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr));
6424								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
6425								}
6426							// We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the same machine giving
6427							// different answers for the reverse mapping record.) This is simply a misconfiguration, and we don't try to recover from it.
6428							else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
6429								{
6430								LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
6431								mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
6432								}
6433							else
6434								LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
6435							}
6436						}
6437					// Else, matching signature, different type or rdata, but not a considered a conflict.
6438					// If the packet record has the cache-flush bit set, then we check to see if we
6439					// have any record(s) of the same type that we should re-assert to rescue them
6440					// (see note about "multi-homing and bridged networks" at the end of this function).
6441					else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
6442						if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
6443							{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
6444					}
6445				}
6446			}
6447
6448		if (!AcceptableResponse)
6449			{
6450			const CacheRecord *cr;
6451			for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
6452				{
6453				domainname *target = GetRRDomainNameTarget(&cr->resrec);
6454				if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name))
6455					{ AcceptableResponse = mDNStrue; break; }
6456				}
6457			}
6458
6459		// 2. See if we want to add this packet resource record to our cache
6460		// We only try to cache answers if we have a cache to put them in
6461		// Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
6462		if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
6463		if (m->rrcache_size && AcceptableResponse)
6464			{
6465			const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
6466			CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
6467			CacheRecord *rr;
6468
6469			// 2a. Check if this packet resource record is already in our cache
6470			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6471				{
6472				// If we found this exact resource record, refresh its TTL
6473				if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
6474					{
6475					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
6476						verbosedebugf("Found record size %5d interface %p already in cache: %s",
6477							m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
6478					rr->TimeRcvd  = m->timenow;
6479
6480					if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
6481						{
6482						// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
6483						if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
6484							{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
6485
6486						// If this packet record is marked unique, and our previous cached copy was not, then fix it
6487						if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
6488							{
6489							DNSQuestion *q;
6490							for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
6491							rr->resrec.RecordType = m->rec.r.resrec.RecordType;
6492							}
6493						}
6494
6495					if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
6496						{
6497						// If the rdata of the packet record differs in name capitalization from the record in our cache
6498						// then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
6499						// a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
6500						rr->resrec.rroriginalttl = 0;
6501						rr->UnansweredQueries = MaxUnansweredQueries;
6502						SetNextCacheCheckTime(m, rr);
6503						// DO NOT break out here -- we want to continue as if we never found it
6504						}
6505					else if (m->rec.r.resrec.rroriginalttl > 0)
6506						{
6507						//if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
6508						RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
6509						break;
6510						}
6511					else
6512						{
6513						// If the packet TTL is zero, that means we're deleting this record.
6514						// To give other hosts on the network a chance to protest, we push the deletion
6515						// out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
6516						// Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
6517						// lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
6518						debugf("DE for %s", CRDisplayString(m, rr));
6519						rr->resrec.rroriginalttl = 1;
6520						rr->UnansweredQueries = MaxUnansweredQueries;
6521						SetNextCacheCheckTime(m, rr);
6522						break;
6523						}
6524					}
6525				}
6526
6527			// If packet resource record not in our cache, add it now
6528			// (unless it is just a deletion of a record we never had, in which case we don't care)
6529			if (!rr && m->rec.r.resrec.rroriginalttl > 0)
6530				{
6531				rr = CreateNewCacheEntry(m, slot, cg);
6532				if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
6533					{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
6534				}
6535			}
6536		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6537		}
6538
6539exit:
6540	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6541
6542	// If we've just received one or more records with their cache flush bits set,
6543	// then scan that cache slot to see if there are any old stale records we need to flush
6544	while (CacheFlushRecords != (CacheRecord*)1)
6545		{
6546		CacheRecord *r1 = CacheFlushRecords, *r2;
6547		const mDNSu32 slot = HashSlot(r1->resrec.name);
6548		const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
6549		CacheFlushRecords = CacheFlushRecords->NextInCFList;
6550		r1->NextInCFList = mDNSNULL;
6551
6552		// Look for records in the cache with the same signature as this new one with the cache flush
6553		// bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
6554		// (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
6555		// We make these TTL adjustments *only* for records that still have *more* than one second
6556		// remaining to live. Otherwise, a record that we tagged for deletion half a second ago
6557		// (and now has half a second remaining) could inadvertently get its life extended, by either
6558		// (a) if we got an explicit goodbye packet half a second ago, the record would be considered
6559		// "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
6560		// or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
6561		// in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
6562		// If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
6563		// To avoid this, we need to ensure that the cache flushing operation will only act to
6564		// *decrease* a record's remaining lifetime, never *increase* it.
6565		for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
6566			if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
6567				r1->resrec.rrtype      == r2->resrec.rrtype &&
6568				r1->resrec.rrclass     == r2->resrec.rrclass)
6569				{
6570				// If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
6571				// else, if record is old, mark it to be flushed
6572				if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
6573					{
6574					// If we find mismatched TTLs in an RRSet, correct them.
6575					// We only do this for records with a TTL of 2 or higher. It's possible to have a
6576					// goodbye announcement with the cache flush bit set (or a case change on record rdata,
6577					// which we treat as a goodbye followed by an addition) and in that case it would be
6578					// inappropriate to synchronize all the other records to a TTL of 0 (or 1).
6579					// We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
6580					// because certain early Bonjour devices are known to have this specific mismatch, and
6581					// there's no point filling syslog with messages about something we already know about.
6582					// We also don't log this for uDNS responses, since a caching name server is obliged
6583					// to give us an aged TTL to correct for how long it has held the record,
6584					// so our received TTLs are expected to vary in that case
6585					if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
6586						{
6587						if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
6588							mDNSOpaque16IsZero(response->h.id))
6589							LogInfo("Correcting TTL from %4d to %4d for %s",
6590								r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
6591						r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
6592						}
6593					r2->TimeRcvd = m->timenow;
6594					}
6595				else				// else, if record is old, mark it to be flushed
6596					{
6597					verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
6598					// We set stale records to expire in one second.
6599					// This gives the owner a chance to rescue it if necessary.
6600					// This is important in the case of multi-homing and bridged networks:
6601					//   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
6602					//   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
6603					//   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
6604					//   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
6605					//   By delaying the deletion by one second, we give X a change to notice that this bridging has
6606					//   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
6607
6608					// We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
6609					// final expiration queries for this record.
6610
6611					// If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
6612					// flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
6613					// one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
6614					if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
6615						{
6616						debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
6617						r2->resrec.rroriginalttl = 0;
6618						m->NextCacheCheck = m->timenow;
6619						m->NextScheduledEvent = m->timenow;
6620						}
6621					else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
6622						{
6623						// We only set a record to expire in one second if it currently has *more* than a second to live
6624						// If it's already due to expire in a second or less, we just leave it alone
6625						r2->resrec.rroriginalttl = 1;
6626						r2->UnansweredQueries = MaxUnansweredQueries;
6627						r2->TimeRcvd = m->timenow - 1;
6628						// We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
6629						// that we marked for deletion via an explicit DE record
6630						}
6631					}
6632				SetNextCacheCheckTime(m, r2);
6633				}
6634		if (r1->DelayDelivery)	// If we were planning to delay delivery of this record, see if we still need to
6635			{
6636			// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
6637			r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
6638			if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
6639			}
6640		}
6641
6642	// See if we need to generate negative cache entries for unanswered unicast questions
6643	ptr = response->data;
6644	for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
6645		{
6646		DNSQuestion q;
6647		ptr = getQuestion(response, ptr, end, InterfaceID, &q);
6648		if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
6649			{
6650			// When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
6651			// Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
6652			// Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
6653			// (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist).
6654			// This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we
6655			// suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache.
6656			// The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're
6657			// *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not
6658			// in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
6659			// negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
6660			if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
6661				LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
6662			else
6663				{
6664				CacheRecord *rr, *neg = mDNSNULL;
6665				mDNSu32 slot = HashSlot(&q.qname);
6666				CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
6667				for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
6668					if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
6669						{
6670						// 1. If we got a fresh answer to this query, then don't need to generate a negative entry
6671						if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break;
6672						// 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
6673						if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
6674						}
6675
6676				if (!rr)
6677					{
6678					// We start off assuming a negative caching TTL of 60 seconds
6679					// but then look to see if we can find an SOA authority record to tell us a better value we should be using
6680					mDNSu32 negttl = 60;
6681					int repeat = 0;
6682					const domainname *name = &q.qname;
6683					mDNSu32           hash = q.qnamehash;
6684
6685					// Special case for our special Microsoft Active Directory "local SOA" check.
6686					// Some cheap home gateways don't include an SOA record in the authority section when
6687					// they send negative responses, so we don't know how long to cache the negative result.
6688					// Because we don't want to keep hitting the root name servers with our query to find
6689					// if we're on a network using Microsoft Active Directory using "local" as a private
6690					// internal top-level domain, we make sure to cache the negative result for at least one day.
6691					if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24;
6692
6693					// If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
6694					if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
6695						{
6696						ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
6697						if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
6698							{
6699							const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
6700							mDNSu32 ttl_s = soa->min;
6701							// We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
6702							// for the SOA record for ".", where the record is reported as non-cacheable
6703							// (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is
6704							if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0])
6705								ttl_s = m->rec.r.resrec.rroriginalttl;
6706							if (negttl < ttl_s) negttl = ttl_s;
6707
6708							// Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
6709							// with an Authority Section SOA record for d.com, then this is a hint that the authority
6710							// is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
6711							// To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
6712							if (q.qtype == kDNSType_SOA)
6713								{
6714								int qcount = CountLabels(&q.qname);
6715								int scount = CountLabels(m->rec.r.resrec.name);
6716								if (qcount - 1 > scount)
6717									if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
6718										repeat = qcount - 1 - scount;
6719								}
6720							}
6721						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6722						}
6723
6724					// If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
6725					// the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
6726					// and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
6727					// of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
6728					// With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
6729					// so that we back off our polling rate and don't keep hitting the server continually.
6730					if (neg)
6731						{
6732						if (negttl < neg->resrec.rroriginalttl * 2)
6733							negttl = neg->resrec.rroriginalttl * 2;
6734						if (negttl > 3600)
6735							negttl = 3600;
6736						}
6737
6738					negttl = GetEffectiveTTL(LLQType, negttl);	// Add 25% grace period if necessary
6739
6740					// If we already had a negative cache entry just update it, else make one or more new negative cache entries
6741					if (neg)
6742						{
6743						debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
6744						RefreshCacheRecord(m, neg, negttl);
6745						}
6746					else while (1)
6747						{
6748						debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
6749						MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any);
6750						CreateNewCacheEntry(m, slot, cg);
6751						m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6752						if (!repeat) break;
6753						repeat--;
6754						name = (const domainname *)(name->c + 1 + name->c[0]);
6755						hash = DomainNameHashValue(name);
6756						slot = HashSlot(name);
6757						cg   = CacheGroupForName(m, slot, hash, name);
6758						}
6759					}
6760				}
6761			}
6762		}
6763	}
6764
6765mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result)
6766	{
6767	if (result && result != mStatus_MemFree)
6768		LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar));
6769
6770	if (result == mStatus_NameConflict)
6771		{
6772		LogMsg("Received Conflicting mDNS -- waking %s %.6a %s",
6773			InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
6774		SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password);
6775		}
6776	else if (result == mStatus_MemFree)
6777		{
6778		m->ProxyRecords--;
6779		mDNSPlatformMemFree(ar);
6780		}
6781	}
6782
6783mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
6784	const DNSMessage *const msg, const mDNSu8 *end,
6785	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
6786	const mDNSInterfaceID InterfaceID)
6787	{
6788	int i;
6789	AuthRecord opt;
6790	mDNSu8 *p = m->omsg.data;
6791	OwnerOptData owner;
6792	mDNSu32 updatelease = 0;
6793	const mDNSu8 *ptr;
6794
6795	LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
6796		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
6797		srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
6798		msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
6799		msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
6800		msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
6801		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
6802
6803	if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
6804
6805	if (mDNS_PacketLoggingEnabled)
6806		DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
6807
6808	ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
6809	if (ptr)
6810		{
6811		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
6812		if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
6813			{
6814			const rdataOPT *o;
6815			const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
6816			for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
6817				{
6818				if      (o->opt == kDNSOpt_Lease)                         updatelease = o->u.updatelease;
6819				else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner       = o->u.owner;
6820				}
6821			}
6822		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6823		}
6824
6825	InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags);
6826
6827	if (!updatelease || !owner.HMAC.l[0])
6828		{
6829		static int msgs = 0;
6830		if (msgs < 100)
6831			{
6832			msgs++;
6833			LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport),
6834				!updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : "");
6835			}
6836		m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr;
6837		}
6838	else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS)
6839		{
6840		static int msgs = 0;
6841		if (msgs < 100)
6842			{
6843			msgs++;
6844			LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport),
6845				m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS);
6846			}
6847		m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
6848		}
6849	else
6850		{
6851		LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
6852
6853		if (updatelease > 24 * 60 * 60)
6854			updatelease = 24 * 60 * 60;
6855
6856		if (updatelease > 0x40000000UL / mDNSPlatformOneSecond)
6857			updatelease = 0x40000000UL / mDNSPlatformOneSecond;
6858
6859		ptr = LocateAuthorities(msg, end);
6860		for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++)
6861			{
6862			ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
6863			if (ptr)
6864				{
6865				mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
6866				AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
6867				if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; }
6868				else
6869					{
6870					mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared;
6871					m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet;
6872					mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar);
6873					AssignDomainName(&ar->namestorage, m->rec.r.resrec.name);
6874					ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse);
6875					ar->resrec.rdata->MaxRDLength = RDLengthMem;
6876					mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem);
6877					ar->WakeUp = owner;
6878					if (m->rec.r.resrec.rrtype == kDNSType_PTR)
6879						{
6880						mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name);
6881						if      (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name);
6882						else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name);
6883						debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar));
6884						if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID);
6885						}
6886					ar->TimeRcvd   = m->timenow;
6887					ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond;
6888					if (m->NextScheduledSPS - ar->TimeExpire > 0)
6889						m->NextScheduledSPS = ar->TimeExpire;
6890					mDNS_Register_internal(m, ar);
6891					// For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
6892					if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
6893					m->ProxyRecords++;
6894					LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar));
6895					}
6896				}
6897			m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6898			}
6899
6900		if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask)
6901			{
6902			LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport));
6903			ClearProxyRecords(m, &owner, m->DuplicateRecords);
6904			ClearProxyRecords(m, &owner, m->ResourceRecords);
6905			}
6906		else
6907			{
6908			mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6909			opt.resrec.rrclass    = NormalMaxDNSMessageData;
6910			opt.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
6911			opt.resrec.rdestimate = sizeof(rdataOPT);
6912			opt.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
6913			opt.resrec.rdata->u.opt[0].u.updatelease = updatelease;
6914			p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData);
6915			}
6916		}
6917
6918	if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
6919	}
6920
6921mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID)
6922	{
6923	if (InterfaceID)
6924		{
6925		AuthRecord *rr;
6926		mDNSu32 updatelease = 60 * 60;		// If SPS fails to indicate lease time, assume one hour
6927		const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
6928		if (ptr)
6929			{
6930			ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
6931			if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
6932				{
6933				const rdataOPT *o;
6934				const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
6935				for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
6936					if (o->opt == kDNSOpt_Lease)
6937						{
6938						updatelease = o->u.updatelease;
6939						LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease);
6940						}
6941				}
6942			m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
6943			}
6944
6945		for (rr = m->ResourceRecords; rr; rr=rr->next)
6946			if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name))))
6947				if (mDNSSameOpaque16(rr->updateid, msg->h.id))
6948					{
6949					rr->updateid = zeroID;
6950					rr->expire   = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond);
6951					LogSPS("Sleep Proxy registered record %5d %s", updatelease, ARDisplayString(m,rr));
6952					}
6953
6954		}
6955	// If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
6956	// may have been the thing we were waiting for, so schedule another check to see if we can sleep now.
6957	if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
6958	}
6959
6960mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
6961	const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID)
6962	{
6963	if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
6964		{
6965		LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
6966#if ForceAlerts
6967		*(long*)0 = 0;
6968#endif
6969		}
6970
6971	// Create empty resource record
6972	cr->resrec.RecordType    = kDNSRecordTypePacketNegative;
6973	cr->resrec.InterfaceID   = InterfaceID;
6974	cr->resrec.name          = name;	// Will be updated to point to cg->name when we call CreateNewCacheEntry
6975	cr->resrec.rrtype        = rrtype;
6976	cr->resrec.rrclass       = rrclass;
6977	cr->resrec.rroriginalttl = ttl_seconds;
6978	cr->resrec.rdlength      = 0;
6979	cr->resrec.rdestimate    = 0;
6980	cr->resrec.namehash      = namehash;
6981	cr->resrec.rdatahash     = 0;
6982	cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
6983	cr->resrec.rdata->MaxRDLength = 0;
6984
6985	cr->NextInKAList       = mDNSNULL;
6986	cr->TimeRcvd           = m->timenow;
6987	cr->DelayDelivery      = 0;
6988	cr->NextRequiredQuery  = m->timenow;
6989	cr->LastUsed           = m->timenow;
6990	cr->CRActiveQuestion   = mDNSNULL;
6991	cr->UnansweredQueries  = 0;
6992	cr->LastUnansweredTime = 0;
6993#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
6994	cr->MPUnansweredQ      = 0;
6995	cr->MPLastUnansweredQT = 0;
6996	cr->MPUnansweredKA     = 0;
6997	cr->MPExpectingKA      = mDNSfalse;
6998#endif
6999	cr->NextInCFList       = mDNSNULL;
7000	}
7001
7002mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
7003	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
7004	const mDNSInterfaceID InterfaceID)
7005	{
7006	mDNSInterfaceID ifid = InterfaceID;
7007	DNSMessage  *msg  = (DNSMessage *)pkt;
7008	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
7009	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
7010	const mDNSu8 UpdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update;
7011	const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
7012	mDNSu8 QR_OP;
7013	mDNSu8 *ptr = mDNSNULL;
7014	mDNSBool TLS = (dstaddr == (mDNSAddr *)1);	// For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
7015	if (TLS) dstaddr = mDNSNULL;
7016
7017#ifndef UNICAST_DISABLED
7018	if (mDNSSameAddress(srcaddr, &m->Router))
7019		{
7020#ifdef _LEGACY_NAT_TRAVERSAL_
7021		if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)))
7022			{
7023			mDNS_Lock(m);
7024			LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
7025			mDNS_Unlock(m);
7026			return;
7027			}
7028#endif
7029		if (mDNSSameIPPort(srcport, NATPMPPort))
7030			{
7031			mDNS_Lock(m);
7032			uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
7033			mDNS_Unlock(m);
7034			return;
7035			}
7036		}
7037#ifdef _LEGACY_NAT_TRAVERSAL_
7038	else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; }
7039#endif
7040
7041#endif
7042	if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
7043	QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
7044	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
7045	ptr = (mDNSu8 *)&msg->h.numQuestions;
7046	msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
7047	msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
7048	msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
7049	msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
7050
7051	if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
7052
7053	// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
7054	// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
7055	if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
7056
7057	mDNS_Lock(m);
7058	m->PktNum++;
7059#ifndef UNICAST_DISABLED
7060	if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR)))
7061		if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
7062			{
7063			ifid = mDNSInterface_Any;
7064			if (mDNS_PacketLoggingEnabled)
7065				DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
7066			uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
7067			// Note: mDNSCore also needs to get access to received unicast responses
7068			}
7069#endif
7070	if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
7071	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
7072	else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate  (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
7073	else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end,                                     InterfaceID);
7074	else
7075		{
7076		LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
7077			msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID);
7078		if (mDNS_LoggingEnabled)
7079			{
7080			int i = 0;
7081			while (i<end-(mDNSu8 *)pkt)
7082				{
7083				char buffer[128];
7084				char *p = buffer + mDNS_snprintf(buffer, sizeof(buffer), "%04X", i);
7085				do if (i<end-(mDNSu8 *)pkt) p += mDNS_snprintf(p, sizeof(buffer), " %02X", ((mDNSu8 *)pkt)[i]); while (++i & 15);
7086				LogInfo("%s", buffer);
7087				}
7088			}
7089		}
7090	// Packet reception often causes a change to the task list:
7091	// 1. Inbound queries can cause us to need to send responses
7092	// 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
7093	// 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
7094	// 4. Response packets that answer questions may cause our client to issue new questions
7095	mDNS_Unlock(m);
7096	}
7097
7098// ***************************************************************************
7099#if COMPILER_LIKES_PRAGMA_MARK
7100#pragma mark -
7101#pragma mark - Searcher Functions
7102#endif
7103
7104// Targets are considered the same if both queries are untargeted, or
7105// if both are targeted to the same address+port
7106// (If Target address is zero, TargetPort is undefined)
7107#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
7108	(mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
7109
7110// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
7111// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
7112// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
7113// doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
7114// a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
7115
7116// If IsLLQ(Q) is true, it means the question is both:
7117// (a) long-lived and
7118// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
7119// for multicast questions, we don't want to treat LongLived as anything special
7120#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
7121
7122mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
7123	{
7124	DNSQuestion *q;
7125	// Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
7126	// This prevents circular references, where two questions are each marked as a duplicate of the other.
7127	// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
7128	// further in the list.
7129	for (q = m->Questions; q && q != question; q=q->next)		// Scan our list for another question
7130		if (q->InterfaceID == question->InterfaceID &&			// with the same InterfaceID,
7131			SameQTarget(q, question)                &&			// and same unicast/multicast target settings
7132			q->qtype      == question->qtype        &&			// type,
7133			q->qclass     == question->qclass       &&			// class,
7134			IsLLQ(q)      == IsLLQ(question)        &&			// and long-lived status matches
7135			(!q->AuthInfo || question->AuthInfo)    &&			// to avoid deadlock, don't make public query dup of a private one
7136			q->qnamehash  == question->qnamehash    &&
7137			SameDomainName(&q->qname, &question->qname))		// and name
7138			return(q);
7139	return(mDNSNULL);
7140	}
7141
7142// This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
7143mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
7144	{
7145	DNSQuestion *q;
7146	for (q = m->Questions; q; q=q->next)		// Scan our list of questions
7147		if (q->DuplicateOf == question)			// To see if any questions were referencing this as their duplicate
7148			if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL)
7149				{
7150				// If q used to be a duplicate, but now is not,
7151				// then inherit the state from the question that's going away
7152				q->LastQTime         = question->LastQTime;
7153				q->ThisQInterval     = question->ThisQInterval;
7154				q->ExpectUnicastResp = question->ExpectUnicastResp;
7155				q->LastAnswerPktNum  = question->LastAnswerPktNum;
7156				q->RecentAnswerPkts  = question->RecentAnswerPkts;
7157				q->RequestUnicast    = question->RequestUnicast;
7158				q->LastQTxTime       = question->LastQTxTime;
7159				q->CNAMEReferrals    = question->CNAMEReferrals;
7160				q->nta               = question->nta;
7161				q->servAddr          = question->servAddr;
7162				q->servPort          = question->servPort;
7163				q->qDNSServer        = question->qDNSServer;
7164				q->unansweredQueries = question->unansweredQueries;
7165
7166				q->TargetQID         = question->TargetQID;
7167				q->LocalSocket       = question->LocalSocket;
7168
7169				q->state             = question->state;
7170			//	q->tcp               = question->tcp;
7171				q->ReqLease          = question->ReqLease;
7172				q->expire            = question->expire;
7173				q->ntries            = question->ntries;
7174				q->id                = question->id;
7175
7176				question->LocalSocket = mDNSNULL;
7177				question->nta        = mDNSNULL;	// If we've got a GetZoneData in progress, transfer it to the newly active question
7178			//	question->tcp        = mDNSNULL;
7179
7180				if (q->LocalSocket)
7181					debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7182
7183				if (q->nta)
7184					{
7185					LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7186					q->nta->ZoneDataContext = q;
7187					}
7188
7189				// Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
7190				if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer");
7191
7192				if (question->state == LLQ_Established)
7193					{
7194					LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
7195					question->state = 0;	// Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
7196					}
7197
7198				SetNextQueryTime(m,q);
7199				}
7200	}
7201
7202// Look up a DNS Server, matching by name in split-dns configurations.
7203mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name)
7204    {
7205	DNSServer *curmatch = mDNSNULL, *p;
7206	int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
7207
7208	for (p = m->DNSServers; p; p = p->next)
7209		{
7210		int scount = CountLabels(&p->domain);
7211		if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
7212			if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
7213				{ curmatch = p; curmatchlen = scount; }
7214		}
7215	return(curmatch);
7216	}
7217
7218#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
7219	(mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
7220
7221// Called in normal client context (lock not held)
7222mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
7223	{
7224	DNSQuestion *q;
7225	(void)n;    // Unused
7226	mDNS_Lock(m);
7227	LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
7228	for (q = m->Questions; q; q=q->next)
7229		if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
7230			startLLQHandshake(m, q);	// If ExternalPort is zero, will do StartLLQPolling instead
7231#if APPLE_OSX_mDNSResponder
7232	UpdateAutoTunnelDomainStatuses(m);
7233#endif
7234	mDNS_Unlock(m);
7235	}
7236
7237mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
7238	{
7239	if (question->Target.type && !ValidQuestionTarget(question))
7240		{
7241		LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
7242			question->Target.type, mDNSVal16(question->TargetPort));
7243		question->Target.type = mDNSAddrType_None;
7244		}
7245
7246	if (!question->Target.type) question->TargetPort = zeroIPPort;	// If question->Target specified clear TargetPort
7247
7248	question->TargetQID =
7249#ifndef UNICAST_DISABLED
7250		(question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) ||
7251		(question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)))
7252		? mDNS_NewMessageID(m) :
7253#endif // UNICAST_DISABLED
7254		zeroID;
7255
7256	debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7257
7258	if (m->rrcache_size == 0)	// Can't do queries if we have no cache space allocated
7259		return(mStatus_NoCache);
7260	else
7261		{
7262		int i;
7263		DNSQuestion **q;
7264
7265		if (!ValidateDomainName(&question->qname))
7266			{
7267			LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7268			return(mStatus_Invalid);
7269			}
7270
7271		// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
7272		q = &m->Questions;
7273		if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
7274		while (*q && *q != question) q=&(*q)->next;
7275
7276		if (*q)
7277			{
7278			LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list",
7279				question->qname.c, DNSTypeName(question->qtype), question);
7280			return(mStatus_AlreadyRegistered);
7281			}
7282
7283		*q = question;
7284
7285		// If this question is referencing a specific interface, verify it exists
7286		if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast)
7287			{
7288			NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
7289			if (!intf)
7290				LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
7291					question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
7292			}
7293
7294		// Note: In the case where we already have the answer to this question in our cache, that may be all the client
7295		// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
7296		// be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
7297		// If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
7298		// that to go out immediately.
7299		question->next              = mDNSNULL;
7300		question->qnamehash         = DomainNameHashValue(&question->qname);	// MUST do this before FindDuplicateQuestion()
7301		question->DelayAnswering    = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
7302		question->LastQTime         = m->timenow;
7303		question->ThisQInterval     = InitialQuestionInterval;					// MUST be > zero for an active question
7304		question->ExpectUnicastResp = 0;
7305		question->LastAnswerPktNum  = m->PktNum;
7306		question->RecentAnswerPkts  = 0;
7307		question->CurrentAnswers    = 0;
7308		question->LargeAnswers      = 0;
7309		question->UniqueAnswers     = 0;
7310		question->FlappingInterface1 = mDNSNULL;
7311		question->FlappingInterface2 = mDNSNULL;
7312		question->AuthInfo          = GetAuthInfoForQuestion(m, question);		// Must do this before calling FindDuplicateQuestion()
7313		question->DuplicateOf       = FindDuplicateQuestion(m, question);
7314		question->NextInDQList      = mDNSNULL;
7315		question->SendQNow          = mDNSNULL;
7316		question->SendOnAll         = mDNSfalse;
7317		question->RequestUnicast    = 0;
7318		question->LastQTxTime       = m->timenow;
7319		question->CNAMEReferrals    = 0;
7320
7321		// We'll create our question->LocalSocket on demand, if needed.
7322		// We won't need one for duplicate questions, or from questions answered immediately out of the cache.
7323		// We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
7324		// NAT mapping for receiving inbound add/remove events.
7325		question->LocalSocket       = mDNSNULL;
7326		question->qDNSServer        = mDNSNULL;
7327		question->unansweredQueries = 0;
7328		question->nta               = mDNSNULL;
7329		question->servAddr          = zeroAddr;
7330		question->servPort          = zeroIPPort;
7331		question->tcp               = mDNSNULL;
7332		question->NoAnswer          = NoAnswer_Normal;
7333
7334		question->state             = LLQ_InitialRequest;
7335		question->ReqLease          = 0;
7336		question->expire            = 0;
7337		question->ntries            = 0;
7338		question->id                = zeroOpaque64;
7339
7340		if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
7341
7342		for (i=0; i<DupSuppressInfoSize; i++)
7343			question->DupSuppress[i].InterfaceID = mDNSNULL;
7344
7345		debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
7346			question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
7347			question->LastQTime + question->ThisQInterval - m->timenow,
7348			question->DelayAnswering ? question->DelayAnswering - m->timenow : 0,
7349			question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf);
7350
7351		if (question->InterfaceID == mDNSInterface_LocalOnly)
7352			{
7353			if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
7354			}
7355		else
7356			{
7357			if (!m->NewQuestions) m->NewQuestions = question;
7358
7359			// If the question's id is non-zero, then it's Wide Area
7360			// MUST NOT do this Wide Area setup until near the end of
7361			// mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
7362			// NS, etc.) and if we haven't finished setting up our own question and setting
7363			// m->NewQuestions if necessary then we could end up recursively re-entering
7364			// this routine with the question list data structures in an inconsistent state.
7365			if (!mDNSOpaque16IsZero(question->TargetQID))
7366				{
7367				question->qDNSServer = GetServerForName(m, &question->qname);
7368				ActivateUnicastQuery(m, question, mDNSfalse);
7369
7370				// If long-lived query, and we don't have our NAT mapping active, start it now
7371				if (question->LongLived && !m->LLQNAT.clientContext)
7372					{
7373					m->LLQNAT.Protocol       = NATOp_MapUDP;
7374					m->LLQNAT.IntPort        = m->UnicastPort4;
7375					m->LLQNAT.RequestedPort  = m->UnicastPort4;
7376					m->LLQNAT.clientCallback = LLQNATCallback;
7377					m->LLQNAT.clientContext  = (void*)1; // Means LLQ NAT Traversal is active
7378					mDNS_StartNATOperation_internal(m, &m->LLQNAT);
7379					}
7380
7381#if APPLE_OSX_mDNSResponder
7382				if (question->LongLived)
7383					UpdateAutoTunnelDomainStatuses(m);
7384#endif
7385
7386				}
7387			SetNextQueryTime(m,question);
7388			}
7389
7390		return(mStatus_NoError);
7391		}
7392	}
7393
7394// CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
7395mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
7396	{
7397	debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
7398	mDNS_StopQuery_internal(m, &nta->question);
7399	mDNSPlatformMemFree(nta);
7400	}
7401
7402mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
7403	{
7404	const mDNSu32 slot = HashSlot(&question->qname);
7405	CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
7406	CacheRecord *rr;
7407	DNSQuestion **qp = &m->Questions;
7408
7409	//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7410
7411	if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
7412	while (*qp && *qp != question) qp=&(*qp)->next;
7413	if (*qp) *qp = (*qp)->next;
7414	else
7415		{
7416#if !ForceAlerts
7417		if (question->ThisQInterval >= 0)	// Only log error message if the query was supposed to be active
7418#endif
7419			LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
7420				question->qname.c, DNSTypeName(question->qtype));
7421#if ForceAlerts
7422		*(long*)0 = 0;
7423#endif
7424		return(mStatus_BadReferenceErr);
7425		}
7426
7427	// Take care to cut question from list *before* calling UpdateQuestionDuplicates
7428	UpdateQuestionDuplicates(m, question);
7429	// But don't trash ThisQInterval until afterwards.
7430	question->ThisQInterval = -1;
7431
7432	// If there are any cache records referencing this as their active question, then see if there is any
7433	// other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
7434	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
7435		{
7436		if (rr->CRActiveQuestion == question)
7437			{
7438			DNSQuestion *q;
7439			for (q = m->Questions; q; q=q->next)		// Scan our list of questions
7440				if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
7441					break;
7442			debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
7443			rr->CRActiveQuestion = q;		// Question used to be active; new value may or may not be null
7444			if (!q) m->rrcache_active--;	// If no longer active, decrement rrcache_active count
7445			}
7446		}
7447
7448	// If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
7449	// bump its pointer forward one question.
7450	if (m->CurrentQuestion == question)
7451		{
7452		debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
7453			question->qname.c, DNSTypeName(question->qtype));
7454		m->CurrentQuestion = question->next;
7455		}
7456
7457	if (m->NewQuestions == question)
7458		{
7459		debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
7460			question->qname.c, DNSTypeName(question->qtype));
7461		m->NewQuestions = question->next;
7462		}
7463
7464	if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
7465
7466	// Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
7467	question->next = mDNSNULL;
7468
7469	// LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
7470
7471	// And finally, cancel any associated GetZoneData operation that's still running.
7472	// Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
7473	// so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
7474	// invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
7475	// *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
7476	if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
7477	if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
7478	if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
7479	if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
7480		{
7481		// Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
7482		DNSQuestion *q;
7483		for (q = m->Questions; q; q=q->next)
7484			if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) break;
7485		if (!q)
7486			{
7487			if (!m->LLQNAT.clientContext)		// Should never happen, but just in case...
7488				LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
7489			else
7490				{
7491				LogInfo("Stopping LLQNAT");
7492				mDNS_StopNATOperation_internal(m, &m->LLQNAT);
7493				m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running
7494				}
7495			}
7496
7497		// If necessary, tell server it can delete this LLQ state
7498		if (question->state == LLQ_Established)
7499			{
7500			question->ReqLease = 0;
7501			sendLLQRefresh(m, question);
7502			// If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
7503			// We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
7504			// crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
7505			// we let that run out its natural course and complete asynchronously.
7506			if (question->tcp)
7507				{
7508				question->tcp->question = mDNSNULL;
7509				question->tcp           = mDNSNULL;
7510				}
7511			}
7512#if APPLE_OSX_mDNSResponder
7513		UpdateAutoTunnelDomainStatuses(m);
7514#endif
7515		}
7516
7517	return(mStatus_NoError);
7518	}
7519
7520mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
7521	{
7522	mStatus status;
7523	mDNS_Lock(m);
7524	status = mDNS_StartQuery_internal(m, question);
7525	mDNS_Unlock(m);
7526	return(status);
7527	}
7528
7529mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
7530	{
7531	mStatus status;
7532	mDNS_Lock(m);
7533	status = mDNS_StopQuery_internal(m, question);
7534	mDNS_Unlock(m);
7535	return(status);
7536	}
7537
7538// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
7539// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
7540// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
7541// specifically to catch and report if the client callback does try to make API calls
7542mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question)
7543	{
7544	mStatus status;
7545	DNSQuestion *qq;
7546	mDNS_Lock(m);
7547
7548	// Check if question is new -- don't want to give remove events for a question we haven't even answered yet
7549	for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break;
7550
7551	status = mDNS_StopQuery_internal(m, question);
7552	if (status == mStatus_NoError && !qq)
7553		{
7554		const CacheRecord *rr;
7555		const mDNSu32 slot = HashSlot(&question->qname);
7556		CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
7557		LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
7558		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
7559			if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
7560				{
7561				// Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
7562				if (question->QuestionCallback)
7563					question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
7564				}
7565		}
7566	mDNS_Unlock(m);
7567	return(status);
7568	}
7569
7570mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr)
7571	{
7572	mStatus status;
7573	mDNS_Lock(m);
7574	status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7575	if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
7576	mDNS_Unlock(m);
7577	return(status);
7578	}
7579
7580mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
7581	{
7582	mStatus status = mStatus_BadReferenceErr;
7583	CacheRecord *cr;
7584	mDNS_Lock(m);
7585	cr = FindIdenticalRecordInCache(m, rr);
7586	debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr));
7587	if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7588	if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
7589	mDNS_Unlock(m);
7590	return(status);
7591	}
7592
7593mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
7594	const domainname *const srv, const domainname *const domain,
7595	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
7596	{
7597	question->InterfaceID      = InterfaceID;
7598	question->Target           = zeroAddr;
7599	question->qtype            = kDNSType_PTR;
7600	question->qclass           = kDNSClass_IN;
7601	question->LongLived        = mDNSfalse;
7602	question->ExpectUnique     = mDNSfalse;
7603	question->ForceMCast       = ForceMCast;
7604	question->ReturnIntermed   = mDNSfalse;
7605	question->QuestionCallback = Callback;
7606	question->QuestionContext  = Context;
7607	if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
7608
7609#ifndef UNICAST_DISABLED
7610    if (Question_uDNS(question))
7611		{
7612		question->LongLived     = mDNStrue;
7613		question->ThisQInterval = InitialQuestionInterval;
7614		question->LastQTime     = m->timenow - question->ThisQInterval;
7615		}
7616#endif // UNICAST_DISABLED
7617	return(mDNS_StartQuery_internal(m, question));
7618	}
7619
7620mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
7621	const domainname *const srv, const domainname *const domain,
7622	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
7623	{
7624	mStatus status;
7625	mDNS_Lock(m);
7626	status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context);
7627	mDNS_Unlock(m);
7628	return(status);
7629	}
7630
7631mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
7632	{
7633	NetworkInterfaceInfo *intf;
7634	for (intf = m->HostInterfaces; intf; intf = intf->next)
7635	if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
7636	return(mDNSfalse);
7637	}
7638
7639mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7640	{
7641	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7642	mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
7643	if (!AddRecord) return;
7644	if (answer->rrtype != kDNSType_SRV) return;
7645
7646	query->info->port = answer->rdata->u.srv.port;
7647
7648	// If this is our first answer, then set the GotSRV flag and start the address query
7649	if (!query->GotSRV)
7650		{
7651		query->GotSRV             = mDNStrue;
7652		query->qAv4.InterfaceID   = answer->InterfaceID;
7653		AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
7654		query->qAv6.InterfaceID   = answer->InterfaceID;
7655		AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
7656		mDNS_StartQuery(m, &query->qAv4);
7657		// Only do the AAAA query if this machine actually has IPv6 active
7658		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
7659		}
7660	// If this is not our first answer, only re-issue the address query if the target host name has changed
7661	else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
7662		!SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
7663		{
7664		mDNS_StopQuery(m, &query->qAv4);
7665		if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
7666		if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
7667			{
7668			// If we get here, it means:
7669			// 1. This is not our first SRV answer
7670			// 2. The interface ID is different, but the target host and port are the same
7671			// This implies that we're seeing the exact same SRV record on more than one interface, so we should
7672			// make our address queries at least as broad as the original SRV query so that we catch all the answers.
7673			query->qAv4.InterfaceID = query->qSRV.InterfaceID;	// Will be mDNSInterface_Any, or a specific interface
7674			query->qAv6.InterfaceID = query->qSRV.InterfaceID;
7675			}
7676		else
7677			{
7678			query->qAv4.InterfaceID   = answer->InterfaceID;
7679			AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
7680			query->qAv6.InterfaceID   = answer->InterfaceID;
7681			AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
7682			}
7683		debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
7684		mDNS_StartQuery(m, &query->qAv4);
7685		// Only do the AAAA query if this machine actually has IPv6 active
7686		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
7687		}
7688	else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
7689		{
7690		if (++query->Answers >= 100)
7691			debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
7692				query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
7693				mDNSVal16(answer->rdata->u.srv.port));
7694		query->ServiceInfoQueryCallback(m, query);
7695		}
7696	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7697	// callback function is allowed to do anything, including deleting this query and freeing its memory.
7698	}
7699
7700mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7701	{
7702	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7703	if (!AddRecord) return;
7704	if (answer->rrtype != kDNSType_TXT) return;
7705	if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
7706
7707	query->GotTXT       = mDNStrue;
7708	query->info->TXTlen = answer->rdlength;
7709	query->info->TXTinfo[0] = 0;		// In case answer->rdlength is zero
7710	mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
7711
7712	verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
7713
7714	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7715	// callback function is allowed to do anything, including deleting this query and freeing its memory.
7716	if (query->ServiceInfoQueryCallback && query->GotADD)
7717		{
7718		if (++query->Answers >= 100)
7719			debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
7720				query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
7721		query->ServiceInfoQueryCallback(m, query);
7722		}
7723	}
7724
7725mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
7726	{
7727	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
7728	//LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
7729	if (!AddRecord) return;
7730
7731	if (answer->rrtype == kDNSType_A)
7732		{
7733		query->info->ip.type = mDNSAddrType_IPv4;
7734		query->info->ip.ip.v4 = answer->rdata->u.ipv4;
7735		}
7736	else if (answer->rrtype == kDNSType_AAAA)
7737		{
7738		query->info->ip.type = mDNSAddrType_IPv6;
7739		query->info->ip.ip.v6 = answer->rdata->u.ipv6;
7740		}
7741	else
7742		{
7743		debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
7744		return;
7745		}
7746
7747	query->GotADD = mDNStrue;
7748	query->info->InterfaceID = answer->InterfaceID;
7749
7750	verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
7751
7752	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
7753	// callback function is allowed to do anything, including deleting this query and freeing its memory.
7754	if (query->ServiceInfoQueryCallback && query->GotTXT)
7755		{
7756		if (++query->Answers >= 100)
7757			debugf(answer->rrtype == kDNSType_A ?
7758				"**** WARNING **** have given %lu answers for %##s (A) %.4a" :
7759				"**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
7760				query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
7761		query->ServiceInfoQueryCallback(m, query);
7762		}
7763	}
7764
7765// On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
7766// If the query is not interface-specific, then InterfaceID may be zero
7767// Each time the Callback is invoked, the remainder of the fields will have been filled in
7768// In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
7769mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
7770	ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
7771	{
7772	mStatus status;
7773	mDNS_Lock(m);
7774
7775	query->qSRV.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
7776	query->qSRV.InterfaceID         = info->InterfaceID;
7777	query->qSRV.Target              = zeroAddr;
7778	AssignDomainName(&query->qSRV.qname, &info->name);
7779	query->qSRV.qtype               = kDNSType_SRV;
7780	query->qSRV.qclass              = kDNSClass_IN;
7781	query->qSRV.LongLived           = mDNSfalse;
7782	query->qSRV.ExpectUnique        = mDNStrue;
7783	query->qSRV.ForceMCast          = mDNSfalse;
7784	query->qSRV.ReturnIntermed      = mDNSfalse;
7785	query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
7786	query->qSRV.QuestionContext     = query;
7787
7788	query->qTXT.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
7789	query->qTXT.InterfaceID         = info->InterfaceID;
7790	query->qTXT.Target              = zeroAddr;
7791	AssignDomainName(&query->qTXT.qname, &info->name);
7792	query->qTXT.qtype               = kDNSType_TXT;
7793	query->qTXT.qclass              = kDNSClass_IN;
7794	query->qTXT.LongLived           = mDNSfalse;
7795	query->qTXT.ExpectUnique        = mDNStrue;
7796	query->qTXT.ForceMCast          = mDNSfalse;
7797	query->qTXT.ReturnIntermed      = mDNSfalse;
7798	query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
7799	query->qTXT.QuestionContext     = query;
7800
7801	query->qAv4.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
7802	query->qAv4.InterfaceID         = info->InterfaceID;
7803	query->qAv4.Target              = zeroAddr;
7804	query->qAv4.qname.c[0]          = 0;
7805	query->qAv4.qtype               = kDNSType_A;
7806	query->qAv4.qclass              = kDNSClass_IN;
7807	query->qAv4.LongLived           = mDNSfalse;
7808	query->qAv4.ExpectUnique        = mDNStrue;
7809	query->qAv4.ForceMCast          = mDNSfalse;
7810	query->qAv4.ReturnIntermed      = mDNSfalse;
7811	query->qAv4.QuestionCallback    = FoundServiceInfo;
7812	query->qAv4.QuestionContext     = query;
7813
7814	query->qAv6.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
7815	query->qAv6.InterfaceID         = info->InterfaceID;
7816	query->qAv6.Target              = zeroAddr;
7817	query->qAv6.qname.c[0]          = 0;
7818	query->qAv6.qtype               = kDNSType_AAAA;
7819	query->qAv6.qclass              = kDNSClass_IN;
7820	query->qAv6.LongLived           = mDNSfalse;
7821	query->qAv6.ExpectUnique        = mDNStrue;
7822	query->qAv6.ForceMCast          = mDNSfalse;
7823	query->qAv6.ReturnIntermed      = mDNSfalse;
7824	query->qAv6.QuestionCallback    = FoundServiceInfo;
7825	query->qAv6.QuestionContext     = query;
7826
7827	query->GotSRV                   = mDNSfalse;
7828	query->GotTXT                   = mDNSfalse;
7829	query->GotADD                   = mDNSfalse;
7830	query->Answers                  = 0;
7831
7832	query->info                     = info;
7833	query->ServiceInfoQueryCallback = Callback;
7834	query->ServiceInfoQueryContext  = Context;
7835
7836//	info->name      = Must already be set up by client
7837//	info->interface = Must already be set up by client
7838	info->ip        = zeroAddr;
7839	info->port      = zeroIPPort;
7840	info->TXTlen    = 0;
7841
7842	// We use mDNS_StartQuery_internal here because we're already holding the lock
7843	status = mDNS_StartQuery_internal(m, &query->qSRV);
7844	if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
7845	if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
7846
7847	mDNS_Unlock(m);
7848	return(status);
7849	}
7850
7851mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
7852	{
7853	mDNS_Lock(m);
7854	// We use mDNS_StopQuery_internal here because we're already holding the lock
7855	if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
7856	if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
7857	if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
7858	if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
7859	mDNS_Unlock(m);
7860	}
7861
7862mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
7863	const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
7864	{
7865	question->InterfaceID      = InterfaceID;
7866	question->Target           = zeroAddr;
7867	question->qtype            = kDNSType_PTR;
7868	question->qclass           = kDNSClass_IN;
7869	question->LongLived        = mDNSfalse;
7870	question->ExpectUnique     = mDNSfalse;
7871	question->ForceMCast       = mDNSfalse;
7872	question->ReturnIntermed   = mDNSfalse;
7873	question->QuestionCallback = Callback;
7874	question->QuestionContext  = Context;
7875	if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
7876	if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
7877	if (!dom) dom = &localdomain;
7878	if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
7879	return(mDNS_StartQuery(m, question));
7880	}
7881
7882// ***************************************************************************
7883#if COMPILER_LIKES_PRAGMA_MARK
7884#pragma mark -
7885#pragma mark - Responder Functions
7886#endif
7887
7888mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
7889	{
7890	mStatus status;
7891	mDNS_Lock(m);
7892	status = mDNS_Register_internal(m, rr);
7893	mDNS_Unlock(m);
7894	return(status);
7895	}
7896
7897mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
7898	const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
7899	{
7900#ifndef UNICAST_DISABLED
7901	mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
7902#else
7903	mDNSBool unicast = mDNSfalse;
7904#endif
7905
7906	if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
7907		{
7908		LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
7909		return(mStatus_Invalid);
7910		}
7911
7912	mDNS_Lock(m);
7913
7914	// If TTL is unspecified, leave TTL unchanged
7915	if (newttl == 0) newttl = rr->resrec.rroriginalttl;
7916
7917	// If we already have an update queued up which has not gone through yet,
7918	// give the client a chance to free that memory
7919	if (!unicast && rr->NewRData)
7920		{
7921		RData *n = rr->NewRData;
7922		rr->NewRData = mDNSNULL;			// Clear the NewRData pointer ...
7923		if (rr->UpdateCallback)
7924			rr->UpdateCallback(m, rr, n);	// ...and let the client free this memory, if necessary
7925		}
7926
7927	rr->NewRData             = newrdata;
7928	rr->newrdlength          = newrdlength;
7929	rr->UpdateCallback       = Callback;
7930
7931	if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
7932
7933	if (rr->resrec.rroriginalttl == newttl &&
7934		rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
7935		CompleteRDataUpdate(m, rr);
7936	else
7937		{
7938		domainlabel name;
7939		domainname type, domain;
7940		DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
7941		rr->AnnounceCount = InitialAnnounceCount;
7942		// iChat often does suprious record updates where no data has changed. For the _presence service type, using
7943		// name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
7944		// update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
7945		// even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
7946		// To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
7947		if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
7948		InitializeLastAPTime(m, rr);
7949		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
7950		if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
7951		if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
7952		if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
7953		if (rr->UpdateCredits <= 5)
7954			{
7955			mDNSu32 delay = 6 - rr->UpdateCredits;		// Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
7956			if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
7957			rr->ThisAPInterval *= 4;
7958			rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
7959			LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
7960				rr->resrec.name->c, delay, delay > 1 ? "s" : "");
7961			}
7962		rr->resrec.rroriginalttl = newttl;
7963		}
7964
7965	mDNS_Unlock(m);
7966	return(mStatus_NoError);
7967	}
7968
7969// Note: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
7970// the record list and/or question list.
7971// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
7972mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
7973	{
7974	mStatus status;
7975	mDNS_Lock(m);
7976	status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7977	mDNS_Unlock(m);
7978	return(status);
7979	}
7980
7981// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
7982mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
7983
7984mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
7985	{
7986	NetworkInterfaceInfo *intf;
7987	for (intf = m->HostInterfaces; intf; intf = intf->next)
7988		if (intf->Advertise) break;
7989	return(intf);
7990	}
7991
7992mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
7993	{
7994	char buffer[MAX_REVERSE_MAPPING_NAME];
7995	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
7996	if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
7997
7998	// Send dynamic update for non-linklocal IPv4 Addresses
7999	mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kHostNameTTL, kDNSRecordTypeUnique,      mDNS_HostNameCallback, set);
8000	mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
8001	mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique,      mDNSNULL, mDNSNULL);
8002
8003#if ANSWER_REMOTE_HOSTNAME_QUERIES
8004	set->RR_A    .AllowRemoteQuery  = mDNStrue;
8005	set->RR_PTR  .AllowRemoteQuery  = mDNStrue;
8006	set->RR_HINFO.AllowRemoteQuery  = mDNStrue;
8007#endif
8008	// 1. Set up Address record to map from host name ("foo.local.") to IP address
8009	// 2. Set up reverse-lookup PTR record to map from our address back to our host name
8010	AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
8011	if (set->ip.type == mDNSAddrType_IPv4)
8012		{
8013		set->RR_A.resrec.rrtype = kDNSType_A;
8014		set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
8015		// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
8016		mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
8017			set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
8018		}
8019	else if (set->ip.type == mDNSAddrType_IPv6)
8020		{
8021		int i;
8022		set->RR_A.resrec.rrtype = kDNSType_AAAA;
8023		set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
8024		for (i = 0; i < 16; i++)
8025			{
8026			static const char hexValues[] = "0123456789ABCDEF";
8027			buffer[i * 4    ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
8028			buffer[i * 4 + 1] = '.';
8029			buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
8030			buffer[i * 4 + 3] = '.';
8031			}
8032		mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
8033		}
8034
8035	MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
8036	set->RR_PTR.AutoTarget = Target_AutoHost;	// Tell mDNS that the target of this PTR is to be kept in sync with our host name
8037	set->RR_PTR.ForceMCast = mDNStrue;			// This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
8038
8039	set->RR_A.RRSet = &primary->RR_A;			// May refer to self
8040
8041	mDNS_Register_internal(m, &set->RR_A);
8042	mDNS_Register_internal(m, &set->RR_PTR);
8043
8044	if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
8045		{
8046		mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
8047		AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
8048		set->RR_HINFO.DependentOn = &set->RR_A;
8049		mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
8050		p += 1 + (int)p[0];
8051		mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
8052		mDNS_Register_internal(m, &set->RR_HINFO);
8053		}
8054	else
8055		{
8056		debugf("Not creating HINFO record: platform support layer provided no information");
8057		set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
8058		}
8059	}
8060
8061mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
8062	{
8063	NetworkInterfaceInfo *intf;
8064
8065    // If we still have address records referring to this one, update them
8066	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
8067	AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
8068	for (intf = m->HostInterfaces; intf; intf = intf->next)
8069		if (intf->RR_A.RRSet == &set->RR_A)
8070			intf->RR_A.RRSet = A;
8071
8072	// Unregister these records.
8073	// When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
8074	// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
8075	// Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
8076	// To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
8077	if (set->RR_A.    resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A,     mDNS_Dereg_normal);
8078	if (set->RR_PTR.  resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR,   mDNS_Dereg_normal);
8079	if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
8080	}
8081
8082mDNSexport void mDNS_SetFQDN(mDNS *const m)
8083	{
8084	domainname newmname;
8085	NetworkInterfaceInfo *intf;
8086	AuthRecord *rr;
8087	newmname.c[0] = 0;
8088
8089	if (!AppendDomainLabel(&newmname, &m->hostlabel))  { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8090	if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
8091
8092	mDNS_Lock(m);
8093
8094	if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged");
8095	else
8096		{
8097		AssignDomainName(&m->MulticastHostname, &newmname);
8098
8099		// 1. Stop advertising our address records on all interfaces
8100		for (intf = m->HostInterfaces; intf; intf = intf->next)
8101			if (intf->Advertise) DeadvertiseInterface(m, intf);
8102
8103		// 2. Start advertising our address records using the new name
8104		for (intf = m->HostInterfaces; intf; intf = intf->next)
8105			if (intf->Advertise) AdvertiseInterface(m, intf);
8106		}
8107
8108	// 3. Make sure that any AutoTarget SRV records (and the like) get updated
8109	for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
8110	for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
8111
8112	mDNS_Unlock(m);
8113	}
8114
8115mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8116	{
8117	(void)rr;	// Unused parameter
8118
8119	#if MDNS_DEBUGMSGS
8120		{
8121		char *msg = "Unknown result";
8122		if      (result == mStatus_NoError)      msg = "Name registered";
8123		else if (result == mStatus_NameConflict) msg = "Name conflict";
8124		debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
8125		}
8126	#endif
8127
8128	if (result == mStatus_NoError)
8129		{
8130		// Notify the client that the host name is successfully registered
8131		if (m->MainCallback)
8132			m->MainCallback(m, mStatus_NoError);
8133		}
8134	else if (result == mStatus_NameConflict)
8135		{
8136		domainlabel oldlabel = m->hostlabel;
8137
8138		// 1. First give the client callback a chance to pick a new name
8139		if (m->MainCallback)
8140			m->MainCallback(m, mStatus_NameConflict);
8141
8142		// 2. If the client callback didn't do it, add (or increment) an index ourselves
8143		// This needs to be case-INSENSITIVE compare, because we need to know that the name has been changed so as to
8144		// remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
8145		if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
8146			IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
8147
8148		// 3. Generate the FQDNs from the hostlabel,
8149		// and make sure all SRV records, etc., are updated to reference our new hostname
8150		mDNS_SetFQDN(m);
8151		LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
8152		}
8153	else if (result == mStatus_MemFree)
8154		{
8155		// .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
8156		// mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
8157		debugf("mDNS_HostNameCallback: MemFree (ignored)");
8158		}
8159	else
8160		LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result,  rr->resrec.name->c);
8161	}
8162
8163mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
8164	{
8165	NetworkInterfaceInfo *intf;
8166	active->IPv4Available = mDNSfalse;
8167	active->IPv6Available = mDNSfalse;
8168	for (intf = m->HostInterfaces; intf; intf = intf->next)
8169		if (intf->InterfaceID == active->InterfaceID)
8170			{
8171			if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
8172			if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
8173			}
8174	}
8175
8176mDNSlocal void RestartRecordGetZoneData(mDNS * const m)
8177	{
8178	AuthRecord *rr;
8179	ServiceRecordSet *s;
8180
8181	for (rr = m->ResourceRecords; rr; rr=rr->next)
8182		if (AuthRecord_uDNS(rr))
8183			{
8184			debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c);
8185			if (rr->nta) CancelGetZoneData(m, rr->nta);
8186			rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
8187			}
8188
8189	for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
8190		{
8191		debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
8192		if (s->srs_nta) CancelGetZoneData(m, s->srs_nta);
8193		s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
8194		}
8195	}
8196
8197mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set)
8198	{
8199	int i;
8200	set->NetWakeBrowse.ThisQInterval = -1;
8201	for (i=0; i<3; i++)
8202		{
8203		set->NetWakeResolve[i].ThisQInterval = -1;
8204		set->SPSAddr[i].type = mDNSAddrType_None;
8205		}
8206	set->NextSPSAttempt     = -1;
8207	set->NextSPSAttemptTime = m->timenow;
8208	}
8209
8210mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
8211	{
8212	NetworkInterfaceInfo *p = m->HostInterfaces;
8213	while (p && p != set) p=p->next;
8214	if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
8215
8216	if (set->InterfaceActive)
8217		{
8218		LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
8219		mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set);
8220		}
8221	}
8222
8223mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set)
8224	{
8225	NetworkInterfaceInfo *p = m->HostInterfaces;
8226	while (p && p != set) p=p->next;
8227	if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; }
8228
8229	if (set->NetWakeBrowse.ThisQInterval >= 0)
8230		{
8231		int i;
8232		LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip);
8233
8234		// Stop our browse and resolve operations
8235		mDNS_StopQuery_internal(m, &set->NetWakeBrowse);
8236		for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]);
8237
8238		// Make special call to the browse callback to let it know it can to remove all records for this interface
8239		if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
8240
8241		// Reset our variables back to initial state, so we're ready for when NetWake is turned back on
8242		// (includes resetting NetWakeBrowse.ThisQInterval back to -1)
8243		InitializeNetWakeState(m, set);
8244		}
8245	}
8246
8247mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
8248	{
8249	AuthRecord *rr;
8250	mDNSBool FirstOfType = mDNStrue;
8251	NetworkInterfaceInfo **p = &m->HostInterfaces;
8252
8253	if (!set->InterfaceID)
8254		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
8255
8256	if (!mDNSAddressIsValidNonZero(&set->mask))
8257		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
8258
8259	mDNS_Lock(m);
8260
8261	// Assume this interface will be active now, unless we find a duplicate already in the list
8262	set->InterfaceActive = mDNStrue;
8263	set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
8264	set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
8265
8266	InitializeNetWakeState(m, set);
8267
8268	// Scan list to see if this InterfaceID is already represented
8269	while (*p)
8270		{
8271		if (*p == set)
8272			{
8273			LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
8274			mDNS_Unlock(m);
8275			return(mStatus_AlreadyRegistered);
8276			}
8277
8278		if ((*p)->InterfaceID == set->InterfaceID)
8279			{
8280			// This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
8281			set->InterfaceActive = mDNSfalse;
8282			if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
8283			if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
8284			if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
8285			}
8286
8287		p=&(*p)->next;
8288		}
8289
8290	set->next = mDNSNULL;
8291	*p = set;
8292
8293	if (set->Advertise)
8294		AdvertiseInterface(m, set);
8295
8296	LogInfo("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
8297		set->InterfaceActive ?
8298			"not represented in list; marking active and retriggering queries" :
8299			"already represented in list; marking inactive for now");
8300
8301	if (set->NetWake) mDNS_ActivateNetWake_internal(m, set);
8302
8303	// In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8304	// giving the false impression that there's an active representative of this interface when there really isn't.
8305	// Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
8306	// even if we believe that we previously had an active representative of this interface.
8307	if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
8308		{
8309		DNSQuestion *q;
8310		// If flapping, delay between first and second queries is eight seconds instead of one
8311		mDNSs32 delay    = flapping ? mDNSPlatformOneSecond   * 5 : 0;
8312		mDNSu8  announce = flapping ? (mDNSu8)1                   : InitialAnnounceCount;
8313		mDNSs32 newSS    = 0;
8314
8315		// Use a small amount of randomness:
8316		// In the case of a network administrator turning on an Ethernet hub so that all the
8317		// connected machines establish link at exactly the same time, we don't want them all
8318		// to go and hit the network with identical queries at exactly the same moment.
8319		newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
8320#if APPLE_OSX_mDNSResponder
8321		// We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
8322		// of network change notifications in a row, and we don't know when we're done getting notified.
8323		// Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
8324		newSS += mDNSPlatformOneSecond * 2;
8325#endif
8326		if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS;
8327
8328		if (flapping)
8329			{
8330			LogMsg("Note: RegisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
8331				set->ifname, &set->ip);
8332			if (!m->SuppressProbes ||
8333				m->SuppressProbes - (m->timenow + delay) < 0)
8334				m->SuppressProbes = (m->timenow + delay);
8335			}
8336
8337		for (q = m->Questions; q; q=q->next)								// Scan our list of questions
8338			if (mDNSOpaque16IsZero(q->TargetQID))
8339				if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)		// If non-specific Q, or Q on this specific interface,
8340					{															// then reactivate this question
8341					mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
8342					mDNSs32 initial  = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
8343					mDNSs32 qdelay   = dodelay ? mDNSPlatformOneSecond * 5 : 0;
8344					if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
8345
8346					if (!q->ThisQInterval || q->ThisQInterval > initial)
8347						{
8348						q->ThisQInterval = initial;
8349						q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
8350						}
8351					q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
8352					q->RecentAnswerPkts = 0;
8353					SetNextQueryTime(m,q);
8354					}
8355
8356		// For all our non-specific authoritative resource records (and any dormant records specific to this interface)
8357		// we now need them to re-probe if necessary, and then re-announce.
8358		for (rr = m->ResourceRecords; rr; rr=rr->next)
8359			if (!AuthRecord_uDNS(rr))
8360				if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
8361					{
8362					if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
8363					rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
8364					if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
8365					InitializeLastAPTime(m, rr);
8366					}
8367		}
8368
8369	RestartRecordGetZoneData(m);
8370
8371	mDNS_Unlock(m);
8372	return(mStatus_NoError);
8373	}
8374
8375// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
8376// the record list and/or question list.
8377// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8378mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
8379	{
8380	NetworkInterfaceInfo **p = &m->HostInterfaces;
8381
8382	mDNSBool revalidate = mDNSfalse;
8383	// If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
8384	// time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
8385	// still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
8386	if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
8387
8388	mDNS_Lock(m);
8389
8390	// Find this record in our list
8391	while (*p && *p != set) p=&(*p)->next;
8392	if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
8393
8394	mDNS_DeactivateNetWake_internal(m, set);
8395
8396	// Unlink this record from our list
8397	*p = (*p)->next;
8398	set->next = mDNSNULL;
8399
8400	if (!set->InterfaceActive)
8401		{
8402		// If this interface not the active member of its set, update the v4/v6Available flags for the active member
8403		NetworkInterfaceInfo *intf;
8404		for (intf = m->HostInterfaces; intf; intf = intf->next)
8405			if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
8406				UpdateInterfaceProtocols(m, intf);
8407		}
8408	else
8409		{
8410		NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID);
8411		if (intf)
8412			{
8413			LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
8414				" making it active", set->InterfaceID, set->ifname, &set->ip);
8415			if (intf->InterfaceActive)
8416				LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip);
8417			intf->InterfaceActive = mDNStrue;
8418			UpdateInterfaceProtocols(m, intf);
8419
8420			if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf);
8421
8422			// See if another representative *of the same type* exists. If not, we mave have gone from
8423			// dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
8424			for (intf = m->HostInterfaces; intf; intf = intf->next)
8425				if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
8426					break;
8427			if (!intf) revalidate = mDNStrue;
8428			}
8429		else
8430			{
8431			mDNSu32 slot;
8432			CacheGroup *cg;
8433			CacheRecord *rr;
8434			DNSQuestion *q;
8435			DNSServer *s;
8436
8437			LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
8438				" marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
8439
8440			if (flapping)
8441				LogMsg("Note: DeregisterInterface: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
8442					set->ifname, &set->ip);
8443
8444			// 1. Deactivate any questions specific to this interface, and tag appropriate questions
8445			// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
8446			for (q = m->Questions; q; q=q->next)
8447				{
8448				if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
8449				if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
8450					{
8451					q->FlappingInterface2 = q->FlappingInterface1;
8452					q->FlappingInterface1 = set->InterfaceID;		// Keep history of the last two interfaces to go away
8453					}
8454				}
8455
8456			// 2. Flush any cache records received on this interface
8457			revalidate = mDNSfalse;		// Don't revalidate if we're flushing the records
8458			FORALL_CACHERECORDS(slot, cg, rr)
8459				if (rr->resrec.InterfaceID == set->InterfaceID)
8460					{
8461					// If this interface is deemed flapping,
8462					// postpone deleting the cache records in case the interface comes back again
8463					if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
8464					else
8465						{
8466						// We want these record to go away in 30 seconds
8467						// We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
8468						// if the interface does come back, any relevant questions will be reactivated anyway
8469						mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
8470						rr->UnansweredQueries = MaxUnansweredQueries;
8471						}
8472					}
8473
8474			// 3. Any DNS servers specific to this interface are now unusable
8475			for (s = m->DNSServers; s; s = s->next)
8476				if (s->interface == set->InterfaceID)
8477					{
8478					s->interface = mDNSInterface_Any;
8479					s->teststate = DNSServer_Disabled;
8480					}
8481			}
8482		}
8483
8484	// If we were advertising on this interface, deregister those address and reverse-lookup records now
8485	if (set->Advertise) DeadvertiseInterface(m, set);
8486
8487	// If we have any cache records received on this interface that went away, then re-verify them.
8488	// In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
8489	// giving the false impression that there's an active representative of this interface when there really isn't.
8490	// Don't need to do this when shutting down, because *all* interfaces are about to go away
8491	if (revalidate && !m->ShutdownTime)
8492		{
8493		mDNSu32 slot;
8494		CacheGroup *cg;
8495		CacheRecord *rr;
8496		m->NextCacheCheck = m->timenow;
8497		FORALL_CACHERECORDS(slot, cg, rr)
8498			if (rr->resrec.InterfaceID == set->InterfaceID)
8499				mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
8500		}
8501
8502	mDNS_Unlock(m);
8503	}
8504
8505mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8506	{
8507	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
8508	(void)m;	// Unused parameter
8509
8510	#if MDNS_DEBUGMSGS
8511		{
8512		char *msg = "Unknown result";
8513		if      (result == mStatus_NoError)      msg = "Name Registered";
8514		else if (result == mStatus_NameConflict) msg = "Name Conflict";
8515		else if (result == mStatus_MemFree)      msg = "Memory Free";
8516		debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
8517		}
8518	#endif
8519
8520	// Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
8521	if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
8522
8523	// If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
8524	if (result == mStatus_NameConflict)
8525		{
8526		sr->Conflict = mDNStrue;				// Record that this service set had a conflict
8527		mDNS_DeregisterService(m, sr);			// Unlink the records from our list
8528		return;
8529		}
8530
8531	if (result == mStatus_MemFree)
8532		{
8533		// If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records,
8534		// are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
8535		// every record is finished cleaning up.
8536		mDNSu32 i;
8537		if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8538		if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8539		if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8540		if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
8541		for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
8542
8543		// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
8544		// then we can now report the NameConflict to the client
8545		if (sr->Conflict) result = mStatus_NameConflict;
8546
8547		if (sr->srs_nta)
8548			{
8549			LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV));
8550			CancelGetZoneData(m, sr->srs_nta);
8551			sr->srs_nta = mDNSNULL;
8552			}
8553		}
8554
8555	// CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
8556	// function is allowed to do anything, including deregistering this service and freeing its memory.
8557	if (sr->ServiceCallback)
8558		sr->ServiceCallback(m, sr, result);
8559	}
8560
8561mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
8562	{
8563	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
8564	if (sr->ServiceCallback)
8565		sr->ServiceCallback(m, sr, result);
8566	}
8567
8568#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8569mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
8570	{
8571	mDNSu32 i;
8572	ServiceRecordSet **p = &m->ServiceRegistrations;
8573	while (*p && *p != srs) p=&(*p)->uDNS_next;
8574	if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
8575
8576	srs->uDNS_next = mDNSNULL;
8577	*p = srs;
8578
8579	srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
8580	srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
8581	srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
8582	for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
8583
8584	srs->srs_uselease = mDNStrue;
8585
8586	if (srs->RR_SRV.AutoTarget)
8587		{
8588		// For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
8589		// advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
8590		// with the port number in our advertised SRV record automatically tracking the external mapped port.
8591		DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
8592		if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
8593		}
8594
8595	if (!GetServiceTarget(m, &srs->RR_SRV))
8596		{
8597		// defer registration until we've got a target
8598		LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
8599		srs->state   = regState_NoTarget;
8600		return mStatus_NoError;
8601		}
8602
8603	ActivateUnicastRegistration(m, &srs->RR_SRV);
8604	srs->state = regState_FetchingZoneData;
8605	return mStatus_NoError;
8606	}
8607#endif
8608
8609// Note:
8610// Name is first label of domain name (any dots in the name are actual dots, not label separators)
8611// Type is service type (e.g. "_ipp._tcp.")
8612// Domain is fully qualified domain name (i.e. ending with a null label)
8613// We always register a TXT, even if it is empty (so that clients are not
8614// left waiting forever looking for a nonexistent record.)
8615// If the host parameter is mDNSNULL or the root domain (ASCII NUL),
8616// then the default host name (m->MulticastHostname) is automatically used
8617// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
8618mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
8619	const domainlabel *const name, const domainname *const type, const domainname *const domain,
8620	const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
8621	AuthRecord *SubTypes, mDNSu32 NumSubTypes,
8622	const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
8623	{
8624	mStatus err;
8625	mDNSu32 i;
8626
8627	sr->state                  = regState_Zero;
8628	sr->srs_uselease           = 0;
8629	sr->TestForSelfConflict    = 0;
8630	sr->Private                = 0;
8631	sr->id                     = zeroID;
8632	sr->zone.c[0]              = 0;
8633	sr->SRSUpdateServer        = zeroAddr;
8634	sr->SRSUpdatePort          = zeroIPPort;
8635	mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
8636	sr->NATinfo.IntPort        = port;		// Record originally-requested port
8637	sr->ClientCallbackDeferred = 0;
8638	sr->DeferredStatus         = 0;
8639	sr->SRVUpdateDeferred      = 0;
8640	sr->SRVChanged             = 0;
8641	sr->tcp                    = mDNSNULL;
8642
8643	sr->ServiceCallback = Callback;
8644	sr->ServiceContext  = Context;
8645	sr->Conflict        = mDNSfalse;
8646
8647	sr->Extras          = mDNSNULL;
8648	sr->NumSubTypes     = NumSubTypes;
8649	sr->SubTypes        = SubTypes;
8650
8651	// Initialize the AuthRecord objects to sane values
8652	// Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
8653	mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
8654	mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared,   ServiceCallback, sr);
8655	mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
8656	mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
8657
8658	// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
8659	if (mDNSIPPortIsZero(port))
8660		return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
8661
8662	// If the client is registering an oversized TXT record,
8663	// it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
8664	if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
8665		sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
8666
8667	// Set up the record names
8668	// For now we only create an advisory record for the main type, not for subtypes
8669	// We need to gain some operational experience before we decide if there's a need to create them for subtypes too
8670	if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
8671		return(mStatus_BadParamErr);
8672	if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
8673	if (ConstructServiceName(&sr->RR_SRV.namestorage, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
8674	AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name);
8675
8676	// 1. Set up the ADV record rdata to advertise our service type
8677	AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
8678
8679	// 2. Set up the PTR record rdata to point to our service name
8680	// We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
8681	AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
8682	sr->RR_PTR.Additional1 = &sr->RR_SRV;
8683	sr->RR_PTR.Additional2 = &sr->RR_TXT;
8684
8685	// 2a. Set up any subtype PTRs to point to our service name
8686	// If the client is using subtypes, it is the client's responsibility to have
8687	// already set the first label of the record name to the subtype being registered
8688	for (i=0; i<NumSubTypes; i++)
8689		{
8690		domainname st;
8691		AssignDomainName(&st, sr->SubTypes[i].resrec.name);
8692		st.c[1+st.c[0]] = 0;			// Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
8693		AppendDomainName(&st, type);
8694		mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
8695		if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
8696		AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage);
8697		sr->SubTypes[i].Additional1 = &sr->RR_SRV;
8698		sr->SubTypes[i].Additional2 = &sr->RR_TXT;
8699		}
8700
8701	// 3. Set up the SRV record rdata.
8702	sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
8703	sr->RR_SRV.resrec.rdata->u.srv.weight   = 0;
8704	sr->RR_SRV.resrec.rdata->u.srv.port     = port;
8705
8706	// Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
8707	if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host);
8708	else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
8709
8710	// 4. Set up the TXT record rdata,
8711	// and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
8712	if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
8713	else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
8714		{
8715		sr->RR_TXT.resrec.rdlength = txtlen;
8716		if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
8717		mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen);
8718		}
8719	sr->RR_TXT.DependentOn = &sr->RR_SRV;
8720
8721	sr->srs_nta = mDNSNULL;
8722
8723#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8724	// If the client has specified an explicit InterfaceID,
8725	// then we do a multicast registration on that interface, even for unicast domains.
8726	if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
8727		{
8728		mStatus status;
8729		mDNS_Lock(m);
8730		// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
8731		// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
8732		// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
8733		// (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
8734		if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
8735
8736		status = uDNS_RegisterService(m, sr);
8737		mDNS_Unlock(m);
8738		return(status);
8739		}
8740#endif
8741
8742	mDNS_Lock(m);
8743	err = mDNS_Register_internal(m, &sr->RR_SRV);
8744	if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
8745	// We register the RR_PTR last, because we want to be sure that in the event of a forced call to
8746	// mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
8747	// the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
8748	// the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
8749	// make sure we've deregistered all our records and done any other necessary cleanup before that happens.
8750	if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
8751	for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
8752	if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
8753
8754	mDNS_Unlock(m);
8755
8756	if (err) mDNS_DeregisterService(m, sr);
8757	return(err);
8758	}
8759
8760mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
8761	{
8762	(void)m;		// Unused
8763	(void)rr;		// Unused
8764	(void)result;	// Unused
8765	LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr));
8766	}
8767
8768mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
8769	ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
8770	{
8771	ExtraResourceRecord **e;
8772	mStatus status;
8773
8774	extra->next = mDNSNULL;
8775	mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
8776		extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
8777	AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
8778
8779	mDNS_Lock(m);
8780	e = &sr->Extras;
8781	while (*e) e = &(*e)->next;
8782
8783	if (ttl == 0) ttl = kStandardTTL;
8784
8785	extra->r.DependentOn = &sr->RR_SRV;
8786
8787	debugf("mDNS_AddRecordToService adding record to %##s %s %d",
8788		extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
8789
8790	status = mDNS_Register_internal(m, &extra->r);
8791	if (status == mStatus_NoError)
8792		{
8793		*e = extra;
8794#ifndef UNICAST_DISABLED
8795		if (AuthRecord_uDNS(&sr->RR_SRV))
8796			{
8797			extra->r.resrec.RecordType = kDNSRecordTypeShared;	// don't want it to conflict with the service name (???)
8798			extra->r.RecordCallback = DummyCallback;	// don't generate callbacks for extra RRs for unicast services (WHY NOT????)
8799			if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
8800			}
8801#endif
8802		}
8803
8804	mDNS_Unlock(m);
8805	return(status);
8806	}
8807
8808mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
8809	mDNSRecordCallback MemFreeCallback, void *Context)
8810	{
8811	ExtraResourceRecord **e;
8812	mStatus status;
8813
8814	mDNS_Lock(m);
8815	e = &sr->Extras;
8816	while (*e && *e != extra) e = &(*e)->next;
8817	if (!*e)
8818		{
8819		debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
8820		status = mStatus_BadReferenceErr;
8821		}
8822	else
8823		{
8824		debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
8825		extra->r.RecordCallback = MemFreeCallback;
8826		extra->r.RecordContext  = Context;
8827		*e = (*e)->next;
8828		status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
8829		}
8830	mDNS_Unlock(m);
8831	return(status);
8832	}
8833
8834mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
8835	{
8836	// Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
8837	// mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
8838	domainlabel name1, name2;
8839	domainname type, domain;
8840	const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target;
8841	ExtraResourceRecord *extras = sr->Extras;
8842	mStatus err;
8843
8844	DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
8845	if (!newname)
8846		{
8847		name2 = name1;
8848		IncrementLabelSuffix(&name2, mDNStrue);
8849		newname = &name2;
8850		}
8851
8852	if (SameDomainName(&domain, &localdomain))
8853		debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
8854	else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
8855
8856	err = mDNS_RegisterService(m, sr, newname, &type, &domain,
8857		host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
8858		sr->SubTypes, sr->NumSubTypes,
8859		sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
8860
8861	// mDNS_RegisterService() just reset sr->Extras to NULL.
8862	// Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
8863	// through the old list of extra records, and re-add them to our freshly created service registration
8864	while (!err && extras)
8865		{
8866		ExtraResourceRecord *e = extras;
8867		extras = extras->next;
8868		err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
8869		}
8870
8871	return(err);
8872	}
8873
8874// Note: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
8875// which may change the record list and/or question list.
8876// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
8877mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
8878	{
8879	// If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
8880	if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
8881
8882#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
8883	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
8884		{
8885		mStatus status;
8886		mDNS_Lock(m);
8887		status = uDNS_DeregisterService(m, sr);
8888		mDNS_Unlock(m);
8889		return(status);
8890		}
8891#endif
8892	if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
8893		{
8894		debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
8895		return(mStatus_BadReferenceErr);
8896		}
8897	else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
8898		{
8899		debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
8900		// Avoid race condition:
8901		// If a service gets a conflict, then we set the Conflict flag to tell us to generate
8902		// an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
8903		// If the client happens to deregister the service in the middle of that process, then
8904		// we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
8905		// instead of incorrectly promoting it to mStatus_NameConflict.
8906		// This race condition is exposed particularly when the conformance test generates
8907		// a whole batch of simultaneous conflicts across a range of services all advertised
8908		// using the same system default name, and if we don't take this precaution then
8909		// we end up incrementing m->nicelabel multiple times instead of just once.
8910		// <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
8911		sr->Conflict = mDNSfalse;
8912		return(mStatus_NoError);
8913		}
8914	else
8915		{
8916		mDNSu32 i;
8917		mStatus status;
8918		ExtraResourceRecord *e;
8919		mDNS_Lock(m);
8920		e = sr->Extras;
8921
8922		// We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
8923		// SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
8924		mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
8925		mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
8926
8927		mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
8928
8929		// We deregister all of the extra records, but we leave the sr->Extras list intact
8930		// in case the client wants to do a RenameAndReregister and reinstate the registration
8931		while (e)
8932			{
8933			mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
8934			e = e->next;
8935			}
8936
8937		for (i=0; i<sr->NumSubTypes; i++)
8938			mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
8939
8940		// Be sure to deregister the PTR last!
8941		// Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
8942		// which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
8943		// which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
8944		// we've deregistered all our records and done any other necessary cleanup before that happens.
8945		status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
8946		mDNS_Unlock(m);
8947		return(status);
8948		}
8949	}
8950
8951// Create a registration that asserts that no such service exists with this name.
8952// This can be useful where there is a given function is available through several protocols.
8953// For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
8954// protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
8955// "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
8956// could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
8957mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
8958	const domainlabel *const name, const domainname *const type, const domainname *const domain,
8959	const domainname *const host,
8960	const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
8961	{
8962	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
8963	if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
8964	rr->resrec.rdata->u.srv.priority    = 0;
8965	rr->resrec.rdata->u.srv.weight      = 0;
8966	rr->resrec.rdata->u.srv.port        = zeroIPPort;
8967	if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
8968	else rr->AutoTarget = Target_AutoHost;
8969	return(mDNS_Register(m, rr));
8970	}
8971
8972mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
8973	mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
8974	{
8975	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
8976	if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
8977	if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
8978	return(mDNS_Register(m, rr));
8979	}
8980
8981mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
8982	{
8983	mDNSOpaque16 id;
8984	int i;
8985	for (i=0; i<10; i++)
8986		{
8987		AuthRecord *r;
8988		DNSQuestion *q;
8989		id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
8990		for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue;
8991		for (q = m->Questions;       q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue;
8992		break;
8993		}
8994	debugf("mDNS_NewMessageID: %5d", mDNSVal16(id));
8995	return id;
8996	}
8997
8998// ***************************************************************************
8999#if COMPILER_LIKES_PRAGMA_MARK
9000#pragma mark -
9001#pragma mark - Sleep Proxy Server
9002#endif
9003
9004mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr)
9005	{
9006	// We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine.
9007	// If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine.
9008	// If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep)
9009	// then we'll transition out of probing state and start answering ARPs again.
9010	rr->resrec.RecordType = kDNSRecordTypeUnique;
9011	rr->ProbeCount        = DefaultProbeCountForTypeUnique;
9012	rr->AnnounceCount     = InitialAnnounceCount;
9013	InitializeLastAPTime(m, rr);
9014	}
9015
9016mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
9017	{
9018	static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } };
9019	static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } };	// Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
9020	static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } };	// Protocol address space (IP = 0x0800), hlen, plen
9021	static const mDNSOpaque16 ARP_op_request = { { 0, 1 } };
9022	const EthernetHeader *const eth = (const EthernetHeader *)p;
9023	const ARP_EthIP      *const arp = (const ARP_EthIP      *)(eth+1);
9024	const IPv4Header     *const v4  = (const IPv4Header     *)(eth+1);
9025	const IPv6Header     *const v6  = (const IPv6Header     *)(eth+1);
9026	if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger)
9027		{
9028		AuthRecord *rr;
9029		NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
9030		if (!intf) return;
9031
9032		debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa);
9033
9034		mDNS_Lock(m);
9035
9036		// Pass 1:
9037		// Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
9038		// We also process and answer ARPs from our own kernel (no special treatment for localhost).
9039		// We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
9040		// The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below.
9041		if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
9042			for (rr = m->ResourceRecords; rr; rr=rr->next)
9043				if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
9044					{
9045					static const char msg1[] = "ARP Req from owner -- re-probing";
9046					static const char msg2[] = "Ignoring  ARP Request from      ";
9047					static const char msg3[] = "Creating Local ARP Cache entry  ";
9048					static const char msg4[] = "Answering ARP Request from      ";
9049					const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
9050											(rr->AnnounceCount == InitialAnnounceCount)     ? msg2 :
9051											mDNSSameEthAddress(&arp->sha, &intf->MAC)       ? msg3 : msg4;
9052					LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
9053						InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
9054					if      (msg == msg1) RestartProbing(m, rr);
9055					else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID);
9056					else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b);
9057					}
9058
9059		// Pass 2:
9060		// For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
9061		// (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
9062		// so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
9063		// We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
9064		// If we see an apparently conflicting ARP, we check the sender hardware address:
9065		//   If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
9066		//   If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
9067		if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
9068			debugf("ARP from self for %.4a", &arp->tpa);
9069		else
9070			{
9071			if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
9072				for (rr = m->ResourceRecords; rr; rr=rr->next)
9073					if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
9074						{
9075						RestartProbing(m, rr);
9076						if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
9077							LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
9078								InterfaceNameForID(m, InterfaceID),
9079								mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request     " : "Response    ",
9080								&arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
9081						else
9082							{
9083							LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
9084								InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
9085							SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
9086							}
9087						}
9088			}
9089
9090		mDNS_Unlock(m);
9091		}
9092	else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
9093		{
9094		const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4;
9095		const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0);
9096		debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst);
9097		if (end >= required)
9098			{
9099			#define SSH_AsNumber 22
9100			#define ARD_AsNumber 3283
9101			#define IPSEC_AsNumber 4500
9102			static const mDNSIPPort SSH   = { { SSH_AsNumber   >> 8, SSH_AsNumber   & 0xFF } };
9103			static const mDNSIPPort ARD   = { { ARD_AsNumber   >> 8, ARD_AsNumber   & 0xFF } };
9104			static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } };
9105
9106			mDNSBool wake = mDNSfalse;
9107			mDNSIPPort port = zeroIPPort;
9108
9109			switch (v4->protocol)
9110				{
9111				#define XX wake ? "Received" : "Ignoring", end-p
9112				case  1:	LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
9113							break;
9114
9115				case  6:	{
9116							const TCPHeader *const tcp = (const TCPHeader *)trans;
9117							port = tcp->dst;
9118
9119							// Plan to wake if
9120							// (a) RST is not set, AND
9121							// (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
9122							wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1);
9123
9124							// For now, to reduce spurious wakeups, we wake only for TCP SYN,
9125							// except for ssh connections, where we'll wake for plain data packets too
9126							if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse;
9127
9128							LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX,
9129								&v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port),
9130								(tcp->flags & 2) ? " SYN" : "",
9131								(tcp->flags & 1) ? " FIN" : "",
9132								(tcp->flags & 4) ? " RST" : "");
9133							}
9134							break;
9135
9136				case 17:	{
9137							const UDPHeader *const udp = (const UDPHeader *)trans;
9138							mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);
9139							port = udp->dst;
9140							wake = mDNStrue;
9141
9142							// For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets
9143							if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF);
9144
9145							// For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
9146							// Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
9147							// except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
9148							// UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total
9149							if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
9150
9151							LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
9152							}
9153							break;
9154
9155				default:	LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst);
9156							break;
9157				}
9158
9159			if (wake)
9160				{
9161				AuthRecord *rr, *r2;
9162
9163				mDNS_Lock(m);
9164				for (rr = m->ResourceRecords; rr; rr=rr->next)
9165					if (rr->resrec.InterfaceID == InterfaceID &&
9166						rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst))
9167						{
9168						const mDNSu8 *const tp = (v4->protocol == 6) ? (mDNSu8 *)"\x4_tcp" : (mDNSu8 *)"\x4_udp";
9169						for (r2 = m->ResourceRecords; r2; r2=r2->next)
9170							if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
9171								r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
9172								SameDomainLabel(SkipLeadingLabels(r2->resrec.name, 2)->c, tp))
9173								break;
9174						if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr;	// So that we wake for BTMM IPSEC packets, even without a matching SRV record
9175						if (r2)
9176							{
9177							rr->AnnounceCount = 0;
9178							LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
9179								InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
9180							SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
9181							}
9182						else
9183							LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
9184								InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
9185						}
9186				mDNS_Unlock(m);
9187				}
9188			}
9189		}
9190	else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
9191		{
9192		debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst);
9193		(void)v6;
9194		}
9195	}
9196
9197mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name)
9198	{
9199	name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
9200		m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel);
9201	}
9202
9203mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
9204	{
9205	if (result == mStatus_NameConflict)
9206		mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
9207	else if (result == mStatus_MemFree)
9208		{
9209		if (m->SleepState)
9210			m->SPSState = 3;
9211		else
9212			{
9213			m->SPSState = (m->SPSSocket != mDNSNULL);
9214			if (m->SPSState)
9215				{
9216				domainlabel name;
9217				ConstructSleepProxyServerName(m, &name);
9218				mDNS_RegisterService(m, srs,
9219					&name, &SleepProxyServiceType, &localdomain,
9220					mDNSNULL, m->SPSSocket->port,				// Host, port
9221					(mDNSu8 *)"", 1,							// TXT data, length
9222					mDNSNULL, 0,								// Subtypes (none)
9223					mDNSInterface_Any,							// Interface ID
9224					SleepProxyServerCallback, mDNSNULL);		// Callback and context
9225				}
9226			LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped");
9227			}
9228		}
9229	}
9230
9231mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
9232	{
9233	// If turning off SPS, close our socket
9234	// (Do this first, BEFORE calling mDNS_DeregisterService below)
9235	if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; }
9236
9237	// If turning off, or changing type, deregister old name
9238	if (m->SPSState == 1 && sps != m->SPSType)
9239		{ m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); }
9240
9241	// Record our new SPS parameters
9242	m->SPSType          = sps;
9243	m->SPSPortability   = port;
9244	m->SPSMarginalPower = marginalpower;
9245	m->SPSTotalPower    = totpower;
9246
9247	// If turning on, open socket and advertise service
9248	if (sps)
9249		{
9250		if (!m->SPSSocket)
9251			{
9252			m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
9253			if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
9254			}
9255		if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree);
9256		}
9257	}
9258
9259// ***************************************************************************
9260#if COMPILER_LIKES_PRAGMA_MARK
9261#pragma mark -
9262#pragma mark - Startup and Shutdown
9263#endif
9264
9265mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
9266	{
9267	if (storage && numrecords)
9268		{
9269		mDNSu32 i;
9270		debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
9271		for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
9272		storage[numrecords-1].next = m->rrcache_free;
9273		m->rrcache_free = storage;
9274		m->rrcache_size += numrecords;
9275		}
9276	}
9277
9278mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
9279	{
9280	mDNS_Lock(m);
9281	mDNS_GrowCache_internal(m, storage, numrecords);
9282	mDNS_Unlock(m);
9283	}
9284
9285mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
9286	CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
9287	mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
9288	{
9289	mDNSu32 slot;
9290	mDNSs32 timenow;
9291	mStatus result;
9292
9293	if (!rrcachestorage) rrcachesize = 0;
9294
9295	m->p                             = p;
9296	m->KnownBugs                     = 0;
9297	m->CanReceiveUnicastOn5353       = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
9298	m->AdvertiseLocalAddresses       = AdvertiseLocalAddresses;
9299	m->DivertMulticastAdvertisements = mDNSfalse;
9300	m->mDNSPlatformStatus            = mStatus_Waiting;
9301	m->UnicastPort4                  = zeroIPPort;
9302	m->UnicastPort6                  = zeroIPPort;
9303	m->PrimaryMAC                    = zeroEthAddr;
9304	m->MainCallback                  = Callback;
9305	m->MainContext                   = Context;
9306	m->rec.r.resrec.RecordType       = 0;
9307
9308	// For debugging: To catch and report locking failures
9309	m->mDNS_busy               = 0;
9310	m->mDNS_reentrancy         = 0;
9311	m->ShutdownTime            = 0;
9312	m->lock_rrcache            = 0;
9313	m->lock_Questions          = 0;
9314	m->lock_Records            = 0;
9315
9316	// Task Scheduling variables
9317	result = mDNSPlatformTimeInit();
9318	if (result != mStatus_NoError) return(result);
9319	m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
9320	timenow = mDNS_TimeNow_NoLock(m);
9321
9322	m->timenow                 = 0;		// MUST only be set within mDNS_Lock/mDNS_Unlock section
9323	m->timenow_last            = timenow;
9324	m->NextScheduledEvent      = timenow;
9325	m->SuppressSending         = timenow;
9326	m->NextCacheCheck          = timenow + 0x78000000;
9327	m->NextScheduledQuery      = timenow + 0x78000000;
9328	m->NextScheduledProbe      = timenow + 0x78000000;
9329	m->NextScheduledResponse   = timenow + 0x78000000;
9330	m->NextScheduledNATOp      = timenow + 0x78000000;
9331	m->NextScheduledSPS        = timenow + 0x78000000;
9332	m->RandomQueryDelay        = 0;
9333	m->RandomReconfirmDelay    = 0;
9334	m->PktNum                  = 0;
9335	m->SleepState              = SleepState_Awake;
9336	m->SleepSeqNum             = 0;
9337	m->SystemWakeOnLANEnabled  = mDNSfalse;
9338	m->DelaySleep              = 0;
9339	m->SleepLimit              = 0;
9340
9341	// These fields only required for mDNS Searcher...
9342	m->Questions               = mDNSNULL;
9343	m->NewQuestions            = mDNSNULL;
9344	m->CurrentQuestion         = mDNSNULL;
9345	m->LocalOnlyQuestions      = mDNSNULL;
9346	m->NewLocalOnlyQuestions   = mDNSNULL;
9347	m->rrcache_size            = 0;
9348	m->rrcache_totalused       = 0;
9349	m->rrcache_active          = 0;
9350	m->rrcache_report          = 10;
9351	m->rrcache_free            = mDNSNULL;
9352
9353	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
9354
9355	mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
9356
9357	// Fields below only required for mDNS Responder...
9358	m->hostlabel.c[0]          = 0;
9359	m->nicelabel.c[0]          = 0;
9360	m->MulticastHostname.c[0]  = 0;
9361	m->HIHardware.c[0]         = 0;
9362	m->HISoftware.c[0]         = 0;
9363	m->ResourceRecords         = mDNSNULL;
9364	m->DuplicateRecords        = mDNSNULL;
9365	m->NewLocalRecords         = mDNSNULL;
9366	m->CurrentRecord           = mDNSNULL;
9367	m->HostInterfaces          = mDNSNULL;
9368	m->ProbeFailTime           = 0;
9369	m->NumFailedProbes         = 0;
9370	m->SuppressProbes          = 0;
9371
9372#ifndef UNICAST_DISABLED
9373	m->NextuDNSEvent            = timenow + 0x78000000;
9374	m->NextSRVUpdate            = timenow + 0x78000000;
9375	m->SuppressStdPort53Queries = 0;
9376
9377	m->ServiceRegistrations     = mDNSNULL;
9378	m->DNSServers               = mDNSNULL;
9379
9380	m->Router                   = zeroAddr;
9381	m->AdvertisedV4             = zeroAddr;
9382	m->AdvertisedV6             = zeroAddr;
9383
9384	m->AuthInfoList             = mDNSNULL;
9385
9386	m->ReverseMap.ThisQInterval = -1;
9387	m->StaticHostname.c[0]      = 0;
9388	m->FQDN.c[0]                = 0;
9389	m->Hostnames                = mDNSNULL;
9390	m->AutoTunnelHostAddr.b[0]  = 0;
9391	m->AutoTunnelHostAddrActive = mDNSfalse;
9392	m->AutoTunnelLabel.c[0]     = 0;
9393
9394	m->RegisterSearchDomains    = mDNSfalse;
9395
9396	// NAT traversal fields
9397	m->NATTraversals            = mDNSNULL;
9398	m->CurrentNATTraversal      = mDNSNULL;
9399	m->retryIntervalGetAddr     = 0;	// delta between time sent and retry
9400	m->retryGetAddr             = timenow + 0x78000000;	// absolute time when we retry
9401	m->ExternalAddress          = zerov4Addr;
9402
9403	m->NATMcastRecvskt          = mDNSNULL;
9404	m->LastNATupseconds         = 0;
9405	m->LastNATReplyLocalTime    = timenow;
9406	m->LastNATMapResultCode     = NATErr_None;
9407
9408	m->UPnPInterfaceID          = 0;
9409	m->SSDPSocket               = mDNSNULL;
9410	m->SSDPWANPPPConnection     = mDNSfalse;
9411	m->UPnPRouterPort           = zeroIPPort;
9412	m->UPnPSOAPPort             = zeroIPPort;
9413	m->UPnPRouterURL            = mDNSNULL;
9414	m->UPnPWANPPPConnection     = mDNSfalse;
9415	m->UPnPSOAPURL              = mDNSNULL;
9416	m->UPnPRouterAddressString  = mDNSNULL;
9417	m->UPnPSOAPAddressString    = mDNSNULL;
9418	m->SPSType                  = 0;
9419	m->SPSPortability           = 0;
9420	m->SPSMarginalPower         = 0;
9421	m->SPSTotalPower            = 0;
9422	m->SPSState                 = 0;
9423	m->SPSProxyListChanged      = mDNSNULL;
9424	m->SPSSocket                = mDNSNULL;
9425	m->SPSBrowseCallback        = mDNSNULL;
9426	m->ProxyRecords             = 0;
9427
9428#endif
9429
9430#if APPLE_OSX_mDNSResponder
9431	m->TunnelClients            = mDNSNULL;
9432#endif
9433
9434	result = mDNSPlatformInit(m);
9435
9436#ifndef UNICAST_DISABLED
9437	// It's better to do this *after* the platform layer has set up the
9438	// interface list and security credentials
9439	uDNS_SetupDNSConfig(m);						// Get initial DNS configuration
9440#endif
9441
9442	return(result);
9443	}
9444
9445mDNSexport void mDNS_ConfigChanged(mDNS *const m)
9446	{
9447	if (m->SPSState == 1)
9448		{
9449		domainlabel name, newname;
9450		domainname type, domain;
9451		DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain);
9452		ConstructSleepProxyServerName(m, &newname);
9453		if (!SameDomainLabelCS(name.c, newname.c))
9454			{
9455			LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c);
9456			// When SleepProxyServerCallback gets the mStatus_MemFree message,
9457			// it will reregister the service under the new name
9458			m->SPSState = 2;
9459			mDNS_DeregisterService(m, &m->SPSRecords);
9460			}
9461		}
9462
9463	if (m->MainCallback)
9464		m->MainCallback(m, mStatus_ConfigChanged);
9465	}
9466
9467mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
9468	{
9469	(void)m;	// unused
9470	debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
9471	mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
9472	}
9473
9474mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
9475	{
9476	mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
9477					 cr->resrec.rrtype     == kDNSType_A ||
9478					 cr->resrec.rrtype     == kDNSType_AAAA ||
9479					 cr->resrec.rrtype     == kDNSType_SRV;
9480
9481	(void) lameduck;
9482	(void) ptr;
9483	debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
9484
9485	if (purge) mDNS_PurgeCacheResourceRecord(m, cr);
9486	else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
9487	}
9488
9489mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
9490	{
9491	mDNSu32 slot;
9492	CacheGroup *cg;
9493	CacheRecord *cr;
9494
9495	mDNSAddr     v4, v6, r;
9496	domainname   fqdn;
9497	DNSServer   *ptr, **p = &m->DNSServers;
9498	const DNSServer *oldServers = m->DNSServers;
9499	DNSQuestion *q;
9500
9501	debugf("uDNS_SetupDNSConfig: entry");
9502
9503	if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
9504
9505	mDNS_Lock(m);
9506
9507	// Let the platform layer get the current DNS information
9508	// The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
9509	// (no need to hit the network with domain enumeration queries until we actually need that information).
9510	for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
9511
9512	mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
9513
9514	// Update our qDNSServer pointers before we go and free the DNSServer object memory
9515	for (q = m->Questions; q; q=q->next)
9516		if (!mDNSOpaque16IsZero(q->TargetQID))
9517			{
9518			DNSServer *s = GetServerForName(m, &q->qname);
9519			DNSServer *t = q->qDNSServer;
9520			if (t != s)
9521				{
9522				// If DNS Server for this question has changed, reactivate it
9523				debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
9524					t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
9525					s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
9526					q->qname.c, DNSTypeName(q->qtype));
9527				q->qDNSServer = s;
9528				q->unansweredQueries = 0;
9529				ActivateUnicastQuery(m, q, mDNStrue);
9530				}
9531			}
9532
9533	// Flush all records that match a new resolver
9534	FORALL_CACHERECORDS(slot, cg, cr)
9535		{
9536		ptr = GetServerForName(m, cr->resrec.name);
9537		if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
9538			PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
9539		}
9540
9541	while (*p)
9542		{
9543		if (((*p)->flags & DNSServer_FlagDelete) != 0)
9544			{
9545			// Scan our cache, looking for uDNS records that we would have queried this server for.
9546			// We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
9547			// different DNS servers can give different answers to the same question.
9548			ptr = *p;
9549			ptr->flags &= ~DNSServer_FlagDelete;	// Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
9550			FORALL_CACHERECORDS(slot, cg, cr)
9551				if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
9552					PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
9553			*p = (*p)->next;
9554			debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
9555			mDNSPlatformMemFree(ptr);
9556			}
9557		else
9558			{
9559			(*p)->flags &= ~DNSServer_FlagNew;
9560			p = &(*p)->next;
9561			}
9562		}
9563
9564	// If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
9565	// This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
9566	// Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
9567	// Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated.
9568	if ((m->DNSServers != mDNSNULL) != (oldServers != mDNSNULL))
9569		{
9570		int count = 0;
9571		FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
9572		LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
9573			m->DNSServers ? "DNS server became" : "No DNS servers", count);
9574		}
9575
9576	// If we no longer have any DNS servers, we need to force anything that needs to get zone data
9577	// to get that information again (which will fail, since we have no more DNS servers)
9578	if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL))	RestartRecordGetZoneData(m);
9579
9580	// Did our FQDN change?
9581	if (!SameDomainName(&fqdn, &m->FQDN))
9582		{
9583		if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
9584
9585		AssignDomainName(&m->FQDN, &fqdn);
9586
9587		if (m->FQDN.c[0])
9588			{
9589			mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
9590			mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
9591			}
9592		}
9593
9594	mDNS_Unlock(m);
9595
9596	// handle router and primary interface changes
9597	v4 = v6 = r = zeroAddr;
9598	v4.type = r.type = mDNSAddrType_IPv4;
9599
9600	if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
9601		{
9602		mDNS_SetPrimaryInterfaceInfo(m,
9603			!mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
9604			!mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL,
9605			!mDNSIPv4AddressIsZero(r .ip.v4) ? &r  : mDNSNULL);
9606		}
9607	else
9608		{
9609		mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL);
9610		if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);	// Set status to 1 to indicate temporary failure
9611		}
9612
9613	return mStatus_NoError;
9614	}
9615
9616mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
9617	{
9618	m->mDNSPlatformStatus = result;
9619	if (m->MainCallback)
9620		{
9621		mDNS_Lock(m);
9622		mDNS_DropLockBeforeCallback();		// Allow client to legally make mDNS API calls from the callback
9623		m->MainCallback(m, mStatus_NoError);
9624		mDNS_ReclaimLockAfterCallback();	// Decrement mDNS_reentrancy to block mDNS API calls again
9625		mDNS_Unlock(m);
9626		}
9627	}
9628
9629extern ServiceRecordSet *CurrentServiceRecordSet;
9630
9631mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start)
9632	{
9633	m->CurrentRecord = start;
9634	while (m->CurrentRecord)
9635		{
9636		AuthRecord *rr = m->CurrentRecord;
9637		if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
9638			{
9639			LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
9640			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
9641			}
9642		// Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
9643		// the list may have been changed in that call.
9644		if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
9645			m->CurrentRecord = rr->next;
9646		}
9647	}
9648
9649mDNSexport void mDNS_StartExit(mDNS *const m)
9650	{
9651	NetworkInterfaceInfo *intf;
9652	AuthRecord *rr;
9653
9654	mDNS_Lock(m);
9655
9656	m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
9657
9658	mDNS_DropLockBeforeCallback();		// mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
9659	mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0);
9660	mDNS_ReclaimLockAfterCallback();
9661
9662#ifndef UNICAST_DISABLED
9663	{
9664	SearchListElem *s;
9665	SuspendLLQs(m);
9666	// Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
9667	// because we deregister all records and services later in this routine
9668	while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
9669
9670	// For each member of our SearchList, deregister any records it may have created, and cut them from the list.
9671	// Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list)
9672	// and we may crash because the list still contains dangling pointers.
9673	for (s = SearchList; s; s = s->next)
9674		while (s->AuthRecs)
9675			{
9676			ARListElem *dereg = s->AuthRecs;
9677			s->AuthRecs = s->AuthRecs->next;
9678			mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal);	// Memory will be freed in the FreeARElemCallback
9679			}
9680	}
9681#endif
9682
9683	for (intf = m->HostInterfaces; intf; intf = intf->next)
9684		if (intf->Advertise)
9685			DeadvertiseInterface(m, intf);
9686
9687	// Shut down all our active NAT Traversals
9688	while (m->NATTraversals)
9689		{
9690		NATTraversalInfo *t = m->NATTraversals;
9691		mDNS_StopNATOperation_internal(m, t);		// This will cut 't' from the list, thereby advancing m->NATTraversals in the process
9692
9693		// After stopping the NAT Traversal, we zero out the fields.
9694		// This has particularly important implications for our AutoTunnel records --
9695		// when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
9696		// handlers to just turn around and attempt to re-register those same records.
9697		// Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
9698		t->ExternalAddress = zerov4Addr;
9699		t->ExternalPort    = zeroIPPort;
9700		t->Lifetime        = 0;
9701		t->Result          = mStatus_NoError;
9702		}
9703
9704	// Make sure there are nothing but deregistering records remaining in the list
9705	if (m->CurrentRecord)
9706		LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
9707
9708	// We're in the process of shutting down, so queries, etc. are no longer available.
9709	// Consequently, determining certain information, e.g. the uDNS update server's IP
9710	// address, will not be possible.  The records on the main list are more likely to
9711	// already contain such information, so we deregister the duplicate records first.
9712	LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
9713	DeregLoop(m, m->DuplicateRecords);
9714	LogInfo("mDNS_StartExit: Deregistering resource records");
9715	DeregLoop(m, m->ResourceRecords);
9716
9717	// If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
9718	// we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay.
9719	if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond)
9720		{
9721		m->NextScheduledResponse = m->timenow;
9722		m->SuppressSending = 0;
9723		}
9724
9725#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
9726	CurrentServiceRecordSet = m->ServiceRegistrations;
9727	while (CurrentServiceRecordSet)
9728		{
9729		ServiceRecordSet *srs = CurrentServiceRecordSet;
9730		LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c);
9731		uDNS_DeregisterService(m, srs);
9732		if (CurrentServiceRecordSet == srs)
9733			CurrentServiceRecordSet = srs->uDNS_next;
9734		}
9735#endif
9736
9737	if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
9738	else                    LogInfo("mDNS_StartExit: No deregistering records remain");
9739
9740	if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
9741	else                         LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
9742
9743	for (rr = m->DuplicateRecords; rr; rr = rr->next)
9744		LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
9745
9746	// If any deregistering records remain, send their deregistration announcements before we exit
9747	if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
9748
9749	mDNS_Unlock(m);
9750
9751	LogInfo("mDNS_StartExit: done");
9752	}
9753
9754mDNSexport void mDNS_FinalExit(mDNS *const m)
9755	{
9756	mDNSu32 rrcache_active = 0;
9757	mDNSu32 rrcache_totalused = 0;
9758	mDNSu32 slot;
9759	AuthRecord *rr;
9760	ServiceRecordSet *srs;
9761
9762	LogInfo("mDNS_FinalExit: mDNSPlatformClose");
9763	mDNSPlatformClose(m);
9764
9765	rrcache_totalused = m->rrcache_totalused;
9766	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
9767		{
9768		while (m->rrcache_hash[slot])
9769			{
9770			CacheGroup *cg = m->rrcache_hash[slot];
9771			while (cg->members)
9772				{
9773				CacheRecord *cr = cg->members;
9774				cg->members = cg->members->next;
9775				if (cr->CRActiveQuestion) rrcache_active++;
9776				ReleaseCacheRecord(m, cr);
9777				}
9778			cg->rrcache_tail = &cg->members;
9779			ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
9780			}
9781		}
9782	debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
9783	if (rrcache_active != m->rrcache_active)
9784		LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
9785
9786	for (rr = m->ResourceRecords; rr; rr = rr->next)
9787		LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
9788
9789	for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
9790		LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c);
9791
9792	LogInfo("mDNS_FinalExit: done");
9793	}
9794