xref: /titanic_41/usr/src/cmd/cmd-inet/usr.lib/mdnsd/mDNS.c (revision 4b22b9337f359bfd063322244f5336cc7c6ffcfa)
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 complile on *any* platform that has a C compiler, without
22  * making *any* assumptions about availability of so-called "standard" C functions,
23  * routines, or types (which may or may not be present on any given platform).
24 
25  * Formatting notes:
26  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27  * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28  * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29  * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30  * therefore common sense dictates that if they are part of a compound statement then they
31  * should be indented to the same level as everything else in that compound statement.
32  * Indenting curly braces at the same level as the "if" implies that curly braces are
33  * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35  * understand why variable y is not of type "char*" just proves the point that poor code
36  * layout leads people to unfortunate misunderstandings about how the C language really works.)
37 
38     Change History (most recent first):
39 
40 $Log: mDNS.c,v $
41 Revision 1.537.2.1  2006/08/29 06:24:22  cheshire
42 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
43 
44 Revision 1.537  2006/03/19 02:00:07  cheshire
45 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
46 
47 Revision 1.536  2006/03/08 23:29:53  cheshire
48 <rdar://problem/4468716> Improve "Service Renamed" log message
49 
50 Revision 1.535  2006/03/02 20:41:17  cheshire
51 <rdar://problem/4111464> After record update, old record sometimes remains in cache
52 Minor code tidying and comments to reduce the risk of similar programming errors in future
53 
54 Revision 1.534  2006/03/02 03:25:46  cheshire
55 <rdar://problem/4111464> After record update, old record sometimes remains in cache
56 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
57 
58 Revision 1.533  2006/02/26 00:54:41  cheshire
59 Fixes to avoid code generation warning/error on FreeBSD 7
60 
61 Revision 1.532  2005/12/02 20:24:36  cheshire
62 <rdar://problem/4363209> Adjust cutoff time for KA list by one second
63 
64 Revision 1.531  2005/12/02 19:05:42  cheshire
65 Tidy up constants
66 
67 Revision 1.530  2005/11/07 01:49:48  cheshire
68 For consistency, use NonZeroTime() function instead of ?: expression
69 
70 Revision 1.529  2005/10/25 23:42:24  cheshire
71 <rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
72 Changed switch statement to an "if"
73 
74 Revision 1.528  2005/10/25 23:34:22  cheshire
75 <rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
76 
77 Revision 1.527  2005/10/25 22:43:59  cheshire
78 Add clarifying comments
79 
80 Revision 1.526  2005/10/20 00:10:33  cheshire
81 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
82 
83 Revision 1.525  2005/09/24 00:47:17  cheshire
84 Fix comment typos
85 
86 Revision 1.524  2005/09/16 21:06:49  cheshire
87 Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
88 
89 Revision 1.523  2005/03/21 00:33:51  shersche
90 <rdar://problem/4021486> Fix build warnings on Win32 platform
91 
92 Revision 1.522  2005/03/04 21:48:12  cheshire
93 <rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity
94 
95 Revision 1.521  2005/02/25 04:21:00  cheshire
96 <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
97 
98 Revision 1.520  2005/02/16 01:14:11  cheshire
99 Convert RR Cache LogOperation() calls to debugf()
100 
101 Revision 1.519  2005/02/15 01:57:20  cheshire
102 When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero
103 
104 Revision 1.518  2005/02/10 22:35:17  cheshire
105 <rdar://problem/3727944> Update name
106 
107 Revision 1.517  2005/02/03 00:21:21  cheshire
108 Update comments about BIND named and zero-length TXT records
109 
110 Revision 1.516  2005/01/28 06:06:32  cheshire
111 Update comment
112 
113 Revision 1.515  2005/01/27 00:21:49  cheshire
114 <rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
115 
116 Revision 1.514  2005/01/21 01:33:45  cheshire
117 <rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
118 
119 Revision 1.513  2005/01/21 00:07:54  cheshire
120 <rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
121 
122 Revision 1.512  2005/01/20 00:37:45  cheshire
123 <rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
124 Take care not to recycle records while they are on the CacheFlushRecords list
125 
126 Revision 1.511  2005/01/19 22:48:53  cheshire
127 <rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
128 
129 Revision 1.510  2005/01/19 03:12:45  cheshire
130 Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
131 
132 Revision 1.509  2005/01/19 03:08:49  cheshire
133 <rdar://problem/3961051> CPU Spin in mDNSResponder
134 Log messages to help catch and report CPU spins
135 
136 Revision 1.508  2005/01/18 18:56:32  cheshire
137 <rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
138 
139 Revision 1.507  2005/01/18 01:12:07  cheshire
140 <rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
141 
142 Revision 1.506  2005/01/17 23:28:53  cheshire
143 Fix compile error
144 
145 Revision 1.505  2005/01/11 02:02:56  shersche
146 Move variable declaration to the beginning of statement block
147 
148 Revision 1.504  2004/12/20 20:24:35  cheshire
149 <rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
150 
151 Revision 1.503  2004/12/20 18:41:47  cheshire
152 <rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
153 
154 Revision 1.502  2004/12/20 18:04:08  cheshire
155 <rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
156 
157 Revision 1.501  2004/12/19 23:50:18  cheshire
158 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
159 Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
160 
161 Revision 1.500  2004/12/18 03:13:46  cheshire
162 <rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
163 
164 Revision 1.499  2004/12/17 23:37:45  cheshire
165 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
166 (and other repetitive configuration changes)
167 
168 Revision 1.498  2004/12/17 05:25:46  cheshire
169 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
170 
171 Revision 1.497  2004/12/17 03:20:58  cheshire
172 <rdar://problem/3925168> Don't send unicast replies we know will be ignored
173 
174 Revision 1.496  2004/12/16 22:18:26  cheshire
175 Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
176 
177 Revision 1.495  2004/12/16 21:27:37  ksekar
178 Fixed build failures when compiled with verbose debugging messages
179 
180 Revision 1.494  2004/12/16 20:46:56  cheshire
181 Fix compiler warnings
182 
183 Revision 1.493  2004/12/16 20:13:00  cheshire
184 <rdar://problem/3324626> Cache memory management improvements
185 
186 Revision 1.492  2004/12/16 08:03:24  shersche
187 Fix compilation error when UNICAST_DISABLED is set
188 
189 Revision 1.491  2004/12/11 01:52:11  cheshire
190 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
191 
192 Revision 1.490  2004/12/10 20:06:25  cheshire
193 <rdar://problem/3915074> Reduce egregious stack space usage
194 Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
195 
196 Revision 1.489  2004/12/10 20:03:43  cheshire
197 <rdar://problem/3915074> Reduce egregious stack space usage
198 Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
199 
200 Revision 1.488  2004/12/10 19:50:41  cheshire
201 <rdar://problem/3915074> Reduce egregious stack space usage
202 Reduced SendResponses() stack frame from 9K to 176 bytes
203 
204 Revision 1.487  2004/12/10 19:39:13  cheshire
205 <rdar://problem/3915074> Reduce egregious stack space usage
206 Reduced SendQueries() stack frame from 18K to 112 bytes
207 
208 Revision 1.486  2004/12/10 14:16:17  cheshire
209 <rdar://problem/3889788> Relax update rate limiting
210 We now allow an average rate of ten updates per minute.
211 Updates in excess of that are rate limited, but more gently than before.
212 
213 Revision 1.485  2004/12/10 02:09:24  cheshire
214 <rdar://problem/3898376> Modify default TTLs
215 
216 Revision 1.484  2004/12/09 03:15:40  ksekar
217 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
218 
219 Revision 1.483  2004/12/07 23:00:14  ksekar
220 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
221 Call RecordProbeFailure even if there is no record callback
222 
223 Revision 1.482  2004/12/07 22:49:06  cheshire
224 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
225 
226 Revision 1.481  2004/12/07 21:26:04  ksekar
227 <rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
228 
229 Revision 1.480  2004/12/07 20:42:33  cheshire
230 Add explicit context parameter to mDNS_RemoveRecordFromService()
231 
232 Revision 1.479  2004/12/07 17:50:49  ksekar
233 <rdar://problem/3908850> BIND doesn't allow zero-length TXT records
234 
235 Revision 1.478  2004/12/06 21:15:22  ksekar
236 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
237 
238 Revision 1.477  2004/12/04 02:12:45  cheshire
239 <rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
240 
241 Revision 1.476  2004/11/29 23:34:31  cheshire
242 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
243 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
244 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
245 
246 Revision 1.475  2004/11/29 23:13:31  cheshire
247 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set
248 Additional check: Make sure we don't unnecessarily send packets containing only additionals.
249 (This could occur with multi-packet KA lists, if the answer and additionals were marked
250 by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
251 
252 Revision 1.474  2004/11/29 17:18:12  cheshire
253 Remove "Unknown DNS packet type" message for update responses
254 
255 Revision 1.473  2004/11/25 01:57:52  cheshire
256 <rdar://problem/3484552> All unique records in a set should have the cache flush bit set
257 
258 Revision 1.472  2004/11/25 01:28:09  cheshire
259 <rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
260 
261 Revision 1.471  2004/11/25 01:10:13  cheshire
262 Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
263 
264 Revision 1.470  2004/11/24 21:54:44  cheshire
265 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
266 
267 Revision 1.469  2004/11/24 04:50:39  cheshire
268 Minor tidying
269 
270 Revision 1.468  2004/11/24 01:47:07  cheshire
271 <rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
272 
273 Revision 1.467  2004/11/24 01:41:28  cheshire
274 Rename CompleteProbing() to AcknowledgeRecord()
275 
276 Revision 1.466  2004/11/23 21:08:07  ksekar
277 Don't use ID to demux multicast/unicast now that unicast uses random IDs
278 
279 Revision 1.465  2004/11/15 20:09:21  ksekar
280 <rdar://problem/3719050> Wide Area support for Add/Remove record
281 
282 Revision 1.464  2004/11/03 01:44:36  cheshire
283 Update debugging messages
284 
285 Revision 1.463  2004/10/29 02:38:48  cheshire
286 Fix Windows compile errors
287 
288 Revision 1.462  2004/10/28 19:21:07  cheshire
289 Guard against registering interface with zero InterfaceID
290 
291 Revision 1.461  2004/10/28 19:02:16  cheshire
292 Remove \n from LogMsg() call
293 
294 Revision 1.460  2004/10/28 03:24:40  cheshire
295 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
296 
297 Revision 1.459  2004/10/26 22:34:37  cheshire
298 <rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
299 
300 Revision 1.458  2004/10/26 20:45:28  cheshire
301 Show mask in "invalid mask" message
302 
303 Revision 1.457  2004/10/26 06:28:36  cheshire
304 Now that we don't check IP TTL any more, remove associated log message
305 
306 Revision 1.456  2004/10/26 06:21:42  cheshire
307 Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
308 
309 Revision 1.455  2004/10/26 06:11:40  cheshire
310 Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
311 
312 Revision 1.454  2004/10/23 01:16:00  cheshire
313 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
314 
315 Revision 1.453  2004/10/22 20:52:06  ksekar
316 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
317 
318 Revision 1.452  2004/10/20 01:50:40  cheshire
319 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
320 Implemented ForceMCast mode for AuthRecords as well as for Questions
321 
322 Revision 1.451  2004/10/19 21:33:15  cheshire
323 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
324 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
325 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
326 
327 Revision 1.450  2004/10/19 17:42:59  ksekar
328 Fixed compiler warnings for non-debug builds.
329 
330 Revision 1.449  2004/10/18 22:57:07  cheshire
331 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
332 
333 Revision 1.448  2004/10/16 00:16:59  cheshire
334 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
335 
336 Revision 1.447  2004/10/15 00:51:21  cheshire
337 <rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
338 
339 Revision 1.446  2004/10/14 00:43:34  cheshire
340 <rdar://problem/3815984> Services continue to announce SRV and HINFO
341 
342 Revision 1.445  2004/10/12 21:07:09  cheshire
343 Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
344 
345 Revision 1.444  2004/10/11 17:54:16  ksekar
346 Changed hashtable pointer output from debugf to verbosedebugf.
347 
348 Revision 1.443  2004/10/10 07:05:45  cheshire
349 For consistency, use symbol "localdomain" instead of literal string
350 
351 Revision 1.442  2004/10/08 20:25:10  cheshire
352 Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
353 
354 Revision 1.441  2004/10/08 03:25:01  ksekar
355 <rdar://problem/3831716> domain enumeration should use LLQs
356 
357 Revision 1.440  2004/10/06 01:44:19  cheshire
358 <rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
359 
360 Revision 1.439  2004/10/03 23:14:11  cheshire
361 Add "mDNSEthAddr" type and "zeroEthAddr" constant
362 
363 Revision 1.438  2004/09/29 23:07:04  cheshire
364 Patch from Pavel Repin to fix compile error on Windows
365 
366 Revision 1.437  2004/09/28 02:23:50  cheshire
367 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
368 Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
369 For records with the cache flush bit set, defer the decision until the end of the packet
370 
371 Revision 1.436  2004/09/28 01:27:04  cheshire
372 Update incorrect log message
373 
374 Revision 1.435  2004/09/25 02:41:39  cheshire
375 <rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
376 
377 Revision 1.434  2004/09/25 02:32:06  cheshire
378 Update comments
379 
380 Revision 1.433  2004/09/25 02:24:27  cheshire
381 Removed unused rr->UseCount
382 
383 Revision 1.432  2004/09/24 21:35:17  cheshire
384 <rdar://problem/3561220> Browses are no longer piggybacking on other browses
385 TargetPort and TargetQID are allowed to be undefined if no question->Target is set
386 
387 Revision 1.431  2004/09/24 21:33:12  cheshire
388 Adjust comment
389 
390 Revision 1.430  2004/09/24 02:15:49  cheshire
391 <rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
392 
393 Revision 1.429  2004/09/24 00:20:21  cheshire
394 <rdar://problem/3483349> Any rrtype is a conflict for unique records
395 
396 Revision 1.428  2004/09/24 00:12:25  cheshire
397 Get rid of unused RRUniqueOrKnownUnique(RR)
398 
399 Revision 1.427  2004/09/23 20:44:11  cheshire
400 <rdar://problem/3813148> Reduce timeout before expiring records on failure
401 
402 Revision 1.426  2004/09/23 20:21:07  cheshire
403 <rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
404 Associate a unique sequence number with each received packet, and only increment the count of recent answer
405 packets if the packet sequence number for this answer record is not one we've already seen and counted.
406 
407 Revision 1.425  2004/09/23 20:14:38  cheshire
408 Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
409 
410 Revision 1.424  2004/09/23 00:58:36  cheshire
411 <rdar://problem/3781269> Rate limiting interferes with updating TXT records
412 
413 Revision 1.423  2004/09/23 00:50:53  cheshire
414 <rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
415 
416 Revision 1.422  2004/09/22 02:34:46  cheshire
417 Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
418 
419 Revision 1.421  2004/09/21 23:29:49  cheshire
420 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
421 
422 Revision 1.420  2004/09/21 23:01:42  cheshire
423 Update debugf messages
424 
425 Revision 1.419  2004/09/21 19:51:14  cheshire
426 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
427 
428 Revision 1.418  2004/09/21 18:40:17  cheshire
429 <rdar://problem/3376752> Adjust default record TTLs
430 
431 Revision 1.417  2004/09/21 17:32:16  cheshire
432 <rdar://problem/3809484> Rate limiting imposed too soon
433 
434 Revision 1.416  2004/09/20 23:52:01  cheshire
435 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
436 
437 Revision 1.415  2004/09/18 01:14:09  cheshire
438 <rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
439 
440 Revision 1.414  2004/09/18 01:06:48  cheshire
441 Add comments
442 
443 Revision 1.413  2004/09/17 01:08:48  cheshire
444 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
445   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
446   declared in that file are ONLY appropriate to single-address-space embedded applications.
447   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
448 
449 Revision 1.412  2004/09/17 00:46:33  cheshire
450 mDNS_TimeNow should take const mDNS parameter
451 
452 Revision 1.411  2004/09/17 00:31:51  cheshire
453 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
454 
455 Revision 1.410  2004/09/17 00:19:10  cheshire
456 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
457 
458 Revision 1.409  2004/09/16 21:59:15  cheshire
459 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
460 
461 Revision 1.408  2004/09/16 21:36:36  cheshire
462 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
463 Changes to add necessary locking calls around unicast DNS operations
464 
465 Revision 1.407  2004/09/16 02:29:39  cheshire
466 Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
467 uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
468 
469 Revision 1.406  2004/09/16 01:58:14  cheshire
470 Fix compiler warnings
471 
472 Revision 1.405  2004/09/16 00:24:48  cheshire
473 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
474 
475 Revision 1.404  2004/09/15 21:44:11  cheshire
476 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
477 Show time value in log to help diagnose errors
478 
479 Revision 1.403  2004/09/15 00:46:32  ksekar
480 Changed debugf to verbosedebugf in CheckCacheExpiration
481 
482 Revision 1.402  2004/09/14 23:59:55  cheshire
483 <rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
484 
485 Revision 1.401  2004/09/14 23:27:46  cheshire
486 Fix compile errors
487 
488 Revision 1.400  2004/09/02 03:48:47  cheshire
489 <rdar://problem/3709039> Disable targeted unicast query support by default
490 1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
491 2. New field AllowRemoteQuery in AuthRecord structure
492 3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
493 4. mDNS.c only answers remote queries if AllowRemoteQuery is set
494 
495 Revision 1.399  2004/09/02 01:39:40  cheshire
496 For better readability, follow consistent convention that QR bit comes first, followed by OP bits
497 
498 Revision 1.398  2004/09/01 03:59:29  ksekar
499 <rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
500 
501 Revision 1.397  2004/08/25 22:04:25  rpantos
502 Fix the standard Windows compile error.
503 
504 Revision 1.396  2004/08/25 00:37:27  ksekar
505 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
506 
507 Revision 1.395  2004/08/18 17:21:18  ksekar
508 Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
509 
510 Revision 1.394  2004/08/14 03:22:41  cheshire
511 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
512 Add GetUserSpecifiedDDNSName() routine
513 Convert ServiceRegDomain to domainname instead of C string
514 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
515 
516 Revision 1.393  2004/08/13 23:42:52  cheshire
517 Removed unused "zeroDomainNamePtr"
518 
519 Revision 1.392  2004/08/13 23:37:02  cheshire
520 Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
521 "uDNS_info.UnicastHostname" for clarity
522 
523 Revision 1.391  2004/08/13 23:25:00  cheshire
524 Now that we do both uDNS and mDNS, global replace "m->hostname" with
525 "m->MulticastHostname" for clarity
526 
527 Revision 1.390  2004/08/11 02:17:01  cheshire
528 <rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
529 
530 Revision 1.389  2004/08/10 23:19:14  ksekar
531 <rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
532 Moved routines/constants to allow extern access for garbage collection daemon
533 
534 Revision 1.388  2004/07/30 17:40:06  ksekar
535 <rdar://problem/3739115>: TXT Record updates not available for wide-area services
536 
537 Revision 1.387  2004/07/26 22:49:30  ksekar
538 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
539 
540 Revision 1.386  2004/07/13 21:24:24  rpantos
541 Fix for <rdar://problem/3701120>.
542 
543 Revision 1.385  2004/06/18 19:09:59  cheshire
544 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
545 
546 Revision 1.384  2004/06/15 04:31:23  cheshire
547 Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
548 
549 Revision 1.383  2004/06/11 00:04:59  cheshire
550 <rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
551 
552 Revision 1.382  2004/06/08 04:59:40  cheshire
553 Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
554 
555 Revision 1.381  2004/06/05 00:57:30  cheshire
556 Remove incorrect LogMsg()
557 
558 Revision 1.380  2004/06/05 00:04:26  cheshire
559 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
560 
561 Revision 1.379  2004/05/28 23:42:36  ksekar
562 <rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
563 
564 Revision 1.378  2004/05/25 17:25:25  cheshire
565 Remove extraneous blank lines and white space
566 
567 Revision 1.377  2004/05/18 23:51:25  cheshire
568 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
569 
570 Revision 1.376  2004/05/05 18:30:44  ksekar
571 Restored surpressed Cache Tail debug messages.
572 
573 Revision 1.375  2004/04/26 21:36:25  cheshire
574 Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
575 is indicated as being available on that interface
576 
577 Revision 1.374  2004/04/21 02:53:26  cheshire
578 Typo in debugf statement
579 
580 Revision 1.373  2004/04/21 02:49:11  cheshire
581 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
582 
583 Revision 1.372  2004/04/21 02:38:51  cheshire
584 Add debugging checks
585 
586 Revision 1.371  2004/04/14 23:09:28  ksekar
587 Support for TSIG signed dynamic updates.
588 
589 Revision 1.370  2004/04/09 17:40:26  cheshire
590 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
591 
592 Revision 1.369  2004/04/09 16:34:00  cheshire
593 Debugging code for later; currently unused
594 
595 Revision 1.368  2004/04/02 19:19:48  cheshire
596 Add code to do optional logging of multi-packet KA list time intervals
597 
598 Revision 1.367  2004/03/20 03:16:10  cheshire
599 Minor refinement to "Excessive update rate" message
600 
601 Revision 1.366  2004/03/20 03:12:57  cheshire
602 <rdar://problem/3587619>: UpdateCredits not granted promptly enough
603 
604 Revision 1.365  2004/03/19 23:51:22  cheshire
605 Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
606 
607 Revision 1.364  2004/03/13 01:57:33  ksekar
608 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
609 
610 Revision 1.363  2004/03/12 21:00:51  cheshire
611 Also show port numbers when logging "apparent spoof mDNS Response" messages
612 
613 Revision 1.362  2004/03/12 08:58:18  cheshire
614 Guard against empty TXT records
615 
616 Revision 1.361  2004/03/09 03:00:46  cheshire
617 <rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
618 
619 Revision 1.360  2004/03/08 02:52:41  cheshire
620 Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
621 
622 Revision 1.359  2004/03/02 03:21:56  cheshire
623 <rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
624 
625 Revision 1.358  2004/02/20 08:18:34  cheshire
626 <rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
627 
628 Revision 1.357  2004/02/18 01:47:41  cheshire
629 <rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
630 
631 Revision 1.356  2004/02/06 23:04:19  ksekar
632 Basic Dynamic Update support via mDNS_Register (dissabled via
633 UNICAST_REGISTRATION #define)
634 
635 Revision 1.355  2004/02/05 09:32:33  cheshire
636 Fix from Bob Bradley: When using the "%.*s" string form,
637 guard against truncating in the middle of a multi-byte UTF-8 character.
638 
639 Revision 1.354  2004/02/05 09:30:22  cheshire
640 Update comments
641 
642 Revision 1.353  2004/01/28 03:41:00  cheshire
643 <rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
644 
645 Revision 1.352  2004/01/28 02:30:07  ksekar
646 Added default Search Domains to unicast browsing, controlled via
647 Networking sharing prefs pane.  Stopped sending unicast messages on
648 every interface.  Fixed unicast resolving via mach-port API.
649 
650 Revision 1.351  2004/01/27 20:15:22  cheshire
651 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
652 
653 Revision 1.350  2004/01/24 23:38:16  cheshire
654 Use mDNSVal16() instead of shifting and ORing operations
655 
656 Revision 1.349  2004/01/23 23:23:14  ksekar
657 Added TCP support for truncated unicast messages.
658 
659 Revision 1.348  2004/01/22 03:54:11  cheshire
660 Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
661 which means "do this query via multicast, even if it's apparently a unicast domain"
662 
663 Revision 1.347  2004/01/22 03:50:49  cheshire
664 If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
665 
666 Revision 1.346  2004/01/22 03:48:41  cheshire
667 Make sure uDNS client doesn't accidentally use query ID zero
668 
669 Revision 1.345  2004/01/22 03:43:08  cheshire
670 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
671 
672 Revision 1.344  2004/01/21 21:53:18  cheshire
673 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
674 
675 Revision 1.343  2003/12/23 00:07:47  cheshire
676 Make port number in debug message be five-character field, left justified
677 
678 Revision 1.342  2003/12/20 01:34:28  cheshire
679 <rdar://problem/3515876>: Error putting additional records into packets
680 Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
681 after every record, not once at the end.
682 
683 Revision 1.341  2003/12/18 22:56:12  cheshire
684 <rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
685 
686 Revision 1.340  2003/12/16 02:31:37  cheshire
687 Minor update to comments
688 
689 Revision 1.339  2003/12/13 05:50:33  bradley
690 Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
691 layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
692 fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
693 
694 Revision 1.338  2003/12/13 03:05:27  ksekar
695 <rdar://problem/3192548>: DynDNS: Unicast query of service records
696 
697 Revision 1.337  2003/12/01 21:46:05  cheshire
698 mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
699 
700 Revision 1.336  2003/12/01 21:26:19  cheshire
701 Guard against zero-length sbuffer in mDNS_vsnprintf()
702 
703 Revision 1.335  2003/12/01 20:27:48  cheshire
704 Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
705 
706 Revision 1.334  2003/11/20 22:59:53  cheshire
707 Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
708 Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
709 
710 Revision 1.333  2003/11/20 20:49:53  cheshire
711 Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
712 
713 Revision 1.332  2003/11/20 05:47:37  cheshire
714 <rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
715 Now that we only include answers in the known answer list if they are less than
716 halfway to expiry, the check to also see if we have another query scheduled
717 before the record expires is no longer necessary (and in fact, not correct).
718 
719 Revision 1.331  2003/11/19 22:31:48  cheshire
720 When automatically adding A records to SRVs, add them as additionals, not answers
721 
722 Revision 1.330  2003/11/19 22:28:50  cheshire
723 Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
724 to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
725 
726 Revision 1.329  2003/11/19 22:19:24  cheshire
727 Show log message when ignoring packets with bad TTL.
728 This is to help diagnose problems on Linux versions that may not report the TTL reliably.
729 
730 Revision 1.328  2003/11/19 22:06:38  cheshire
731 Show log messages when a service or hostname is renamed
732 
733 Revision 1.327  2003/11/19 22:03:44  cheshire
734 Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
735 
736 Revision 1.326  2003/11/17 22:27:02  cheshire
737 Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
738 on platforms that have native clock rates below fifty ticks per second.
739 
740 Revision 1.325  2003/11/17 20:41:44  cheshire
741 Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
742 
743 Revision 1.324  2003/11/17 20:36:32  cheshire
744 Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
745 DeadvertiseInterface() -- they're internal private routines, not API routines.
746 
747 Revision 1.323  2003/11/14 20:59:08  cheshire
748 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
749 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
750 
751 Revision 1.322  2003/11/14 19:47:52  cheshire
752 Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
753 
754 Revision 1.321  2003/11/14 19:18:34  cheshire
755 Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
756 
757 Revision 1.320  2003/11/13 06:45:04  cheshire
758 Fix compiler warning on certain compilers
759 
760 Revision 1.319  2003/11/13 00:47:40  cheshire
761 <rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
762 
763 Revision 1.318  2003/11/13 00:33:26  cheshire
764 Change macro "RRIsAddressType" to "RRTypeIsAddressType"
765 
766 Revision 1.317  2003/11/13 00:10:49  cheshire
767 <rdar://problem/3436412>: Verify that rr data is different before updating.
768 
769 Revision 1.316  2003/11/08 23:37:54  cheshire
770 Give explicit zero initializers to blank static structure, required by certain compilers.
771 (Thanks to ramaprasad.kr@hp.com for reporting this.)
772 
773 Revision 1.315  2003/11/07 03:32:56  cheshire
774 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
775 This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
776 purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
777 to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
778 can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
779 
780 Revision 1.314  2003/11/07 03:19:49  cheshire
781 Minor variable renaming for clarity
782 
783 Revision 1.313  2003/11/07 03:14:49  cheshire
784 Previous checkin proved to be overly simplistic; reversing
785 
786 Revision 1.312  2003/11/03 23:45:15  cheshire
787 <rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
788 Build cache lists in FIFO order, not customary C LIFO order
789 (Append new elements to tail of cache list, instead of prepending at the head.)
790 
791 Revision 1.311  2003/10/09 18:00:11  cheshire
792 Another compiler warning fix.
793 
794 Revision 1.310  2003/10/07 20:27:05  cheshire
795 Patch from Bob Bradley, to fix warning and compile error on Windows
796 
797 Revision 1.309  2003/09/26 01:06:36  cheshire
798 <rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
799 Made new routine HaveSentEntireRRSet() to check if flag should be set
800 
801 Revision 1.308  2003/09/23 01:05:01  cheshire
802 Minor changes to comments and debugf() message
803 
804 Revision 1.307  2003/09/09 20:13:30  cheshire
805 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it
806 Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented
807 rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount
808 
809 Revision 1.306  2003/09/09 03:00:03  cheshire
810 <rdar://problem/3413099> Services take a long time to disappear when switching networks.
811 Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect
812 
813 Revision 1.305  2003/09/09 02:49:31  cheshire
814 <rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep
815 
816 Revision 1.304  2003/09/09 02:41:19  cheshire
817 <rdar://problem/3411105> Don't send a Goodbye record if we never announced it
818 
819 Revision 1.303  2003/09/05 19:55:02  cheshire
820 <rdar://problem/3409533> Include address records when announcing SRV records
821 
822 Revision 1.302  2003/09/05 00:01:36  cheshire
823 <rdar://problem/3407549> Don't accelerate queries that have large KA lists
824 
825 Revision 1.301  2003/09/04 22:51:13  cheshire
826 <rdar://problem/3398213> Group probes and goodbyes better
827 
828 Revision 1.300  2003/09/03 02:40:37  cheshire
829 <rdar://problem/3404842> mDNSResponder complains about '_'s
830 Underscores are not supposed to be legal in standard DNS names, but IANA appears
831 to have allowed them in previous service name registrations, so we should too.
832 
833 Revision 1.299  2003/09/03 02:33:09  cheshire
834 <rdar://problem/3404795> CacheRecordRmv ERROR
835 Don't update m->NewQuestions until *after* CheckCacheExpiration();
836 
837 Revision 1.298  2003/09/03 01:47:01  cheshire
838 <rdar://problem/3319418> Services always in a state of flux
839 Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
840 
841 Revision 1.297  2003/08/29 19:44:15  cheshire
842 <rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
843 1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
844    that already have at least one unique answer in the cache
845 2. For these queries, go straight to QM, skipping QU
846 
847 Revision 1.296  2003/08/29 19:08:21  cheshire
848 <rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep
849 Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time.
850 
851 Revision 1.295  2003/08/28 01:10:59  cheshire
852 <rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst
853 
854 Revision 1.294  2003/08/27 02:30:22  cheshire
855 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
856 One more change: "query->GotTXT" is now a straightforward bi-state boolean again
857 
858 Revision 1.293  2003/08/27 02:25:31  cheshire
859 <rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
860 
861 Revision 1.292  2003/08/21 19:27:36  cheshire
862 <rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
863 
864 Revision 1.291  2003/08/21 18:57:44  cheshire
865 <rdar://problem/3387140> Synchronized queries on the network
866 
867 Revision 1.290  2003/08/21 02:25:23  cheshire
868 Minor changes to comments and debugf() messages
869 
870 Revision 1.289  2003/08/21 02:21:50  cheshire
871 <rdar://problem/3386473> Efficiency: Reduce repeated queries
872 
873 Revision 1.288  2003/08/20 23:39:30  cheshire
874 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
875 
876 Revision 1.287  2003/08/20 20:47:18  cheshire
877 Fix compiler warning
878 
879 Revision 1.286  2003/08/20 02:18:51  cheshire
880 <rdar://problem/3344098> Cleanup: Review syslog messages
881 
882 Revision 1.285  2003/08/20 01:59:06  cheshire
883 <rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata
884 Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place
885 
886 Revision 1.284  2003/08/19 22:20:00  cheshire
887 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
888 More minor refinements
889 
890 Revision 1.283  2003/08/19 22:16:27  cheshire
891 Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case.
892 
893 Revision 1.282  2003/08/19 06:48:25  cheshire
894 <rdar://problem/3376552> Guard against excessive record updates
895 Each record starts with 10 UpdateCredits.
896 Every update consumes one UpdateCredit.
897 UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
898 As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
899 When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
900 
901 Revision 1.281  2003/08/19 04:49:28  cheshire
902 <rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
903 1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
904 2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
905 3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
906 
907 Revision 1.280  2003/08/19 02:33:36  cheshire
908 Update comments
909 
910 Revision 1.279  2003/08/19 02:31:11  cheshire
911 <rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
912 Final expiration queries now only mark the question for sending on the particular interface
913 pertaining to the record that's expiring.
914 
915 Revision 1.278  2003/08/18 22:53:37  cheshire
916 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
917 
918 Revision 1.277  2003/08/18 19:05:44  cheshire
919 <rdar://problem/3382423> UpdateRecord not working right
920 Added "newrdlength" field to hold new length of updated rdata
921 
922 Revision 1.276  2003/08/16 03:39:00  cheshire
923 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
924 
925 Revision 1.275  2003/08/16 02:51:27  cheshire
926 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
927 Don't try to compute namehash etc, until *after* validating the name
928 
929 Revision 1.274  2003/08/16 01:12:40  cheshire
930 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
931 Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a
932 simple C structure assignment of a domainname, because that object is defined to be 256 bytes long,
933 and in the process of copying it, the C compiler may run off the end of the rdata object into
934 unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a
935 call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid.
936 
937 Revision 1.273  2003/08/15 20:16:02  cheshire
938 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
939 We want to avoid touching the rdata pages, so we don't page them in.
940 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
941    Moved this from the RData to the ResourceRecord object.
942 2. To avoid unnecessarily touching the rdata just to compare it,
943    compute a hash of the rdata and store the hash in the ResourceRecord object.
944 
945 Revision 1.272  2003/08/14 19:29:04  cheshire
946 <rdar://problem/3378473> Include cache records in SIGINFO output
947 Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
948 
949 Revision 1.271  2003/08/14 02:17:05  cheshire
950 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
951 
952 Revision 1.270  2003/08/13 17:07:28  ksekar
953 <rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
954 Added check to result of mDNS_Register() before linking extra record into list.
955 
956 Revision 1.269  2003/08/12 19:56:23  cheshire
957 Update to APSL 2.0
958 
959 Revision 1.268  2003/08/12 15:01:10  cheshire
960 Add comments
961 
962 Revision 1.267  2003/08/12 14:59:27  cheshire
963 <rdar://problem/3374490> Rate-limiting blocks some legitimate responses
964 When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
965 whether to suppress the response, also check LastMCInterface to see if it matches.
966 
967 Revision 1.266  2003/08/12 12:47:16  cheshire
968 In mDNSCoreMachineSleep debugf message, display value of m->timenow
969 
970 Revision 1.265  2003/08/11 20:04:28  cheshire
971 <rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache
972 
973 Revision 1.264  2003/08/09 00:55:02  cheshire
974 <rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
975 Don't scan the whole cache after every packet.
976 
977 Revision 1.263  2003/08/09 00:35:29  cheshire
978 Moved AnswerNewQuestion() later in the file, in preparation for next checkin
979 
980 Revision 1.262  2003/08/08 19:50:33  cheshire
981 <rdar://problem/3370332> Remove "Cache size now xxx" messages
982 
983 Revision 1.261  2003/08/08 19:18:45  cheshire
984 <rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug
985 
986 Revision 1.260  2003/08/08 18:55:48  cheshire
987 <rdar://problem/3370365> Guard against time going backwards
988 
989 Revision 1.259  2003/08/08 18:36:04  cheshire
990 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
991 
992 Revision 1.258  2003/08/08 16:22:05  cheshire
993 <rdar://problem/3335473> Need to check validity of TXT (and other) records
994 Remove unneeded LogMsg
995 
996 Revision 1.257  2003/08/07 01:41:08  cheshire
997 <rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones)
998 
999 Revision 1.256  2003/08/06 23:25:51  cheshire
1000 <rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four
1001 
1002 Revision 1.255  2003/08/06 23:22:50  cheshire
1003 Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours)
1004 
1005 Revision 1.254  2003/08/06 21:33:39  cheshire
1006 Fix compiler warnings on PocketPC 2003 (Windows CE)
1007 
1008 Revision 1.253  2003/08/06 20:43:57  cheshire
1009 <rdar://problem/3335473> Need to check validity of TXT (and other) records
1010 Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update()
1011 
1012 Revision 1.252  2003/08/06 20:35:47  cheshire
1013 Enhance debugging routine GetRRDisplayString() so it can also be used to display
1014 other RDataBody objects, not just the one currently attached the given ResourceRecord
1015 
1016 Revision 1.251  2003/08/06 19:07:34  cheshire
1017 <rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should
1018 Was checking LastAPTime instead of LastMCTime
1019 
1020 Revision 1.250  2003/08/06 19:01:55  cheshire
1021 Update comments
1022 
1023 Revision 1.249  2003/08/06 00:13:28  cheshire
1024 Tidy up debugf messages
1025 
1026 Revision 1.248  2003/08/05 22:20:15  cheshire
1027 <rdar://problem/3330324> Need to check IP TTL on responses
1028 
1029 Revision 1.247  2003/08/05 00:56:39  cheshire
1030 <rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed
1031 
1032 Revision 1.246  2003/08/04 19:20:49  cheshire
1033 Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages
1034 
1035 Revision 1.245  2003/08/02 01:56:29  cheshire
1036 For debugging: log message if we ever get more than one question in a truncated packet
1037 
1038 Revision 1.244  2003/08/01 23:55:32  cheshire
1039 Fix for compiler warnings on Windows, submitted by Bob Bradley
1040 
1041 Revision 1.243  2003/07/25 02:26:09  cheshire
1042 Typo: FIxed missing semicolon
1043 
1044 Revision 1.242  2003/07/25 01:18:41  cheshire
1045 Fix memory leak on shutdown in mDNS_Close() (detected in Windows version)
1046 
1047 Revision 1.241  2003/07/23 21:03:42  cheshire
1048 Only show "Found record..." debugf message in verbose mode
1049 
1050 Revision 1.240  2003/07/23 21:01:11  cheshire
1051 <rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one
1052 After sending a packet, suppress further sending for the next 100ms.
1053 
1054 Revision 1.239  2003/07/22 01:30:05  cheshire
1055 <rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once
1056 
1057 Revision 1.238  2003/07/22 00:10:20  cheshire
1058 <rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters
1059 
1060 Revision 1.237  2003/07/19 03:23:13  cheshire
1061 <rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
1062 
1063 Revision 1.236  2003/07/19 03:04:55  cheshire
1064 Fix warnings; some debugf message improvements
1065 
1066 Revision 1.235  2003/07/19 00:03:32  cheshire
1067 <rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received
1068 ScheduleNextTask is quite an expensive operation.
1069 We don't need to do all that work after receiving a no-op packet that didn't change our state.
1070 
1071 Revision 1.234  2003/07/18 23:52:11  cheshire
1072 To improve consistency of field naming, global search-and-replace:
1073 NextProbeTime    -> NextScheduledProbe
1074 NextResponseTime -> NextScheduledResponse
1075 
1076 Revision 1.233  2003/07/18 00:29:59  cheshire
1077 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
1078 
1079 Revision 1.232  2003/07/18 00:11:38  cheshire
1080 Add extra case to switch statements to handle HINFO data for Get, Put and Display
1081 (In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT)
1082 
1083 Revision 1.231  2003/07/18 00:06:37  cheshire
1084 To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
1085 
1086 Revision 1.230  2003/07/17 18:16:54  cheshire
1087 <rdar://problem/3319418> Services always in a state of flux
1088 In preparation for working on this, made some debugf messages a little more selective
1089 
1090 Revision 1.229  2003/07/17 17:35:04  cheshire
1091 <rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
1092 
1093 Revision 1.228  2003/07/16 20:50:27  cheshire
1094 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1095 
1096 Revision 1.227  2003/07/16 05:01:36  cheshire
1097 Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
1098 <rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
1099 
1100 Revision 1.226  2003/07/16 04:51:44  cheshire
1101 Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval'
1102 
1103 Revision 1.225  2003/07/16 04:46:41  cheshire
1104 Minor wording cleanup: The correct DNS term is "response", not "reply"
1105 
1106 Revision 1.224  2003/07/16 04:39:02  cheshire
1107 Textual cleanup (no change to functionality):
1108 Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)"
1109 
1110 Revision 1.223  2003/07/16 00:09:22  cheshire
1111 Textual cleanup (no change to functionality):
1112 Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places;
1113 replace with macro "TicksTTL(rr)"
1114 Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)"
1115 replaced with macro "RRExpireTime(rr)"
1116 
1117 Revision 1.222  2003/07/15 23:40:46  cheshire
1118 Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo()
1119 
1120 Revision 1.221  2003/07/15 22:17:56  cheshire
1121 <rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries
1122 
1123 Revision 1.220  2003/07/15 02:12:51  cheshire
1124 Slight tidy-up of debugf messages and comments
1125 
1126 Revision 1.219  2003/07/15 01:55:12  cheshire
1127 <rdar://problem/3315777> Need to implement service registration with subtypes
1128 
1129 Revision 1.218  2003/07/14 16:26:06  cheshire
1130 <rdar://problem/3324795> Duplicate query suppression not working right
1131 Refinement: Don't record DS information for a question in the first quarter second
1132 right after we send it -- in the case where a question happens to be accelerated by
1133 the maximum allowed amount, we don't want it to then be suppressed because the previous
1134 time *we* sent that question falls (just) within the valid duplicate suppression window.
1135 
1136 Revision 1.217  2003/07/13 04:43:53  cheshire
1137 <rdar://problem/3325169> Services on multiple interfaces not always resolving
1138 Minor refinement: No need to make address query broader than the original SRV query that provoked it
1139 
1140 Revision 1.216  2003/07/13 03:13:17  cheshire
1141 <rdar://problem/3325169> Services on multiple interfaces not always resolving
1142 If we get an identical SRV on a second interface, convert address queries to non-specific
1143 
1144 Revision 1.215  2003/07/13 02:28:00  cheshire
1145 <rdar://problem/3325166> SendResponses didn't all its responses
1146 Delete all references to RRInterfaceActive -- it's now superfluous
1147 
1148 Revision 1.214  2003/07/13 01:47:53  cheshire
1149 Fix one error and one warning in the Windows build
1150 
1151 Revision 1.213  2003/07/12 04:25:48  cheshire
1152 Fix minor signed/unsigned warnings
1153 
1154 Revision 1.212  2003/07/12 01:59:11  cheshire
1155 Minor changes to debugf messages
1156 
1157 Revision 1.211  2003/07/12 01:47:01  cheshire
1158 <rdar://problem/3324495> After name conflict, appended number should be higher than previous number
1159 
1160 Revision 1.210  2003/07/12 01:43:28  cheshire
1161 <rdar://problem/3324795> Duplicate query suppression not working right
1162 The correct cutoff time for duplicate query suppression is timenow less one-half the query interval.
1163 The code was incorrectly using the last query time plus one-half the query interval.
1164 This was only correct in the case where query acceleration was not in effect.
1165 
1166 Revision 1.209  2003/07/12 01:27:50  cheshire
1167 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1168 Fix missing "-1" in RemoveLabelSuffix()
1169 
1170 Revision 1.208  2003/07/11 01:32:38  cheshire
1171 Syntactic cleanup (no change to funcationality): Now that we only have one host name,
1172 rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
1173 
1174 Revision 1.207  2003/07/11 01:28:00  cheshire
1175 <rdar://problem/3161289> No more local.arpa
1176 
1177 Revision 1.206  2003/07/11 00:45:02  cheshire
1178 <rdar://problem/3321909> Client should get callback confirming successful host name registration
1179 
1180 Revision 1.205  2003/07/11 00:40:18  cheshire
1181 Tidy up debug message in HostNameCallback()
1182 
1183 Revision 1.204  2003/07/11 00:20:32  cheshire
1184 <rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes
1185 
1186 Revision 1.203  2003/07/10 23:53:41  cheshire
1187 <rdar://problem/3320079> Hostname conflict naming should not use two hyphens
1188 
1189 Revision 1.202  2003/07/04 02:23:20  cheshire
1190 <rdar://problem/3311955> Responder too aggressive at flushing stale data
1191 Changed mDNSResponder to require four unanswered queries before purging a record, instead of two.
1192 
1193 Revision 1.201  2003/07/04 01:09:41  cheshire
1194 <rdar://problem/3315775> Need to implement subtype queries
1195 Modified ConstructServiceName() to allow three-part service types
1196 
1197 Revision 1.200  2003/07/03 23:55:26  cheshire
1198 Minor change to wording of syslog warning messages
1199 
1200 Revision 1.199  2003/07/03 23:51:13  cheshire
1201 <rdar://problem/3315652>:	Lots of "have given xxx answers" syslog warnings
1202 Added more detailed debugging information
1203 
1204 Revision 1.198  2003/07/03 22:19:30  cheshire
1205 <rdar://problem/3314346> Bug fix in 3274153 breaks TiVo
1206 Make exception to allow _tivo_servemedia._tcp.
1207 
1208 Revision 1.197  2003/07/02 22:33:05  cheshire
1209 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1210 Minor refinements:
1211 When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not
1212 Allow cache to grow to 512 records before considering it a potential denial-of-service attack
1213 
1214 Revision 1.196  2003/07/02 21:19:45  cheshire
1215 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
1216 
1217 Revision 1.195  2003/07/02 19:56:58  cheshire
1218 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1219 Minor refinement: m->rrcache_active was not being decremented when
1220 an active record was deleted because its TTL expired
1221 
1222 Revision 1.194  2003/07/02 18:47:40  cheshire
1223 Minor wording change to log messages
1224 
1225 Revision 1.193  2003/07/02 02:44:13  cheshire
1226 Fix warning in non-debug build
1227 
1228 Revision 1.192  2003/07/02 02:41:23  cheshire
1229 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
1230 
1231 Revision 1.191  2003/07/02 02:30:51  cheshire
1232 HashSlot() returns an array index. It can't be negative; hence it should not be signed.
1233 
1234 Revision 1.190  2003/06/27 00:03:05  vlubet
1235 <rdar://problem/3304625> Merge of build failure fix for gcc 3.3
1236 
1237 Revision 1.189  2003/06/11 19:24:03  cheshire
1238 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1239 Slight refinement to previous checkin
1240 
1241 Revision 1.188  2003/06/10 20:33:28  cheshire
1242 <rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
1243 
1244 Revision 1.187  2003/06/10 04:30:44  cheshire
1245 <rdar://problem/3286234> Need to re-probe/re-announce on configuration change
1246 Only interface-specific records were re-probing and re-announcing, not non-specific records.
1247 
1248 Revision 1.186  2003/06/10 04:24:39  cheshire
1249 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1250 Some additional refinements:
1251 Don't try to do this for unicast-response queries
1252 better tracking of Qs and KAs in multi-packet KA lists
1253 
1254 Revision 1.185  2003/06/10 03:52:49  cheshire
1255 Update comments and debug messages
1256 
1257 Revision 1.184  2003/06/10 02:26:39  cheshire
1258 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1259 Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines
1260 
1261 Revision 1.183  2003/06/09 18:53:13  cheshire
1262 Simplify some debugf() statements (replaced block of 25 lines with 2 lines)
1263 
1264 Revision 1.182  2003/06/09 18:38:42  cheshire
1265 <rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network
1266 Only issue a correction if the TTL in the proxy packet is less than half the correct value.
1267 
1268 Revision 1.181  2003/06/07 06:45:05  cheshire
1269 <rdar://problem/3283666> No need for multiple machines to all be sending the same queries
1270 
1271 Revision 1.180  2003/06/07 06:31:07  cheshire
1272 Create little four-line helper function "FindIdenticalRecordInCache()"
1273 
1274 Revision 1.179  2003/06/07 06:28:13  cheshire
1275 For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq"
1276 
1277 Revision 1.178  2003/06/07 06:25:12  cheshire
1278 Update some comments
1279 
1280 Revision 1.177  2003/06/07 04:50:53  cheshire
1281 <rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
1282 
1283 Revision 1.176  2003/06/07 04:33:26  cheshire
1284 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1285 Minor change: Increment/decrement logic for q->CurrentAnswers should be in
1286 CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord()
1287 
1288 Revision 1.175  2003/06/07 04:11:52  cheshire
1289 Minor changes to comments and debug messages
1290 
1291 Revision 1.174  2003/06/07 01:46:38  cheshire
1292 <rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
1293 
1294 Revision 1.173  2003/06/07 01:22:13  cheshire
1295 <rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
1296 
1297 Revision 1.172  2003/06/07 00:59:42  cheshire
1298 <rdar://problem/3283454> Need some randomness to spread queries on the network
1299 
1300 Revision 1.171  2003/06/06 21:41:10  cheshire
1301 For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
1302 
1303 Revision 1.170  2003/06/06 21:38:55  cheshire
1304 Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
1305 already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
1306 
1307 Revision 1.169  2003/06/06 21:35:55  cheshire
1308 Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget
1309 (the target is a domain name, but not necessarily a host name)
1310 
1311 Revision 1.168  2003/06/06 21:33:31  cheshire
1312 Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval"
1313 
1314 Revision 1.167  2003/06/06 21:30:42  cheshire
1315 <rdar://problem/3282962> Don't delay queries for shared record types
1316 
1317 Revision 1.166  2003/06/06 17:20:14  cheshire
1318 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
1319 (Global search-and-replace; no functional change to code execution.)
1320 
1321 Revision 1.165  2003/06/04 02:53:21  cheshire
1322 Add some "#pragma warning" lines so it compiles clean on Microsoft compilers
1323 
1324 Revision 1.164  2003/06/04 01:25:33  cheshire
1325 <rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
1326 Display time interval between first and subsequent queries
1327 
1328 Revision 1.163  2003/06/03 19:58:14  cheshire
1329 <rdar://problem/3277665> mDNS_DeregisterService() fixes:
1330 When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet.
1331 Guard against a couple of possible mDNS_DeregisterService() race conditions.
1332 
1333 Revision 1.162  2003/06/03 19:30:39  cheshire
1334 Minor addition refinements for
1335 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1336 
1337 Revision 1.161  2003/06/03 18:29:03  cheshire
1338 Minor changes to comments and debugf() messages
1339 
1340 Revision 1.160  2003/06/03 05:02:16  cheshire
1341 <rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
1342 
1343 Revision 1.159  2003/06/03 03:31:57  cheshire
1344 <rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine
1345 
1346 Revision 1.158  2003/06/02 22:57:09  cheshire
1347 Minor clarifying changes to comments and log messages;
1348 IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord()
1349 
1350 Revision 1.157  2003/05/31 00:09:49  cheshire
1351 <rdar://problem/3274862> Add ability to discover what services are on a network
1352 
1353 Revision 1.156  2003/05/30 23:56:49  cheshire
1354 <rdar://problem/3274847> Crash after error in mDNS_RegisterService()
1355 Need to set "sr->Extras = mDNSNULL" before returning
1356 
1357 Revision 1.155  2003/05/30 23:48:00  cheshire
1358 <rdar://problem/3274832> Announcements not properly grouped
1359 Due to inconsistent setting of rr->LastAPTime at different places in the
1360 code, announcements were not properly grouped into a single packet.
1361 Fixed by creating a single routine called InitializeLastAPTime().
1362 
1363 Revision 1.154  2003/05/30 23:38:14  cheshire
1364 <rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records
1365 Wrote buffer[32] where it should have said buffer[64]
1366 
1367 Revision 1.153  2003/05/30 19:10:56  cheshire
1368 <rdar://problem/3274153> ConstructServiceName needs to be more restrictive
1369 
1370 Revision 1.152  2003/05/29 22:39:16  cheshire
1371 <rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character
1372 
1373 Revision 1.151  2003/05/29 06:35:42  cheshire
1374 <rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record
1375 
1376 Revision 1.150  2003/05/29 06:25:45  cheshire
1377 <rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion()
1378 
1379 Revision 1.149  2003/05/29 06:18:39  cheshire
1380 <rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv
1381 
1382 Revision 1.148  2003/05/29 06:11:34  cheshire
1383 <rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks
1384 
1385 Revision 1.147  2003/05/29 06:01:18  cheshire
1386 Change some debugf() calls to LogMsg() calls to help with debugging
1387 
1388 Revision 1.146  2003/05/28 21:00:44  cheshire
1389 Re-enable "immediate answer burst" debugf message
1390 
1391 Revision 1.145  2003/05/28 20:57:44  cheshire
1392 <rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet
1393 known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2
1394 version of mDNSResponder, so for now we should suppress this warning message.
1395 
1396 Revision 1.144  2003/05/28 18:05:12  cheshire
1397 <rdar://problem/3009899> mDNSResponder allows invalid service registrations
1398 Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names
1399 
1400 Revision 1.143  2003/05/28 04:31:29  cheshire
1401 <rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time
1402 
1403 Revision 1.142  2003/05/28 03:13:07  cheshire
1404 <rdar://problem/3009899> mDNSResponder allows invalid service registrations
1405 Require that the transport protocol be _udp or _tcp
1406 
1407 Revision 1.141  2003/05/28 02:19:12  cheshire
1408 <rdar://problem/3270634> Misleading messages generated by iChat
1409 Better fix: Only generate the log message for queries where the TC bit is set.
1410 
1411 Revision 1.140  2003/05/28 01:55:24  cheshire
1412 Minor change to log messages
1413 
1414 Revision 1.139  2003/05/28 01:52:51  cheshire
1415 <rdar://problem/3270634> Misleading messages generated by iChat
1416 
1417 Revision 1.138  2003/05/27 22:35:00  cheshire
1418 <rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions
1419 
1420 Revision 1.137  2003/05/27 20:04:33  cheshire
1421 <rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf()
1422 
1423 Revision 1.136  2003/05/27 18:50:07  cheshire
1424 <rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes
1425 
1426 Revision 1.135  2003/05/26 04:57:28  cheshire
1427 <rdar://problem/3268953> Delay queries when there are already answers in the cache
1428 
1429 Revision 1.134  2003/05/26 04:54:54  cheshire
1430 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1431 Accidentally deleted '%' case from the switch statement
1432 
1433 Revision 1.133  2003/05/26 03:21:27  cheshire
1434 Tidy up address structure naming:
1435 mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
1436 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
1437 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
1438 
1439 Revision 1.132  2003/05/26 03:01:26  cheshire
1440 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
1441 
1442 Revision 1.131  2003/05/26 00:42:05  cheshire
1443 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
1444 
1445 Revision 1.130  2003/05/24 16:39:48  cheshire
1446 <rdar://problem/3268631> SendResponses also needs to handle multihoming better
1447 
1448 Revision 1.129  2003/05/23 02:15:37  cheshire
1449 Fixed misleading use of the term "duplicate suppression" where it should have
1450 said "known answer suppression". (Duplicate answer suppression is something
1451 different, and duplicate question suppression is yet another thing, so the use
1452 of the completely vague term "duplicate suppression" was particularly bad.)
1453 
1454 Revision 1.128  2003/05/23 01:55:13  cheshire
1455 <rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
1456 
1457 Revision 1.127  2003/05/23 01:02:15  ksekar
1458 <rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
1459 
1460 Revision 1.126  2003/05/22 02:29:22  cheshire
1461 <rdar://problem/2984918> SendQueries needs to handle multihoming better
1462 Complete rewrite of SendQueries. Works much better now :-)
1463 
1464 Revision 1.125  2003/05/22 01:50:45  cheshire
1465 Fix warnings, and improve log messages
1466 
1467 Revision 1.124  2003/05/22 01:41:50  cheshire
1468 DiscardDeregistrations doesn't need InterfaceID parameter
1469 
1470 Revision 1.123  2003/05/22 01:38:55  cheshire
1471 Change bracketing of #pragma mark
1472 
1473 Revision 1.122  2003/05/21 19:59:04  cheshire
1474 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1475 Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
1476 
1477 Revision 1.121  2003/05/21 17:54:07  ksekar
1478 <rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
1479 New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
1480 
1481 Revision 1.120  2003/05/19 22:14:14  ksekar
1482 <rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type
1483 
1484 Revision 1.119  2003/05/16 01:34:10  cheshire
1485 Fix some warnings
1486 
1487 Revision 1.118  2003/05/14 18:48:40  cheshire
1488 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1489 More minor refinements:
1490 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
1491 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
1492 
1493 Revision 1.117  2003/05/14 07:08:36  cheshire
1494 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
1495 Previously, when there was any network configuration change, mDNSResponder
1496 would tear down the entire list of active interfaces and start again.
1497 That was very disruptive, and caused the entire cache to be flushed,
1498 and caused lots of extra network traffic. Now it only removes interfaces
1499 that have really gone, and only adds new ones that weren't there before.
1500 
1501 Revision 1.116  2003/05/14 06:51:56  cheshire
1502 <rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
1503 
1504 Revision 1.115  2003/05/14 06:44:31  cheshire
1505 Improve debugging message
1506 
1507 Revision 1.114  2003/05/07 01:47:03  cheshire
1508 <rdar://problem/3250330> Also protect against NULL domainlabels
1509 
1510 Revision 1.113  2003/05/07 00:28:18  cheshire
1511 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
1512 
1513 Revision 1.112  2003/05/06 00:00:46  cheshire
1514 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
1515 
1516 Revision 1.111  2003/05/05 23:42:08  cheshire
1517 <rdar://problem/3245631> Resolves never succeed
1518 Was setting "rr->LastAPTime = timenow - rr->LastAPTime"
1519 instead of  "rr->LastAPTime = timenow - rr->ThisAPInterval"
1520 
1521 Revision 1.110  2003/04/30 21:09:59  cheshire
1522 <rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names
1523 
1524 Revision 1.109  2003/04/26 02:41:56  cheshire
1525 <rdar://problem/3241281> Change timenow from a local variable to a structure member
1526 
1527 Revision 1.108  2003/04/25 01:45:56  cheshire
1528 <rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
1529 
1530 Revision 1.107  2003/04/25 00:41:31  cheshire
1531 <rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future
1532 
1533 Revision 1.106  2003/04/22 03:14:45  cheshire
1534 <rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now
1535 
1536 Revision 1.105  2003/04/22 01:07:43  cheshire
1537 <rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl
1538 If TTL parameter is zero, leave record TTL unchanged
1539 
1540 Revision 1.104  2003/04/21 19:15:52  cheshire
1541 Fix some compiler warnings
1542 
1543 Revision 1.103  2003/04/19 02:26:35  cheshire
1544 <rdar://problem/3233804> Incorrect goodbye packet after conflict
1545 
1546 Revision 1.102  2003/04/17 03:06:28  cheshire
1547 <rdar://problem/3231321> No need to query again when a service goes away
1548 Set UnansweredQueries to 2 when receiving a "goodbye" packet
1549 
1550 Revision 1.101  2003/04/15 20:58:31  jgraessl
1551 <rdar://problem/3229014> Added a hash to lookup records in the cache.
1552 
1553 Revision 1.100  2003/04/15 18:53:14  cheshire
1554 <rdar://problem/3229064> Bug in ScheduleNextTask
1555 mDNS.c 1.94 incorrectly combined two "if" statements into one.
1556 
1557 Revision 1.99  2003/04/15 18:09:13  jgraessl
1558 <rdar://problem/3228892>
1559 Reviewed by: Stuart Cheshire
1560 Added code to keep track of when the next cache item will expire so we can
1561 call TidyRRCache only when necessary.
1562 
1563 Revision 1.98  2003/04/03 03:43:55  cheshire
1564 <rdar://problem/3216837> Off-by-one error in probe rate limiting
1565 
1566 Revision 1.97  2003/04/02 01:48:17  cheshire
1567 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1568 Additional fix pointed out by Josh:
1569 Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state
1570 
1571 Revision 1.96  2003/04/01 23:58:55  cheshire
1572 Minor comment changes
1573 
1574 Revision 1.95  2003/04/01 23:46:05  cheshire
1575 <rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles
1576 mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface
1577 to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second
1578 window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in
1579 FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed.
1580 
1581 Revision 1.94  2003/03/29 01:55:19  cheshire
1582 <rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
1583 Solution: Major cleanup of packet timing and conflict handling rules
1584 
1585 Revision 1.93  2003/03/28 01:54:36  cheshire
1586 Minor tidyup of IPv6 (AAAA) code
1587 
1588 Revision 1.92  2003/03/27 03:30:55  cheshire
1589 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
1590 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
1591 Fixes:
1592 1. Make mDNS_DeregisterInterface() safe to call from a callback
1593 2. Make HostNameCallback() use DeadvertiseInterface() instead
1594    (it never really needed to deregister the interface at all)
1595 
1596 Revision 1.91  2003/03/15 04:40:36  cheshire
1597 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
1598 
1599 Revision 1.90  2003/03/14 20:26:37  cheshire
1600 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1601 
1602 Revision 1.89  2003/03/12 19:57:50  cheshire
1603 Fixed typo in debug message
1604 
1605 Revision 1.88  2003/03/12 00:17:44  cheshire
1606 <rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records
1607 
1608 Revision 1.87  2003/03/11 01:27:20  cheshire
1609 Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
1610 
1611 Revision 1.86  2003/03/06 20:44:33  cheshire
1612 Comment tidyup
1613 
1614 Revision 1.85  2003/03/05 03:38:35  cheshire
1615 <rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
1616 Fixed by leaving client in list after conflict, until client explicitly deallocates
1617 
1618 Revision 1.84  2003/03/05 01:27:30  cheshire
1619 <rdar://problem/3185482> Different TTL for multicast versus unicast responses
1620 When building unicast responses, record TTLs are capped to 10 seconds
1621 
1622 Revision 1.83  2003/03/04 23:48:52  cheshire
1623 <rdar://problem/3188865> Double probes after wake from sleep
1624 Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
1625 
1626 Revision 1.82  2003/03/04 23:38:29  cheshire
1627 <rdar://problem/3099194> mDNSResponder needs performance improvements
1628 Only set rr->CRActiveQuestion to point to the
1629 currently active representative of a question set
1630 
1631 Revision 1.81  2003/02/21 03:35:34  cheshire
1632 <rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
1633 
1634 Revision 1.80  2003/02/21 02:47:53  cheshire
1635 <rdar://problem/3099194> mDNSResponder needs performance improvements
1636 Several places in the code were calling CacheRRActive(), which searched the entire
1637 question list every time, to see if this cache resource record answers any question.
1638 Instead, we now have a field "CRActiveQuestion" in the resource record structure
1639 
1640 Revision 1.79  2003/02/21 01:54:07  cheshire
1641 <rdar://problem/3099194> mDNSResponder needs performance improvements
1642 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
1643 
1644 Revision 1.78  2003/02/20 06:48:32  cheshire
1645 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
1646 Reviewed by: Josh Graessley, Bob Bradley
1647 
1648 Revision 1.77  2003/01/31 03:35:59  cheshire
1649 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1650 When there were *two* active questions in the list, they were incorrectly
1651 finding *each other* and *both* being marked as duplicates of another question
1652 
1653 Revision 1.76  2003/01/29 02:46:37  cheshire
1654 Fix for IPv6:
1655 A physical interface is identified solely by its InterfaceID (not by IP and type).
1656 On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
1657 In cases where the requested outbound protocol (v4 or v6) is not supported on
1658 that InterfaceID, the platform support layer should simply discard that packet.
1659 
1660 Revision 1.75  2003/01/29 01:47:40  cheshire
1661 Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
1662 
1663 Revision 1.74  2003/01/28 05:26:25  cheshire
1664 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1665 Add 'Active' flag for interfaces
1666 
1667 Revision 1.73  2003/01/28 03:45:12  cheshire
1668 Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
1669 
1670 Revision 1.72  2003/01/28 01:49:48  cheshire
1671 <rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
1672 FindDuplicateQuestion() was incorrectly finding the question itself in the list,
1673 and incorrectly marking it as a duplicate (of itself), so that it became inactive.
1674 
1675 Revision 1.71  2003/01/28 01:41:44  cheshire
1676 <rdar://problem/3153091> Race condition when network change causes bad stuff
1677 When an interface goes away, interface-specific questions on that interface become orphaned.
1678 Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
1679 Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
1680 
1681 Revision 1.70  2003/01/23 19:00:20  cheshire
1682 Protect against infinite loops in mDNS_Execute
1683 
1684 Revision 1.69  2003/01/21 22:56:32  jgraessl
1685 <rdar://problem/3124348>  service name changes are not properly handled
1686 Submitted by: Stuart Cheshire
1687 Reviewed by: Joshua Graessley
1688 Applying changes for 3124348 to main branch. 3124348 changes went in to a
1689 branch for SU.
1690 
1691 Revision 1.68  2003/01/17 04:09:27  cheshire
1692 <rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
1693 
1694 Revision 1.67  2003/01/17 03:56:45  cheshire
1695 Default 24-hour TTL is far too long. Changing to two hours.
1696 
1697 Revision 1.66  2003/01/13 23:49:41  jgraessl
1698 Merged changes for the following fixes in to top of tree:
1699 <rdar://problem/3086540>  computer name changes not handled properly
1700 <rdar://problem/3124348>  service name changes are not properly handled
1701 <rdar://problem/3124352>  announcements sent in pairs, failing chattiness test
1702 
1703 Revision 1.65  2002/12/23 22:13:28  jgraessl
1704 Reviewed by: Stuart Cheshire
1705 Initial IPv6 support for mDNSResponder.
1706 
1707 Revision 1.64  2002/11/26 20:49:06  cheshire
1708 <rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
1709 
1710 Revision 1.63  2002/09/21 20:44:49  zarzycki
1711 Added APSL info
1712 
1713 Revision 1.62  2002/09/20 03:25:37  cheshire
1714 Fix some compiler warnings
1715 
1716 Revision 1.61  2002/09/20 01:05:24  cheshire
1717 Don't kill the Extras list in mDNS_DeregisterService()
1718 
1719 Revision 1.60  2002/09/19 23:47:35  cheshire
1720 Added mDNS_RegisterNoSuchService() function for assertion of non-existence
1721 of a particular named service
1722 
1723 Revision 1.59  2002/09/19 21:25:34  cheshire
1724 mDNS_snprintf() doesn't need to be in a separate file
1725 
1726 Revision 1.58  2002/09/19 04:20:43  cheshire
1727 Remove high-ascii characters that confuse some systems
1728 
1729 Revision 1.57  2002/09/17 01:07:08  cheshire
1730 Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
1731 
1732 Revision 1.56  2002/09/16 19:44:17  cheshire
1733 Merge in license terms from Quinn's copy, in preparation for Darwin release
1734 */
1735 
1736 #pragma ident	"%Z%%M%	%I%	%E% SMI"
1737 
1738 #include "DNSCommon.h"                  // Defines general DNS untility routines
1739 #include "uDNS.h"						// Defines entry points into unicast-specific routines
1740 // Disable certain benign warnings with Microsoft compilers
1741 #if(defined(_MSC_VER))
1742 	// Disable "conditional expression is constant" warning for debug macros.
1743 	// Otherwise, this generates warnings for the perfectly natural construct "while(1)"
1744 	// If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
1745 	#pragma warning(disable:4127)
1746 
1747 	// Disable "assignment within conditional expression".
1748 	// Other compilers understand the convention that if you place the assignment expression within an extra pair
1749 	// of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
1750 	// The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
1751 	// to the compiler that the assignment is intentional, we have to just turn this warning off completely.
1752 	#pragma warning(disable:4706)
1753 #endif
1754 
1755 // ***************************************************************************
1756 #if COMPILER_LIKES_PRAGMA_MARK
1757 #pragma mark -
1758 #pragma mark - Program Constants
1759 #endif
1760 
1761 mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
1762 mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
1763 mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
1764 mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
1765 mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
1766 mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
1767 mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
1768 
1769 mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
1770 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)1;
1771 
1772 mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
1773 
1774 #define UnicastDNSPortAsNumber   53
1775 #define NATPMPPortAsNumber       5351
1776 #define DNSEXTPortAsNumber       5352		// Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
1777 #define MulticastDNSPortAsNumber 5353
1778 #define LoopbackIPCPortAsNumber  5354
1779 
1780 mDNSexport const mDNSIPPort UnicastDNSPort     = { { UnicastDNSPortAsNumber   >> 8, UnicastDNSPortAsNumber   & 0xFF } };
1781 mDNSexport const mDNSIPPort NATPMPPort         = { { NATPMPPortAsNumber       >> 8, NATPMPPortAsNumber       & 0xFF } };
1782 mDNSexport const mDNSIPPort DNSEXTPort         = { { DNSEXTPortAsNumber       >> 8, DNSEXTPortAsNumber       & 0xFF } };
1783 mDNSexport const mDNSIPPort MulticastDNSPort   = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
1784 mDNSexport const mDNSIPPort LoopbackIPCPort    = { { LoopbackIPCPortAsNumber  >> 8, LoopbackIPCPortAsNumber  & 0xFF } };
1785 
1786 mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
1787 mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
1788 mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
1789 
1790 mDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
1791 mDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
1792 mDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
1793 mDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
1794 mDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
1795 mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
1796 
1797 // Any records bigger than this are considered 'large' records
1798 #define SmallRecordLimit 1024
1799 
1800 #define kMaxUpdateCredits 10
1801 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
1802 
1803 mDNSexport const char *const mDNS_DomainTypeNames[] =
1804 	{
1805 	 "b._dns-sd._udp.",		// Browse
1806 	"db._dns-sd._udp.",		// Default Browse
1807 	"lb._dns-sd._udp.",		// Legacy Browse
1808 	 "r._dns-sd._udp.",		// Registration
1809 	"dr._dns-sd._udp."		// Default Registration
1810 	};
1811 
1812 #ifdef UNICAST_DISABLED
1813 #define uDNS_IsActiveQuery(q, u) mDNSfalse
1814 #endif
1815 
1816 // ***************************************************************************
1817 #if COMPILER_LIKES_PRAGMA_MARK
1818 #pragma mark -
1819 #pragma mark - Specialized mDNS version of vsnprintf
1820 #endif
1821 
1822 static const struct mDNSprintf_format
1823 	{
1824 	unsigned      leftJustify : 1;
1825 	unsigned      forceSign : 1;
1826 	unsigned      zeroPad : 1;
1827 	unsigned      havePrecision : 1;
1828 	unsigned      hSize : 1;
1829 	unsigned      lSize : 1;
1830 	char          altForm;
1831 	char          sign;		// +, - or space
1832 	unsigned int  fieldWidth;
1833 	unsigned int  precision;
1834 	} mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1835 
mDNS_vsnprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,va_list arg)1836 mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
1837 	{
1838 	mDNSu32 nwritten = 0;
1839 	int c;
1840 	if (buflen == 0) return(0);
1841 	buflen--;		// Pre-reserve one space in the buffer for the terminating null
1842 	if (buflen == 0) goto exit;
1843 
1844 	for (c = *fmt; c != 0; c = *++fmt)
1845 		{
1846 		if (c != '%')
1847 			{
1848 			*sbuffer++ = (char)c;
1849 			if (++nwritten >= buflen) goto exit;
1850 			}
1851 		else
1852 			{
1853 			unsigned int i=0, j;
1854 			// The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
1855 			// generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
1856 			// The size needs to be enough for a 256-byte domain name plus some error text.
1857 			#define mDNS_VACB_Size 300
1858 			char mDNS_VACB[mDNS_VACB_Size];
1859 			#define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
1860 			#define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
1861 			char *s = mDNS_VACB_Lim, *digits;
1862 			struct mDNSprintf_format F = mDNSprintf_format_default;
1863 
1864 			while (1)	//  decode flags
1865 				{
1866 				c = *++fmt;
1867 				if      (c == '-') F.leftJustify = 1;
1868 				else if (c == '+') F.forceSign = 1;
1869 				else if (c == ' ') F.sign = ' ';
1870 				else if (c == '#') F.altForm++;
1871 				else if (c == '0') F.zeroPad = 1;
1872 				else break;
1873 				}
1874 
1875 			if (c == '*')	//  decode field width
1876 				{
1877 				int f = va_arg(arg, int);
1878 				if (f < 0) { f = -f; F.leftJustify = 1; }
1879 				F.fieldWidth = (unsigned int)f;
1880 				c = *++fmt;
1881 				}
1882 			else
1883 				{
1884 				for (; c >= '0' && c <= '9'; c = *++fmt)
1885 					F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
1886 				}
1887 
1888 			if (c == '.')	//  decode precision
1889 				{
1890 				if ((c = *++fmt) == '*')
1891 					{ F.precision = va_arg(arg, unsigned int); c = *++fmt; }
1892 				else for (; c >= '0' && c <= '9'; c = *++fmt)
1893 						F.precision = (10 * F.precision) + (c - '0');
1894 				F.havePrecision = 1;
1895 				}
1896 
1897 			if (F.leftJustify) F.zeroPad = 0;
1898 
1899 			conv:
1900 			switch (c)	//  perform appropriate conversion
1901 				{
1902 				unsigned long n;
1903 				case 'h' :	F.hSize = 1; c = *++fmt; goto conv;
1904 				case 'l' :	// fall through
1905 				case 'L' :	F.lSize = 1; c = *++fmt; goto conv;
1906 				case 'd' :
1907 				case 'i' :	if (F.lSize) n = (unsigned long)va_arg(arg, long);
1908 							else n = (unsigned long)va_arg(arg, int);
1909 							if (F.hSize) n = (short) n;
1910 							if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
1911 							else if (F.forceSign) F.sign = '+';
1912 							goto decimal;
1913 				case 'u' :	if (F.lSize) n = va_arg(arg, unsigned long);
1914 							else n = va_arg(arg, unsigned int);
1915 							if (F.hSize) n = (unsigned short) n;
1916 							F.sign = 0;
1917 							goto decimal;
1918 				decimal:	if (!F.havePrecision)
1919 								{
1920 								if (F.zeroPad)
1921 									{
1922 									F.precision = F.fieldWidth;
1923 									if (F.sign) --F.precision;
1924 									}
1925 								if (F.precision < 1) F.precision = 1;
1926 								}
1927 							if (F.precision > mDNS_VACB_Size - 1)
1928 								F.precision = mDNS_VACB_Size - 1;
1929 							for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
1930 							for (; i < F.precision; i++) *--s = '0';
1931 							if (F.sign) { *--s = F.sign; i++; }
1932 							break;
1933 
1934 				case 'o' :	if (F.lSize) n = va_arg(arg, unsigned long);
1935 							else n = va_arg(arg, unsigned int);
1936 							if (F.hSize) n = (unsigned short) n;
1937 							if (!F.havePrecision)
1938 								{
1939 								if (F.zeroPad) F.precision = F.fieldWidth;
1940 								if (F.precision < 1) F.precision = 1;
1941 								}
1942 							if (F.precision > mDNS_VACB_Size - 1)
1943 								F.precision = mDNS_VACB_Size - 1;
1944 							for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
1945 							if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
1946 							for (; i < F.precision; i++) *--s = '0';
1947 							break;
1948 
1949 				case 'a' :	{
1950 							unsigned char *a = va_arg(arg, unsigned char *);
1951 							if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1952 							else
1953 								{
1954 								s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
1955 								if (F.altForm)
1956 									{
1957 									mDNSAddr *ip = (mDNSAddr*)a;
1958 									switch (ip->type)
1959 										{
1960 										case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
1961 										case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
1962 										default:                F.precision =  0; break;
1963 										}
1964 									}
1965 								switch (F.precision)
1966 									{
1967 									case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
1968 														a[0], a[1], a[2], a[3]); break;
1969 									case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
1970 														a[0], a[1], a[2], a[3], a[4], a[5]); break;
1971 									case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
1972 														"%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1973 														a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
1974 														a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
1975 									default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
1976 														" address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
1977 									}
1978 								}
1979 							}
1980 							break;
1981 
1982 				case 'p' :	F.havePrecision = F.lSize = 1;
1983 							F.precision = 8;
1984 				case 'X' :	digits = "0123456789ABCDEF";
1985 							goto hexadecimal;
1986 				case 'x' :	digits = "0123456789abcdef";
1987 				hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
1988 							else n = va_arg(arg, unsigned int);
1989 							if (F.hSize) n = (unsigned short) n;
1990 							if (!F.havePrecision)
1991 								{
1992 								if (F.zeroPad)
1993 									{
1994 									F.precision = F.fieldWidth;
1995 									if (F.altForm) F.precision -= 2;
1996 									}
1997 								if (F.precision < 1) F.precision = 1;
1998 								}
1999 							if (F.precision > mDNS_VACB_Size - 1)
2000 								F.precision = mDNS_VACB_Size - 1;
2001 							for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
2002 							for (; i < F.precision; i++) *--s = '0';
2003 							if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
2004 							break;
2005 
2006 				case 'c' :	*--s = (char)va_arg(arg, int); i = 1; break;
2007 
2008 				case 's' :	s = va_arg(arg, char *);
2009 							if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
2010 							else switch (F.altForm)
2011 								{
2012 								case 0: i=0;
2013 										if (!F.havePrecision)				// C string
2014 											while(s[i]) i++;
2015 										else
2016 											{
2017 											while ((i < F.precision) && s[i]) i++;
2018 											// Make sure we don't truncate in the middle of a UTF-8 character
2019 											// If last character we got was any kind of UTF-8 multi-byte character,
2020 											// then see if we have to back up.
2021 											// This is not as easy as the similar checks below, because
2022 											// here we can't assume it's safe to examine the *next* byte, so we
2023 											// have to confine ourselves to working only backwards in the string.
2024 											j = i;		// Record where we got to
2025 											// Now, back up until we find first non-continuation-char
2026 											while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
2027 											// Now s[i-1] is the first non-continuation-char
2028 											// and (j-i) is the number of continuation-chars we found
2029 											if (i>0 && (s[i-1] & 0xC0) == 0xC0)	// If we found a start-char
2030 												{
2031 												i--;		// Tentatively eliminate this start-char as well
2032 												// Now (j-i) is the number of characters we're considering eliminating.
2033 												// To be legal UTF-8, the start-char must contain (j-i) one-bits,
2034 												// followed by a zero bit. If we shift it right by (7-(j-i)) bits
2035 												// (with sign extension) then the result has to be 0xFE.
2036 												// If this is right, then we reinstate the tentatively eliminated bytes.
2037 												if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
2038 												}
2039 											}
2040 										break;
2041 								case 1: i = (unsigned char) *s++; break;	// Pascal string
2042 								case 2: {									// DNS label-sequence name
2043 										unsigned char *a = (unsigned char *)s;
2044 										s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
2045 										if (*a == 0) *s++ = '.';	// Special case for root DNS name
2046 										while (*a)
2047 											{
2048 											if (*a > 63)
2049 												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
2050 											if (s + *a >= &mDNS_VACB[254])
2051 												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
2052 											s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a);
2053 											a += 1 + *a;
2054 											}
2055 										i = (mDNSu32)(s - mDNS_VACB);
2056 										s = mDNS_VACB;	// Reset s back to the start of the buffer
2057 										break;
2058 										}
2059 								}
2060 							// Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
2061 							if (F.havePrecision && i > F.precision)
2062 								{ i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2063 							break;
2064 
2065 				case 'n' :	s = va_arg(arg, char *);
2066 							if      (F.hSize) * (short *) s = (short)nwritten;
2067 							else if (F.lSize) * (long  *) s = (long)nwritten;
2068 							else              * (int   *) s = (int)nwritten;
2069 							continue;
2070 
2071 				default:	s = mDNS_VACB;
2072 							i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
2073 
2074 				case '%' :	*sbuffer++ = (char)c;
2075 							if (++nwritten >= buflen) goto exit;
2076 							break;
2077 				}
2078 
2079 			if (i < F.fieldWidth && !F.leftJustify)			// Pad on the left
2080 				do	{
2081 					*sbuffer++ = ' ';
2082 					if (++nwritten >= buflen) goto exit;
2083 					} while (i < --F.fieldWidth);
2084 
2085 			// Make sure we don't truncate in the middle of a UTF-8 character.
2086 			// Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
2087 			// allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
2088 			// so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
2089 			// formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
2090 			if (i > buflen - nwritten)
2091 				{ i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
2092 			for (j=0; j<i; j++) *sbuffer++ = *s++;			// Write the converted result
2093 			nwritten += i;
2094 			if (nwritten >= buflen) goto exit;
2095 
2096 			for (; i < F.fieldWidth; i++)					// Pad on the right
2097 				{
2098 				*sbuffer++ = ' ';
2099 				if (++nwritten >= buflen) goto exit;
2100 				}
2101 			}
2102 		}
2103 	exit:
2104 	*sbuffer++ = 0;
2105 	return(nwritten);
2106 	}
2107 
mDNS_snprintf(char * sbuffer,mDNSu32 buflen,const char * fmt,...)2108 mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
2109 	{
2110 	mDNSu32 length;
2111 
2112 	va_list ptr;
2113 	va_start(ptr,fmt);
2114 	length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
2115 	va_end(ptr);
2116 
2117 	return(length);
2118 	}
2119 
2120 // ***************************************************************************
2121 #if COMPILER_LIKES_PRAGMA_MARK
2122 #pragma mark -
2123 #pragma mark - General Utility Functions
2124 #endif
2125 
2126 #define InitialQuestionInterval (mDNSPlatformOneSecond/2)
2127 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
2128 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
2129 
SetNextQueryTime(mDNS * const m,const DNSQuestion * const q)2130 mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
2131 	{
2132 	if (ActiveQuestion(q))
2133 		if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
2134 			m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
2135 	}
2136 
CacheGroupForName(const mDNS * const m,const mDNSu32 slot,const mDNSu32 namehash,const domainname * const name)2137 mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
2138 	{
2139 	CacheGroup *cg;
2140 	for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
2141 		if (cg->namehash == namehash && SameDomainName(cg->name, name))
2142 			break;
2143 	return(cg);
2144 	}
2145 
CacheGroupForRecord(const mDNS * const m,const mDNSu32 slot,const ResourceRecord * const rr)2146 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
2147 	{
2148 	return(CacheGroupForName(m, slot, rr->namehash, rr->name));
2149 	}
2150 
AddressIsLocalSubnet(mDNS * const m,const mDNSInterfaceID InterfaceID,const mDNSAddr * addr)2151 mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
2152 	{
2153 	NetworkInterfaceInfo *intf;
2154 
2155 	if (addr->type == mDNSAddrType_IPv4)
2156 		{
2157 		if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
2158 		for (intf = m->HostInterfaces; intf; intf = intf->next)
2159 			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2160 				if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
2161 					return(mDNStrue);
2162 		}
2163 
2164 	if (addr->type == mDNSAddrType_IPv6)
2165 		{
2166 		if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
2167 		for (intf = m->HostInterfaces; intf; intf = intf->next)
2168 			if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
2169 				if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
2170 					(((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
2171 					(((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
2172 					(((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
2173 						return(mDNStrue);
2174 		}
2175 
2176 	return(mDNSfalse);
2177 	}
2178 
2179 // Set up a AuthRecord with sensible default values.
2180 // These defaults may be overwritten with new values before mDNS_Register is called
mDNS_SetupResourceRecord(AuthRecord * rr,RData * RDataStorage,mDNSInterfaceID InterfaceID,mDNSu16 rrtype,mDNSu32 ttl,mDNSu8 RecordType,mDNSRecordCallback Callback,void * Context)2181 mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
2182 	mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
2183 	{
2184 	mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2185 	// Don't try to store a TTL bigger than we can represent in platform time units
2186 	if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
2187 		ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
2188 	else if (ttl == 0)		// And Zero TTL is illegal
2189 		ttl = DefaultTTLforRRType(rrtype);
2190 
2191 	// Field Group 1: The actual information pertaining to this resource record
2192 	rr->resrec.RecordType        = RecordType;
2193 	rr->resrec.InterfaceID       = InterfaceID;
2194 	rr->resrec.name              = &rr->namestorage;
2195 	rr->resrec.rrtype            = rrtype;
2196 	rr->resrec.rrclass           = kDNSClass_IN;
2197 	rr->resrec.rroriginalttl     = ttl;
2198 //	rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
2199 //	rr->resrec.rdestimate        = set in mDNS_Register_internal
2200 //	rr->resrec.rdata             = MUST be set by client
2201 
2202 	if (RDataStorage)
2203 		rr->resrec.rdata = RDataStorage;
2204 	else
2205 		{
2206 		rr->resrec.rdata = &rr->rdatastorage;
2207 		rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
2208 		}
2209 
2210 	// Field Group 2: Persistent metadata for Authoritative Records
2211 	rr->Additional1       = mDNSNULL;
2212 	rr->Additional2       = mDNSNULL;
2213 	rr->DependentOn       = mDNSNULL;
2214 	rr->RRSet             = mDNSNULL;
2215 	rr->RecordCallback    = Callback;
2216 	rr->RecordContext     = Context;
2217 
2218 	rr->HostTarget        = mDNSfalse;
2219 	rr->AllowRemoteQuery  = mDNSfalse;
2220 	rr->ForceMCast        = mDNSfalse;
2221 
2222 	// Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
2223 
2224 	rr->namestorage.c[0]  = 0;		// MUST be set by client before calling mDNS_Register()
2225 	}
2226 
2227 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
2228 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
AnswerLocalOnlyQuestionWithResourceRecord(mDNS * const m,DNSQuestion * q,AuthRecord * rr,mDNSBool AddRecord)2229 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
2230 	{
2231 	// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
2232 	if (AddRecord) rr->LocalAnswer = mDNStrue;
2233 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2234 	if (q->QuestionCallback)
2235 		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
2236 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2237 	}
2238 
2239 // When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
2240 // to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
2241 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
2242 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
AnswerLocalQuestions(mDNS * const m,AuthRecord * rr,mDNSBool AddRecord)2243 mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
2244 	{
2245 	if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
2246 
2247 	m->CurrentQuestion = m->LocalOnlyQuestions;
2248 	while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
2249 		{
2250 		DNSQuestion *q = m->CurrentQuestion;
2251 		m->CurrentQuestion = q->next;
2252 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2253 			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);			// MUST NOT dereference q again
2254 		}
2255 
2256 	// If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
2257 	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2258 		{
2259 		m->CurrentQuestion = m->Questions;
2260 		while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2261 			{
2262 			DNSQuestion *q = m->CurrentQuestion;
2263 			m->CurrentQuestion = q->next;
2264 			if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2265 				AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);		// MUST NOT dereference q again
2266 			}
2267 		}
2268 
2269 	m->CurrentQuestion = mDNSNULL;
2270 	}
2271 
2272 // ***************************************************************************
2273 #if COMPILER_LIKES_PRAGMA_MARK
2274 #pragma mark -
2275 #pragma mark - Resource Record Utility Functions
2276 #endif
2277 
2278 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
2279 
2280 #define ResourceRecordIsValidAnswer(RR) ( ((RR)->             resrec.RecordType & kDNSRecordTypeActiveMask)  && \
2281 		((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2282 		((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
2283 		((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask))  )
2284 
2285 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
2286 	(ResourceRecordIsValidAnswer(RR) && \
2287 	((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
2288 
2289 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
2290 #define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
2291 
2292 #define InitialAnnounceCount ((mDNSu8)10)
2293 
2294 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
2295 // This means that because the announce interval is doubled after sending the first packet, the first
2296 // observed on-the-wire inter-packet interval between announcements is actually one second.
2297 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
2298 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
2299 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
2300 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
2301 
2302 #define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
2303 											(X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
2304 											(X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
2305 
2306 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
2307 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
2308 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
2309 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
2310 
2311 #define MaxUnansweredQueries 4
2312 
2313 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
2314 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
2315 // TTL and rdata may differ.
2316 // This is used for cache flush management:
2317 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
2318 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
SameResourceRecordSignature(const ResourceRecord * const r1,const ResourceRecord * const r2)2319 mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
2320 	{
2321 	if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
2322 	if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
2323 	if (r1->InterfaceID &&
2324 		r2->InterfaceID &&
2325 		r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
2326 	return(mDNSBool)(
2327 		r1->rrtype == r2->rrtype &&
2328 		r1->rrclass == r2->rrclass &&
2329 		r1->namehash == r2->namehash &&
2330 		SameDomainName(r1->name, r2->name));
2331 	}
2332 
2333 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
2334 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
2335 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
2336 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
2337 // so a response of any type should match, even if it is not actually the type the client plans to use.
PacketRRMatchesSignature(const CacheRecord * const pktrr,const AuthRecord * const authrr)2338 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
2339 	{
2340 	if (!pktrr)  { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
2341 	if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
2342 	if (pktrr->resrec.InterfaceID &&
2343 		authrr->resrec.InterfaceID &&
2344 		pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
2345 	if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
2346 	return(mDNSBool)(
2347 		pktrr->resrec.rrclass == authrr->resrec.rrclass &&
2348 		pktrr->resrec.namehash == authrr->resrec.namehash &&
2349 		SameDomainName(pktrr->resrec.name, authrr->resrec.name));
2350 	}
2351 
2352 // IdenticalResourceRecord returns true if two resources records have
2353 // the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
IdenticalResourceRecord(const ResourceRecord * const r1,const ResourceRecord * const r2)2354 mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
2355 	{
2356 	if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
2357 	if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
2358 	if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
2359 		return(mDNSfalse);
2360 	return(SameRData(r1, r2));
2361 	}
2362 
2363 // CacheRecord *ks is the CacheRecord from the known answer list in the query.
2364 // This is the information that the requester believes to be correct.
2365 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
2366 // This is the information that we believe to be correct.
2367 // We've already determined that we plan to give this answer on this interface
2368 // (either the record is non-specific, or it is specific to this interface)
2369 // so now we just need to check the name, type, class, rdata and TTL.
ShouldSuppressKnownAnswer(const CacheRecord * const ka,const AuthRecord * const rr)2370 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
2371 	{
2372 	// If RR signature is different, or data is different, then don't suppress our answer
2373 	if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
2374 
2375 	// If the requester's indicated TTL is less than half the real TTL,
2376 	// we need to give our answer before the requester's copy expires.
2377 	// If the requester's indicated TTL is at least half the real TTL,
2378 	// then we can suppress our answer this time.
2379 	// If the requester's indicated TTL is greater than the TTL we believe,
2380 	// then that's okay, and we don't need to do anything about it.
2381 	// (If two responders on the network are offering the same information,
2382 	// that's okay, and if they are offering the information with different TTLs,
2383 	// the one offering the lower TTL should defer to the one offering the higher TTL.)
2384 	return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
2385 	}
2386 
SetNextAnnounceProbeTime(mDNS * const m,const AuthRecord * const rr)2387 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
2388 	{
2389 	if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2390 		{
2391 		//LogMsg("ProbeCount %d Next %ld %s",
2392 		//	rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
2393 		if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2394 			m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
2395 		}
2396 	else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
2397 		{
2398 		if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
2399 			m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
2400 		}
2401 	}
2402 
InitializeLastAPTime(mDNS * const m,AuthRecord * const rr)2403 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
2404 	{
2405 	// To allow us to aggregate probes when a group of services are registered together,
2406 	// the first probe is delayed 1/4 second. This means the common-case behaviour is:
2407 	// 1/4 second wait; probe
2408 	// 1/4 second wait; probe
2409 	// 1/4 second wait; probe
2410 	// 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
2411 
2412 	// If we have no probe suppression time set, or it is in the past, set it now
2413 	if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
2414 		{
2415 		m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
2416 		// If we already have a probe scheduled to go out sooner, then use that time to get better aggregation
2417 		if (m->SuppressProbes - m->NextScheduledProbe >= 0)
2418 			m->SuppressProbes = m->NextScheduledProbe;
2419 		// If we already have a query scheduled to go out sooner, then use that time to get better aggregation
2420 		if (m->SuppressProbes - m->NextScheduledQuery >= 0)
2421 			m->SuppressProbes = m->NextScheduledQuery;
2422 		}
2423 
2424 	// We announce to flush stale data from other caches. It is a reasonable assumption that any
2425 	// old stale copies will probably have the same TTL we're using, so announcing longer than
2426 	// this serves no purpose -- any stale copies of that record will have expired by then anyway.
2427 	rr->AnnounceUntil   = m->timenow + TicksTTL(rr);
2428 	rr->LastAPTime      = m->SuppressProbes - rr->ThisAPInterval;
2429 	// Set LastMCTime to now, to inhibit multicast responses
2430 	// (no need to send additional multicast responses when we're announcing anyway)
2431 	rr->LastMCTime      = m->timenow;
2432 	rr->LastMCInterface = mDNSInterfaceMark;
2433 
2434 	// If this is a record type that's not going to probe, then delay its first announcement so that
2435 	// it will go out synchronized with the first announcement for the other records that *are* probing.
2436 	// This is a minor performance tweak that helps keep groups of related records synchronized together.
2437 	// The addition of "rr->ThisAPInterval / 2" is to make sure that, in the event that any of the probes are
2438 	// delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
2439 	// When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
2440 	// because they will meet the criterion of being at least half-way to their scheduled announcement time.
2441 	if (rr->resrec.RecordType != kDNSRecordTypeUnique)
2442 		rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
2443 
2444 	SetNextAnnounceProbeTime(m, rr);
2445 	}
2446 
2447 #define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
2448 
SetTargetToHostName(mDNS * const m,AuthRecord * const rr)2449 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
2450 	{
2451 	domainname *target = GetRRDomainNameTarget(&rr->resrec);
2452 
2453 	if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
2454 
2455 	if (target && SameDomainName(target, &m->MulticastHostname))
2456 		debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
2457 
2458 	if (target && !SameDomainName(target, &m->MulticastHostname))
2459 		{
2460 		AssignDomainName(target, &m->MulticastHostname);
2461 		SetNewRData(&rr->resrec, mDNSNULL, 0);
2462 
2463 		// If we're in the middle of probing this record, we need to start again,
2464 		// because changing its rdata may change the outcome of the tie-breaker.
2465 		// (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
2466 		rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2467 
2468 		// If we've announced this record, we really should send a goodbye packet for the old rdata before
2469 		// changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
2470 		// so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
2471 		if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
2472 			debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
2473 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2474 
2475 		rr->AnnounceCount  = InitialAnnounceCount;
2476 		rr->RequireGoodbye = mDNSfalse;
2477 		rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2478 		InitializeLastAPTime(m,rr);
2479 		}
2480 	}
2481 
AcknowledgeRecord(mDNS * const m,AuthRecord * const rr)2482 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
2483 	{
2484 	if (!rr->Acknowledged && rr->RecordCallback)
2485 		{
2486 		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2487 		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2488 		rr->Acknowledged = mDNStrue;
2489 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2490 		rr->RecordCallback(m, rr, mStatus_NoError);
2491 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2492 		}
2493 	}
2494 
2495 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
2496 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
2497 	((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
2498 #define RecordIsLocalDuplicate(A,B) \
2499 	((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
2500 
mDNS_Register_internal(mDNS * const m,AuthRecord * const rr)2501 mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
2502 	{
2503 	domainname *target = GetRRDomainNameTarget(&rr->resrec);
2504 	AuthRecord *r;
2505 	AuthRecord **p = &m->ResourceRecords;
2506 	AuthRecord **d = &m->DuplicateRecords;
2507 
2508 	mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
2509 
2510 	if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
2511 		{ LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
2512 
2513 #ifndef UNICAST_DISABLED
2514     if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
2515     	rr->uDNS_info.id = zeroID;
2516     else return uDNS_RegisterRecord(m, rr);
2517 #endif
2518 
2519 	while (*p && *p != rr) p=&(*p)->next;
2520 	while (*d && *d != rr) d=&(*d)->next;
2521 	if (*d || *p)
2522 		{
2523 		LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list",
2524 			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2525 		return(mStatus_AlreadyRegistered);
2526 		}
2527 
2528 	if (rr->DependentOn)
2529 		{
2530 		if (rr->resrec.RecordType == kDNSRecordTypeUnique)
2531 			rr->resrec.RecordType =  kDNSRecordTypeVerified;
2532 		else
2533 			{
2534 			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
2535 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2536 			return(mStatus_Invalid);
2537 			}
2538 		if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
2539 			{
2540 			LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
2541 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
2542 			return(mStatus_Invalid);
2543 			}
2544 		}
2545 
2546 	// If this resource record is referencing a specific interface, make sure it exists
2547 	if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
2548 		{
2549 		NetworkInterfaceInfo *intf;
2550 		for (intf = m->HostInterfaces; intf; intf = intf->next)
2551 			if (intf->InterfaceID == rr->resrec.InterfaceID) break;
2552 		if (!intf)
2553 			{
2554 			debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
2555 			return(mStatus_BadReferenceErr);
2556 			}
2557 		}
2558 
2559 	rr->next = mDNSNULL;
2560 
2561 	// Field Group 1: Persistent metadata for Authoritative Records
2562 //	rr->Additional1       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2563 //	rr->Additional2       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2564 //	rr->DependentOn       = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2565 //	rr->RRSet             = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
2566 //	rr->Callback          = already set in mDNS_SetupResourceRecord
2567 //	rr->Context           = already set in mDNS_SetupResourceRecord
2568 //	rr->RecordType        = already set in mDNS_SetupResourceRecord
2569 //	rr->HostTarget        = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2570 //	rr->AllowRemoteQuery  = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
2571 	// Make sure target is not uninitialized data, or we may crash writing debugging log messages
2572 	if (rr->HostTarget && target) target->c[0] = 0;
2573 
2574 	// Field Group 2: Transient state for Authoritative Records
2575 	rr->Acknowledged      = mDNSfalse;
2576 	rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
2577 	rr->AnnounceCount     = InitialAnnounceCount;
2578 	rr->RequireGoodbye    = mDNSfalse;
2579 	rr->LocalAnswer       = mDNSfalse;
2580 	rr->IncludeInProbe    = mDNSfalse;
2581 	rr->ImmedAnswer       = mDNSNULL;
2582 	rr->ImmedUnicast      = mDNSfalse;
2583 	rr->ImmedAdditional   = mDNSNULL;
2584 	rr->SendRNow          = mDNSNULL;
2585 	rr->v4Requester       = zerov4Addr;
2586 	rr->v6Requester       = zerov6Addr;
2587 	rr->NextResponse      = mDNSNULL;
2588 	rr->NR_AnswerTo       = mDNSNULL;
2589 	rr->NR_AdditionalTo   = mDNSNULL;
2590 	rr->ThisAPInterval    = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
2591 	if (!rr->HostTarget) InitializeLastAPTime(m, rr);
2592 //	rr->AnnounceUntil     = Set for us in InitializeLastAPTime()
2593 //	rr->LastAPTime        = Set for us in InitializeLastAPTime()
2594 //	rr->LastMCTime        = Set for us in InitializeLastAPTime()
2595 //	rr->LastMCInterface   = Set for us in InitializeLastAPTime()
2596 	rr->NewRData          = mDNSNULL;
2597 	rr->newrdlength       = 0;
2598 	rr->UpdateCallback    = mDNSNULL;
2599 	rr->UpdateCredits     = kMaxUpdateCredits;
2600 	rr->NextUpdateCredit  = 0;
2601 	rr->UpdateBlocked     = 0;
2602 
2603 //	rr->resrec.interface         = already set in mDNS_SetupResourceRecord
2604 //	rr->resrec.name->c            = MUST be set by client
2605 //	rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
2606 //	rr->resrec.rrclass           = already set in mDNS_SetupResourceRecord
2607 //	rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
2608 //	rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
2609 
2610 	if (rr->HostTarget)
2611 		SetTargetToHostName(m, rr);	// Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
2612 	else
2613 		{
2614 		rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
2615 		rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
2616 		}
2617 
2618 	if (!ValidateDomainName(rr->resrec.name))
2619 		{ LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2620 
2621 	// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2622 	// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2623 	// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2624 	if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
2625 
2626 	// Don't do this until *after* we've set rr->resrec.rdlength
2627 	if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
2628 		{ LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
2629 
2630 	rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
2631 	rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
2632 
2633 	if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
2634 		{
2635 		// If this is supposed to be unique, make sure we don't have any name conflicts
2636 		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2637 			{
2638 			const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
2639 			for (r = m->ResourceRecords; r; r=r->next)
2640 				{
2641 				const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
2642 				if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
2643 					break;
2644 				}
2645 			if (r)	// If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
2646 				{
2647 				debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2648 				rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2649 				rr->resrec.rroriginalttl = 0;
2650 				rr->ImmedAnswer          = mDNSInterfaceMark;
2651 				m->NextScheduledResponse = m->timenow;
2652 				}
2653 			}
2654 		}
2655 
2656 	// Now that we've finished building our new record, make sure it's not identical to one we already have
2657 	for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
2658 
2659 	if (r)
2660 		{
2661 		debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
2662 		*d = rr;
2663 		// If the previous copy of this record is already verified unique,
2664 		// then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
2665 		// Setting ProbeCount to zero will cause SendQueries() to advance this record to
2666 		// kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
2667 		if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
2668 			rr->ProbeCount = 0;
2669 		}
2670 	else
2671 		{
2672 		debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
2673 		if (!m->NewLocalRecords) m->NewLocalRecords = rr;
2674 		*p = rr;
2675 		}
2676 
2677 	// For records that are not going to probe, acknowledge them right away
2678 	if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
2679 		AcknowledgeRecord(m, rr);
2680 
2681 	return(mStatus_NoError);
2682 	}
2683 
RecordProbeFailure(mDNS * const m,const AuthRecord * const rr)2684 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
2685 	{
2686 	m->ProbeFailTime = m->timenow;
2687 	m->NumFailedProbes++;
2688 	// If we've had fifteen or more probe failures, rate-limit to one every five seconds.
2689 	// If a bunch of hosts have all been configured with the same name, then they'll all
2690 	// conflict and run through the same series of names: name-2, name-3, name-4, etc.,
2691 	// up to name-10. After that they'll start adding random increments in the range 1-100,
2692 	// so they're more likely to branch out in the available namespace and settle on a set of
2693 	// unique names quickly. If after five more tries the host is still conflicting, then we
2694 	// may have a serious problem, so we start rate-limiting so we don't melt down the network.
2695 	if (m->NumFailedProbes >= 15)
2696 		{
2697 		m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
2698 		LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
2699 			m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2700 		}
2701 	}
2702 
CompleteRDataUpdate(mDNS * const m,AuthRecord * const rr)2703 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
2704 	{
2705 	RData *OldRData = rr->resrec.rdata;
2706 	SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);	// Update our rdata
2707 	rr->NewRData = mDNSNULL;									// Clear the NewRData pointer ...
2708 	if (rr->UpdateCallback)
2709 		rr->UpdateCallback(m, rr, OldRData);					// ... and let the client know
2710 	}
2711 
2712 // mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
2713 // mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
2714 // mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
2715 typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
2716 
2717 // NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
2718 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_Deregister_internal(mDNS * const m,AuthRecord * const rr,mDNS_Dereg_type drt)2719 mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
2720 	{
2721 	AuthRecord *r2;
2722 	mDNSu8 RecordType = rr->resrec.RecordType;
2723 	AuthRecord **p = &m->ResourceRecords;	// Find this record in our list of active records
2724 
2725 #ifndef UNICAST_DISABLED
2726     if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
2727 		return uDNS_DeregisterRecord(m, rr);
2728 #endif
2729 
2730 	while (*p && *p != rr) p=&(*p)->next;
2731 
2732 	if (*p)
2733 		{
2734 		// We found our record on the main list. See if there are any duplicates that need special handling.
2735 		if (drt == mDNS_Dereg_conflict)		// If this was a conflict, see that all duplicates get the same treatment
2736 			{
2737 			// Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
2738 			// deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
2739 			for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
2740 			}
2741 		else
2742 			{
2743 			// Before we delete the record (and potentially send a goodbye packet)
2744 			// first see if we have a record on the duplicate list ready to take over from it.
2745 			AuthRecord **d = &m->DuplicateRecords;
2746 			while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
2747 			if (*d)
2748 				{
2749 				AuthRecord *dup = *d;
2750 				debugf("Duplicate record %p taking over from %p %##s (%s)",
2751 					dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2752 				*d        = dup->next;		// Cut replacement record from DuplicateRecords list
2753 				dup->next = rr->next;		// And then...
2754 				rr->next  = dup;			// ... splice it in right after the record we're about to delete
2755 				dup->resrec.RecordType        = rr->resrec.RecordType;
2756 				dup->ProbeCount      = rr->ProbeCount;
2757 				dup->AnnounceCount   = rr->AnnounceCount;
2758 				dup->RequireGoodbye  = rr->RequireGoodbye;
2759 				dup->ImmedAnswer     = rr->ImmedAnswer;
2760 				dup->ImmedUnicast    = rr->ImmedUnicast;
2761 				dup->ImmedAdditional = rr->ImmedAdditional;
2762 				dup->v4Requester     = rr->v4Requester;
2763 				dup->v6Requester     = rr->v6Requester;
2764 				dup->ThisAPInterval  = rr->ThisAPInterval;
2765 				dup->AnnounceUntil   = rr->AnnounceUntil;
2766 				dup->LastAPTime      = rr->LastAPTime;
2767 				dup->LastMCTime      = rr->LastMCTime;
2768 				dup->LastMCInterface = rr->LastMCInterface;
2769 				rr->RequireGoodbye = mDNSfalse;
2770 				}
2771 			}
2772 		}
2773 	else
2774 		{
2775 		// We didn't find our record on the main list; try the DuplicateRecords list instead.
2776 		p = &m->DuplicateRecords;
2777 		while (*p && *p != rr) p=&(*p)->next;
2778 		// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
2779 		if (*p) rr->RequireGoodbye = mDNSfalse;
2780 		if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
2781 			rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2782 		}
2783 
2784 	if (!*p)
2785 		{
2786 		// No need to log an error message if we already know this is a potentially repeated deregistration
2787 		if (drt != mDNS_Dereg_repeat)
2788 			LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
2789 				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2790 		return(mStatus_BadReferenceErr);
2791 		}
2792 
2793 	// If this is a shared record and we've announced it at least once,
2794 	// we need to retract that announcement before we delete the record
2795 	if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
2796 		{
2797 		verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)",
2798 			rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2799 		rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
2800 		rr->resrec.rroriginalttl = 0;
2801 		rr->ImmedAnswer          = mDNSInterfaceMark;
2802 		if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
2803 			m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
2804 		}
2805 	else
2806 		{
2807 		*p = rr->next;					// Cut this record from the list
2808 		// If someone is about to look at this, bump the pointer forward
2809 		if (m->CurrentRecord   == rr) m->CurrentRecord   = rr->next;
2810 		if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
2811 		rr->next = mDNSNULL;
2812 
2813 		if      (RecordType == kDNSRecordTypeUnregistered)
2814 			debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
2815 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2816 		else if (RecordType == kDNSRecordTypeDeregistering)
2817 			debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
2818 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2819 		else
2820 			{
2821 			verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)",
2822 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2823 			rr->resrec.RecordType = kDNSRecordTypeUnregistered;
2824 			}
2825 
2826 		if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
2827 			debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
2828 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2829 
2830 		// If we have an update queued up which never executed, give the client a chance to free that memory
2831 		if (rr->NewRData) CompleteRDataUpdate(m, rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
2832 
2833 		if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
2834 
2835 		// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
2836 		// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
2837 		// In this case the likely client action to the mStatus_MemFree message is to free the memory,
2838 		// so any attempt to touch rr after this is likely to lead to a crash.
2839 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
2840 		if (drt != mDNS_Dereg_conflict)
2841 			{
2842 			if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);			// MUST NOT touch rr after this
2843 			}
2844 		else
2845 			{
2846 			RecordProbeFailure(m, rr);
2847 			if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);	// MUST NOT touch rr after this
2848 			// Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
2849 			// Note that with all the client callbacks going on, by the time we get here all the
2850 			// records we marked may have been explicitly deregistered by the client anyway.
2851 			r2 = m->DuplicateRecords;
2852 			while (r2)
2853 				{
2854 				if (r2->ProbeCount != 0xFF) r2 = r2->next;
2855 				else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
2856 				}
2857 			}
2858 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
2859 		}
2860 	return(mStatus_NoError);
2861 	}
2862 
2863 // ***************************************************************************
2864 #if COMPILER_LIKES_PRAGMA_MARK
2865 #pragma mark -
2866 #pragma mark -
2867 #pragma mark - Packet Sending Functions
2868 #endif
2869 
AddRecordToResponseList(AuthRecord *** nrpp,AuthRecord * rr,AuthRecord * add)2870 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
2871 	{
2872 	if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
2873 		{
2874 		**nrpp = rr;
2875 		// NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
2876 		// If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
2877 		// The referenced record will definitely be acceptable (by recursive application of this rule)
2878 		if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
2879 		rr->NR_AdditionalTo = add;
2880 		*nrpp = &rr->NextResponse;
2881 		}
2882 	debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2883 	}
2884 
AddAdditionalsToResponseList(mDNS * const m,AuthRecord * ResponseRecords,AuthRecord *** nrpp,const mDNSInterfaceID InterfaceID)2885 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
2886 	{
2887 	AuthRecord  *rr, *rr2;
2888 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)			// For each record we plan to put
2889 		{
2890 		// (Note: This is an "if", not a "while". If we add a record, we'll find it again
2891 		// later in the "for" loop, and we will follow further "additional" links then.)
2892 		if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
2893 			AddRecordToResponseList(nrpp, rr->Additional1, rr);
2894 
2895 		if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
2896 			AddRecordToResponseList(nrpp, rr->Additional2, rr);
2897 
2898 		// For SRV records, automatically add the Address record(s) for the target host
2899 		if (rr->resrec.rrtype == kDNSType_SRV)
2900 			for (rr2=m->ResourceRecords; rr2; rr2=rr2->next)					// Scan list of resource records
2901 				if (RRTypeIsAddressType(rr2->resrec.rrtype) &&					// For all address records (A/AAAA) ...
2902 					ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&	// ... which are valid for answer ...
2903 					rr->resrec.rdatahash == rr2->resrec.namehash &&			// ... whose name is the name of the SRV target
2904 					SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
2905 					AddRecordToResponseList(nrpp, rr2, rr);
2906 		}
2907 	}
2908 
SendDelayedUnicastResponse(mDNS * const m,const mDNSAddr * const dest,const mDNSInterfaceID InterfaceID)2909 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
2910 	{
2911 	AuthRecord *rr;
2912 	AuthRecord  *ResponseRecords = mDNSNULL;
2913 	AuthRecord **nrp             = &ResponseRecords;
2914 
2915 	// Make a list of all our records that need to be unicast to this destination
2916 	for (rr = m->ResourceRecords; rr; rr=rr->next)
2917 		{
2918 		// If we find we can no longer unicast this answer, clear ImmedUnicast
2919 		if (rr->ImmedAnswer == mDNSInterfaceMark               ||
2920 			mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
2921 			mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr)  )
2922 			rr->ImmedUnicast = mDNSfalse;
2923 
2924 		if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
2925 			if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
2926 				(dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
2927 				{
2928 				rr->ImmedAnswer  = mDNSNULL;				// Clear the state fields
2929 				rr->ImmedUnicast = mDNSfalse;
2930 				rr->v4Requester  = zerov4Addr;
2931 				rr->v6Requester  = zerov6Addr;
2932 				if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse)	// rr->NR_AnswerTo
2933 					{ rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
2934 				}
2935 		}
2936 
2937 	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
2938 
2939 	while (ResponseRecords)
2940 		{
2941 		mDNSu8 *responseptr = m->omsg.data;
2942 		mDNSu8 *newptr;
2943 		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
2944 
2945 		// Put answers in the packet
2946 		while (ResponseRecords && ResponseRecords->NR_AnswerTo)
2947 			{
2948 			rr = ResponseRecords;
2949 			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2950 				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2951 			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2952 			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2953 			if (!newptr && m->omsg.h.numAnswers) break;	// If packet full, send it now
2954 			if (newptr) responseptr = newptr;
2955 			ResponseRecords = rr->NextResponse;
2956 			rr->NextResponse    = mDNSNULL;
2957 			rr->NR_AnswerTo     = mDNSNULL;
2958 			rr->NR_AdditionalTo = mDNSNULL;
2959 			rr->RequireGoodbye  = mDNStrue;
2960 			}
2961 
2962 		// Add additionals, if there's space
2963 		while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
2964 			{
2965 			rr = ResponseRecords;
2966 			if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2967 				rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
2968 			newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
2969 			rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
2970 
2971 			if (newptr) responseptr = newptr;
2972 			if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
2973 			else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
2974 			ResponseRecords = rr->NextResponse;
2975 			rr->NextResponse    = mDNSNULL;
2976 			rr->NR_AnswerTo     = mDNSNULL;
2977 			rr->NR_AdditionalTo = mDNSNULL;
2978 			}
2979 
2980 		if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
2981 		}
2982 	}
2983 
CompleteDeregistration(mDNS * const m,AuthRecord * rr)2984 mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
2985 	{
2986 	// Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
2987 	// that it should go ahead and immediately dispose of this registration
2988 	rr->resrec.RecordType = kDNSRecordTypeShared;
2989 	rr->RequireGoodbye    = mDNSfalse;
2990 	mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);		// Don't touch rr after this
2991 	}
2992 
2993 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
2994 // the record list and/or question list.
2995 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
DiscardDeregistrations(mDNS * const m)2996 mDNSlocal void DiscardDeregistrations(mDNS *const m)
2997 	{
2998 	if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set");
2999 	m->CurrentRecord = m->ResourceRecords;
3000 
3001 	while (m->CurrentRecord)
3002 		{
3003 		AuthRecord *rr = m->CurrentRecord;
3004 		if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3005 			CompleteDeregistration(m, rr);		// Don't touch rr after this
3006 		else
3007 			m->CurrentRecord = rr->next;
3008 		}
3009 	}
3010 
GrantUpdateCredit(AuthRecord * rr)3011 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
3012 	{
3013 	if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
3014 	else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
3015 	}
3016 
3017 // Note about acceleration of announcements to facilitate automatic coalescing of
3018 // multiple independent threads of announcements into a single synchronized thread:
3019 // The announcements in the packet may be at different stages of maturity;
3020 // One-second interval, two-second interval, four-second interval, and so on.
3021 // After we've put in all the announcements that are due, we then consider
3022 // whether there are other nearly-due announcements that are worth accelerating.
3023 // To be eligible for acceleration, a record MUST NOT be older (further along
3024 // its timeline) than the most mature record we've already put in the packet.
3025 // In other words, younger records can have their timelines accelerated to catch up
3026 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
3027 // Older records cannot have their timelines accelerated; this would just widen
3028 // the gap between them and their younger bretheren and get them even more out of sync.
3029 
3030 // NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
3031 // the record list and/or question list.
3032 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
SendResponses(mDNS * const m)3033 mDNSlocal void SendResponses(mDNS *const m)
3034 	{
3035 	int pktcount = 0;
3036 	AuthRecord *rr, *r2;
3037 	mDNSs32 maxExistingAnnounceInterval = 0;
3038 	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3039 
3040 	m->NextScheduledResponse = m->timenow + 0x78000000;
3041 
3042 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3043 		if (rr->ImmedUnicast)
3044 			{
3045 			mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
3046 			mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
3047 			v4.ip.v4 = rr->v4Requester;
3048 			v6.ip.v6 = rr->v6Requester;
3049 			if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
3050 			if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
3051 			if (rr->ImmedUnicast)
3052 				{
3053 				LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
3054 				rr->ImmedUnicast = mDNSfalse;
3055 				}
3056 			}
3057 
3058 	// ***
3059 	// *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
3060 	// ***
3061 
3062 	// Run through our list of records, and decide which ones we're going to announce on all interfaces
3063 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3064 		{
3065 		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
3066 		if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
3067 			{
3068 			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
3069 			if (maxExistingAnnounceInterval < rr->ThisAPInterval)
3070 				maxExistingAnnounceInterval = rr->ThisAPInterval;
3071 			if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
3072 			}
3073 		}
3074 
3075 	// Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
3076 	// Eligible records that are more than half-way to their announcement time are accelerated
3077 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3078 		if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
3079 			(rr->ThisAPInterval <= maxExistingAnnounceInterval &&
3080 			TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
3081 			ResourceRecordIsValidAnswer(rr)))
3082 			rr->ImmedAnswer = mDNSInterfaceMark;		// Send on all interfaces
3083 
3084 	// When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
3085 	// NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
3086 	// which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
3087 	// then all that means is that it won't get sent -- which would not be the end of the world.
3088 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3089 		if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
3090 			for (r2=m->ResourceRecords; r2; r2=r2->next)				// Scan list of resource records
3091 				if (RRTypeIsAddressType(r2->resrec.rrtype) &&			// For all address records (A/AAAA) ...
3092 					ResourceRecordIsValidAnswer(r2) &&					// ... which are valid for answer ...
3093 					rr->LastMCTime - r2->LastMCTime >= 0 &&				// ... which we have not sent recently ...
3094 					rr->resrec.rdatahash == r2->resrec.namehash &&		// ... whose name is the name of the SRV target
3095 					SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
3096 					(rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
3097 					r2->ImmedAdditional = r2->resrec.InterfaceID;		// ... then mark this address record for sending too
3098 
3099 	// If there's a record which is supposed to be unique that we're going to send, then make sure that we give
3100 	// the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
3101 	// then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
3102 	// record, then other RRSet members that have not been sent recently will get flushed out of client caches.
3103 	// -- 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
3104 	// -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
3105 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3106 		if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3107 			{
3108 			if (rr->ImmedAnswer)			// If we're sending this as answer, see that its whole RRSet is similarly marked
3109 				{
3110 				for (r2 = m->ResourceRecords; r2; r2=r2->next)
3111 					if (ResourceRecordIsValidAnswer(r2))
3112 						if (r2->ImmedAnswer != mDNSInterfaceMark &&
3113 							r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3114 							r2->ImmedAnswer = rr->ImmedAnswer;
3115 				}
3116 			else if (rr->ImmedAdditional)	// If we're sending this as additional, see that its whole RRSet is similarly marked
3117 				{
3118 				for (r2 = m->ResourceRecords; r2; r2=r2->next)
3119 					if (ResourceRecordIsValidAnswer(r2))
3120 						if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
3121 							r2->ImmedAdditional = rr->ImmedAdditional;
3122 				}
3123 			}
3124 
3125 	// Now set SendRNow state appropriately
3126 	for (rr = m->ResourceRecords; rr; rr=rr->next)
3127 		{
3128 		if (rr->ImmedAnswer == mDNSInterfaceMark)		// Sending this record on all appropriate interfaces
3129 			{
3130 			rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3131 			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional if sending as answer
3132 			rr->LastMCTime      = m->timenow;
3133 			rr->LastMCInterface = rr->ImmedAnswer;
3134 			// If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
3135 			if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
3136 				{
3137 				rr->AnnounceCount--;
3138 				rr->ThisAPInterval *= 2;
3139 				rr->LastAPTime = m->timenow;
3140 				if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
3141 				debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
3142 				}
3143 			}
3144 		else if (rr->ImmedAnswer)						// Else, just respond to a single query on single interface:
3145 			{
3146 			rr->SendRNow        = rr->ImmedAnswer;		// Just respond on that interface
3147 			rr->ImmedAdditional = mDNSNULL;				// No need to send as additional too
3148 			rr->LastMCTime      = m->timenow;
3149 			rr->LastMCInterface = rr->ImmedAnswer;
3150 			}
3151 		SetNextAnnounceProbeTime(m, rr);
3152 		//if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
3153 		}
3154 
3155 	// ***
3156 	// *** 2. Loop through interface list, sending records as appropriate
3157 	// ***
3158 
3159 	while (intf)
3160 		{
3161 		int numDereg    = 0;
3162 		int numAnnounce = 0;
3163 		int numAnswer   = 0;
3164 		mDNSu8 *responseptr = m->omsg.data;
3165 		mDNSu8 *newptr;
3166 		InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
3167 
3168 		// First Pass. Look for:
3169 		// 1. Deregistering records that need to send their goodbye packet
3170 		// 2. Updated records that need to retract their old data
3171 		// 3. Answers and announcements we need to send
3172 		// In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
3173 		// send this packet and then try again.
3174 		// If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
3175 		// because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
3176 		for (rr = m->ResourceRecords; rr; rr=rr->next)
3177 			if (rr->SendRNow == intf->InterfaceID)
3178 				{
3179 				if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3180 					{
3181 					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3182 					if (!newptr && m->omsg.h.numAnswers) break;
3183 					numDereg++;
3184 					responseptr = newptr;
3185 					}
3186 				else if (rr->NewRData && !m->SleepState)					// If we have new data for this record
3187 					{
3188 					RData *OldRData     = rr->resrec.rdata;
3189 					mDNSu16 oldrdlength = rr->resrec.rdlength;
3190 					// See if we should send a courtesy "goodbye" for the old data before we replace it.
3191 					if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
3192 						{
3193 						newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
3194 						if (!newptr && m->omsg.h.numAnswers) break;
3195 						numDereg++;
3196 						responseptr = newptr;
3197 						rr->RequireGoodbye = mDNSfalse;
3198 						}
3199 					// Now try to see if we can fit the update in the same packet (not fatal if we can't)
3200 					SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
3201 					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3202 						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
3203 					newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
3204 					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
3205 					if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
3206 					SetNewRData(&rr->resrec, OldRData, oldrdlength);
3207 					}
3208 				else
3209 					{
3210 					if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3211 						rr->resrec.rrclass |= kDNSClass_UniqueRRSet;		// Temporarily set the cache flush bit so PutResourceRecord will set it
3212 					newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
3213 					rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;			// Make sure to clear cache flush bit back to normal state
3214 					if (!newptr && m->omsg.h.numAnswers) break;
3215 					rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
3216 					if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
3217 					responseptr = newptr;
3218 					}
3219 				// If sending on all interfaces, go to next interface; else we're finished now
3220 				if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
3221 					rr->SendRNow = GetNextActiveInterfaceID(intf);
3222 				else
3223 					rr->SendRNow = mDNSNULL;
3224 				}
3225 
3226 		// Second Pass. Add additional records, if there's space.
3227 		newptr = responseptr;
3228 		for (rr = m->ResourceRecords; rr; rr=rr->next)
3229 			if (rr->ImmedAdditional == intf->InterfaceID)
3230 				if (ResourceRecordIsValidAnswer(rr))
3231 					{
3232 					// If we have at least one answer already in the packet, then plan to add additionals too
3233 					mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
3234 
3235 					// If we're not planning to send any additionals, but this record is a unique one, then
3236 					// make sure we haven't already sent any other members of its RRSet -- if we have, then they
3237 					// will have had the cache flush bit set, so now we need to finish the job and send the rest.
3238 					if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
3239 						{
3240 						const AuthRecord *a;
3241 						for (a = m->ResourceRecords; a; a=a->next)
3242 							if (a->LastMCTime      == m->timenow &&
3243 								a->LastMCInterface == intf->InterfaceID &&
3244 								SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
3245 						}
3246 					if (!SendAdditional)					// If we don't want to send this after all,
3247 						rr->ImmedAdditional = mDNSNULL;		// then cancel its ImmedAdditional field
3248 					else if (newptr)						// Else, try to add it if we can
3249 						{
3250 						if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
3251 							rr->resrec.rrclass |= kDNSClass_UniqueRRSet;	// Temporarily set the cache flush bit so PutResourceRecord will set it
3252 						newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
3253 						rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;		// Make sure to clear cache flush bit back to normal state
3254 						if (newptr)
3255 							{
3256 							responseptr = newptr;
3257 							rr->ImmedAdditional = mDNSNULL;
3258 							rr->RequireGoodbye = mDNStrue;
3259 							// If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
3260 							// This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
3261 							// when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
3262 							// all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
3263 							rr->LastMCTime      = m->timenow;
3264 							rr->LastMCInterface = intf->InterfaceID;
3265 							}
3266 						}
3267 					}
3268 
3269 		if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
3270 			{
3271 			debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
3272 				numDereg,                  numDereg                  == 1 ? "" : "s",
3273 				numAnnounce,               numAnnounce               == 1 ? "" : "s",
3274 				numAnswer,                 numAnswer                 == 1 ? "" : "s",
3275 				m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
3276 			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3277 			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3278 			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3279 			if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
3280 			// There might be more things to send on this interface, so go around one more time and try again.
3281 			}
3282 		else	// Nothing more to send on this interface; go to next
3283 			{
3284 			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3285 			#if MDNS_DEBUGMSGS && 0
3286 			const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
3287 			debugf(msg, intf, next);
3288 			#endif
3289 			intf = next;
3290 			}
3291 		}
3292 
3293 	// ***
3294 	// *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
3295 	// ***
3296 
3297 	if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set");
3298 	m->CurrentRecord = m->ResourceRecords;
3299 	while (m->CurrentRecord)
3300 		{
3301 		rr = m->CurrentRecord;
3302 		m->CurrentRecord = rr->next;
3303 
3304 		if (rr->SendRNow)
3305 			{
3306 			if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
3307 				LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr));
3308 			rr->SendRNow = mDNSNULL;
3309 			}
3310 
3311 		if (rr->ImmedAnswer)
3312 			{
3313 			if (rr->NewRData) CompleteRDataUpdate(m,rr);	// Update our rdata, clear the NewRData pointer, and return memory to the client
3314 
3315 			if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
3316 				CompleteDeregistration(m, rr);		// Don't touch rr after this
3317 			else
3318 				{
3319 				rr->ImmedAnswer  = mDNSNULL;
3320 				rr->ImmedUnicast = mDNSfalse;
3321 				rr->v4Requester  = zerov4Addr;
3322 				rr->v6Requester  = zerov6Addr;
3323 				}
3324 			}
3325 		}
3326 	verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
3327 	}
3328 
3329 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
3330 // so we want to be lazy about how frequently we do it.
3331 // 1. If a cache record is currently referenced by *no* active questions,
3332 //    then we don't mind expiring it up to a minute late (who will know?)
3333 // 2. Else, if a cache record is due for some of its final expiration queries,
3334 //    we'll allow them to be late by up to 2% of the TTL
3335 // 3. Else, if a cache record has completed all its final expiration queries without success,
3336 //    and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
3337 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
3338 //    so allow at most 1/10 second lateness
3339 #define CacheCheckGracePeriod(RR) (                                                   \
3340 	((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
3341 	((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
3342 	((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
3343 	((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : (mDNSPlatformOneSecond/10))
3344 
3345 // Note: MUST call SetNextCacheCheckTime any time we change:
3346 // rr->TimeRcvd
3347 // rr->resrec.rroriginalttl
3348 // rr->UnansweredQueries
3349 // rr->CRActiveQuestion
3350 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
3351 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
SetNextCacheCheckTime(mDNS * const m,CacheRecord * const rr)3352 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
3353 	{
3354 	rr->NextRequiredQuery = RRExpireTime(rr);
3355 
3356 	// If we have an active question, then see if we want to schedule a refresher query for this record.
3357 	// Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
3358 	if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3359 		{
3360 		rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
3361 		rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
3362 		verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
3363 			rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
3364 			(rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
3365 		}
3366 
3367 	if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
3368 		m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
3369 
3370 	if (rr->DelayDelivery)
3371 		if (m->NextCacheCheck - rr->DelayDelivery > 0)
3372 			m->NextCacheCheck = rr->DelayDelivery;
3373 	}
3374 
3375 #define kMinimumReconfirmTime                     ((mDNSu32)mDNSPlatformOneSecond *  5)
3376 #define kDefaultReconfirmTimeForWake              ((mDNSu32)mDNSPlatformOneSecond *  5)
3377 #define kDefaultReconfirmTimeForNoAnswer          ((mDNSu32)mDNSPlatformOneSecond * 15)
3378 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
3379 
mDNS_Reconfirm_internal(mDNS * const m,CacheRecord * const rr,mDNSu32 interval)3380 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
3381 	{
3382 	if (interval < kMinimumReconfirmTime)
3383 		interval = kMinimumReconfirmTime;
3384 	if (interval > 0x10000000)	// Make sure interval doesn't overflow when we multiply by four below
3385 		interval = 0x10000000;
3386 
3387 	// If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
3388 	if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
3389 		{
3390 		// Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
3391 		// For all the reconfirmations in a given batch, we want to use the same random value
3392 		// so that the reconfirmation questions can be grouped into a single query packet
3393 		if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
3394 		interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
3395 		rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
3396 		rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
3397 		SetNextCacheCheckTime(m, rr);
3398 		}
3399 	debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
3400 	return(mStatus_NoError);
3401 	}
3402 
3403 #define MaxQuestionInterval         (3600 * mDNSPlatformOneSecond)
3404 
3405 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
3406 // It also appends to the list of known answer records that need to be included,
3407 // and updates the forcast for the size of the known answer section.
BuildQuestion(mDNS * const m,DNSMessage * query,mDNSu8 ** queryptr,DNSQuestion * q,CacheRecord *** kalistptrptr,mDNSu32 * answerforecast)3408 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
3409 	CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
3410 	{
3411 	mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
3412 	mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3413 	const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
3414 	mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
3415 	if (!newptr)
3416 		{
3417 		debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c);
3418 		return(mDNSfalse);
3419 		}
3420 	else if (newptr + *answerforecast >= limit)
3421 		{
3422 		verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d",
3423 			q->qname.c, newptr + *answerforecast - query->data);
3424 		query->h.numQuestions--;
3425 		return(mDNSfalse);
3426 		}
3427 	else
3428 		{
3429 		mDNSu32 forecast = *answerforecast;
3430 		const mDNSu32 slot = HashSlot(&q->qname);
3431 		CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3432 		CacheRecord *rr;
3433 		CacheRecord **ka = *kalistptrptr;	// Make a working copy of the pointer we're going to update
3434 
3435 		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3436 			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3437 				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not already in the known answer list
3438 				rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3439 				ResourceRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3440 				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >				// and its half-way-to-expiry time is at least 1 second away
3441 												mDNSPlatformOneSecond)		// (also ensures we never include goodbye records with TTL=1)
3442 				{
3443 				*ka = rr;	// Link this record into our known answer chain
3444 				ka = &rr->NextInKAList;
3445 				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3446 				forecast += 12 + rr->resrec.rdestimate;
3447 				// If we're trying to put more than one question in this packet, and it doesn't fit
3448 				// then undo that last question and try again next time
3449 				if (query->h.numQuestions > 1 && newptr + forecast >= limit)
3450 					{
3451 					debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
3452 						q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
3453 					query->h.numQuestions--;
3454 					ka = *kalistptrptr;		// Go back to where we started and retract these answer records
3455 					while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3456 					return(mDNSfalse);		// Return false, so we'll try again in the next packet
3457 					}
3458 				}
3459 
3460 		// Traffic reduction:
3461 		// If we already have at least one unique answer in the cache,
3462 		// OR we have so many shared answers that the KA list is too big to fit in one packet
3463 		// The we suppress queries number 3 and 5:
3464 		// Query 1 (immediately;      ThisQInterval =  1 sec; request unicast replies)
3465 		// Query 2 (after  1 second;  ThisQInterval =  2 sec; send normally)
3466 		// Query 3 (after  2 seconds; ThisQInterval =  4 sec; may suppress)
3467 		// Query 4 (after  4 seconds; ThisQInterval =  8 sec; send normally)
3468 		// Query 5 (after  8 seconds; ThisQInterval = 16 sec; may suppress)
3469 		// Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally)
3470 		if (q->UniqueAnswers || newptr + forecast >= limit)
3471 			if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32)
3472 				{
3473 				query->h.numQuestions--;
3474 				ka = *kalistptrptr;		// Go back to where we started and retract these answer records
3475 				while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
3476 				return(mDNStrue);		// Return true: pretend we succeeded, even though we actually suppressed this question
3477 				}
3478 
3479 		// Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
3480 		*queryptr        = newptr;				// Update the packet pointer
3481 		*answerforecast  = forecast;			// Update the forecast
3482 		*kalistptrptr    = ka;					// Update the known answer list pointer
3483 		if (ucast) m->ExpectUnicastResponse = m->timenow;
3484 
3485 		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// For every resource record in our cache,
3486 			if (rr->resrec.InterfaceID == q->SendQNow &&					// received on this interface
3487 				rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&	// which is not in the known answer list
3488 				ResourceRecordAnswersQuestion(&rr->resrec, q))				// which answers our question
3489 					{
3490 					rr->UnansweredQueries++;								// indicate that we're expecting a response
3491 					rr->LastUnansweredTime = m->timenow;
3492 					SetNextCacheCheckTime(m, rr);
3493 					}
3494 
3495 		return(mDNStrue);
3496 		}
3497 	}
3498 
ReconfirmAntecedents(mDNS * const m,DNSQuestion * q)3499 mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
3500 	{
3501 	mDNSu32 slot;
3502 	CacheGroup *cg;
3503 	CacheRecord *rr;
3504 	domainname *target;
3505 	FORALL_CACHERECORDS(slot, cg, rr)
3506 		if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname))
3507 			mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
3508 	}
3509 
3510 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 time)3511 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
3512 	{
3513 	int i;
3514 	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3515 	}
3516 
ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 time,mDNSInterfaceID InterfaceID)3517 mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
3518 	{
3519 	int i;
3520 	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
3521 	}
3522 
SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize],const NetworkInterfaceInfo * const intf)3523 mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
3524 	{
3525 	int i;
3526 	mDNSBool v4 = !intf->IPv4Available;		// If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
3527 	mDNSBool v6 = !intf->IPv6Available;		// If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
3528 	for (i=0; i<DupSuppressInfoSize; i++)
3529 		if (ds[i].InterfaceID == intf->InterfaceID)
3530 			{
3531 			if      (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
3532 			else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
3533 			if (v4 && v6) return(mDNStrue);
3534 			}
3535 	return(mDNSfalse);
3536 	}
3537 
RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize],mDNSs32 Time,mDNSInterfaceID InterfaceID,mDNSs32 Type)3538 mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
3539 	{
3540 	int i, j;
3541 
3542 	// See if we have this one in our list somewhere already
3543 	for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
3544 
3545 	// If not, find a slot we can re-use
3546 	if (i >= DupSuppressInfoSize)
3547 		{
3548 		i = 0;
3549 		for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
3550 			if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
3551 				i = j;
3552 		}
3553 
3554 	// Record the info about this query we saw
3555 	ds[i].Time        = Time;
3556 	ds[i].InterfaceID = InterfaceID;
3557 	ds[i].Type        = Type;
3558 
3559 	return(i);
3560 	}
3561 
AccelerateThisQuery(mDNS * const m,DNSQuestion * q)3562 mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
3563 	{
3564 	// If more than 90% of the way to the query time, we should unconditionally accelerate it
3565 	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
3566 		return(mDNStrue);
3567 
3568 	// If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
3569 	if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
3570 		{
3571 		// We forecast: qname (n) type (2) class (2)
3572 		mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
3573 		const mDNSu32 slot = HashSlot(&q->qname);
3574 		CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3575 		CacheRecord *rr;
3576 		for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)				// If we have a resource record in our cache,
3577 			if (rr->resrec.rdlength <= SmallRecordLimit &&					// which is small enough to sensibly fit in the packet
3578 				ResourceRecordAnswersQuestion(&rr->resrec, q) &&			// which answers our question
3579 				rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 &&			// and it is less than half-way to expiry
3580 				rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
3581 				{
3582 				// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3583 				forecast += 12 + rr->resrec.rdestimate;
3584 				if (forecast >= 512) return(mDNSfalse);	// If this would add 512 bytes or more to the packet, don't accelerate
3585 				}
3586 		return(mDNStrue);
3587 		}
3588 
3589 	return(mDNSfalse);
3590 	}
3591 
3592 // How Standard Queries are generated:
3593 // 1. The Question Section contains the question
3594 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
3595 
3596 // How Probe Queries are generated:
3597 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
3598 // if some other host is already using *any* records with this name, we want to know about it.
3599 // 2. The Authority Section contains the proposed values we intend to use for one or more
3600 // of our records with that name (analogous to the Update section of DNS Update packets)
3601 // because if some other host is probing at the same time, we each want to know what the other is
3602 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
3603 
SendQueries(mDNS * const m)3604 mDNSlocal void SendQueries(mDNS *const m)
3605 	{
3606 	mDNSu32 slot;
3607 	CacheGroup *cg;
3608 	CacheRecord *cr;
3609 	AuthRecord *ar;
3610 	int pktcount = 0;
3611 	DNSQuestion *q;
3612 	// For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
3613 	mDNSs32 maxExistingQuestionInterval = 0;
3614 	const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
3615 	CacheRecord *KnownAnswerList = mDNSNULL;
3616 
3617 	// 1. If time for a query, work out what we need to do
3618 	if (m->timenow - m->NextScheduledQuery >= 0)
3619 		{
3620 		CacheRecord *rr;
3621 		m->NextScheduledQuery = m->timenow + 0x78000000;
3622 
3623 		// We're expecting to send a query anyway, so see if any expiring cache records are close enough
3624 		// to their NextRequiredQuery to be worth batching them together with this one
3625 		FORALL_CACHERECORDS(slot, cg, rr)
3626 			if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3627 				if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
3628 					{
3629 					q = rr->CRActiveQuestion;
3630 					ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
3631 					if (q->Target.type) q->SendQNow = mDNSInterfaceMark;	// If unicast query, mark it
3632 					else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
3633 					else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
3634 					}
3635 
3636 		// Scan our list of questions to see which *unicast* queries need to be sent
3637 		for (q = m->Questions; q; q=q->next)
3638 			if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
3639 				{
3640 				mDNSu8       *qptr        = m->omsg.data;
3641 				const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
3642 				InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
3643 				qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
3644 				mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
3645 				q->ThisQInterval   *= 2;
3646 				if (q->ThisQInterval > MaxQuestionInterval)
3647 					q->ThisQInterval = MaxQuestionInterval;
3648 				q->LastQTime        = m->timenow;
3649 				q->LastQTxTime      = m->timenow;
3650 				q->RecentAnswerPkts = 0;
3651 				q->SendQNow         = mDNSNULL;
3652 				m->ExpectUnicastResponse = m->timenow;
3653 				}
3654 
3655 		// Scan our list of questions to see which *multicast* queries we're definitely going to send
3656 		for (q = m->Questions; q; q=q->next)
3657 			if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
3658 				{
3659 				q->SendQNow = mDNSInterfaceMark;		// Mark this question for sending on all interfaces
3660 				if (maxExistingQuestionInterval < q->ThisQInterval)
3661 					maxExistingQuestionInterval = q->ThisQInterval;
3662 				}
3663 
3664 		// Scan our list of questions
3665 		// (a) to see if there are any more that are worth accelerating, and
3666 		// (b) to update the state variables for *all* the questions we're going to send
3667 		for (q = m->Questions; q; q=q->next)
3668 			{
3669 			if (q->SendQNow ||
3670 				(!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
3671 				{
3672 				// If at least halfway to next query time, advance to next interval
3673 				// If less than halfway to next query time, then
3674 				// treat this as logically a repeat of the last transmission, without advancing the interval
3675 				if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
3676 					{
3677 					q->SendQNow = mDNSInterfaceMark;	// Mark this question for sending on all interfaces
3678 					q->ThisQInterval *= 2;
3679 					if (q->ThisQInterval > MaxQuestionInterval)
3680 						q->ThisQInterval = MaxQuestionInterval;
3681 					else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8)
3682 						{
3683 						debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
3684 							q->qname.c, DNSTypeName(q->qtype));
3685 						ReconfirmAntecedents(m, q);		// Sending third query, and no answers yet; time to begin doubting the source
3686 						}
3687 					}
3688 
3689 				// Mark for sending. (If no active interfaces, then don't even try.)
3690 				q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
3691 				if (q->SendOnAll)
3692 					{
3693 					q->SendQNow  = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
3694 					q->LastQTime = m->timenow;
3695 					}
3696 
3697 				// If we recorded a duplicate suppression for this question less than half an interval ago,
3698 				// then we consider it recent enough that we don't need to do an identical query ourselves.
3699 				ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
3700 
3701 				q->LastQTxTime      = m->timenow;
3702 				q->RecentAnswerPkts = 0;
3703 				if (q->RequestUnicast) q->RequestUnicast--;
3704 				}
3705 			// For all questions (not just the ones we're sending) check what the next scheduled event will be
3706 			SetNextQueryTime(m,q);
3707 			}
3708 		}
3709 
3710 	// 2. Scan our authoritative RR list to see what probes we might need to send
3711 	if (m->timenow - m->NextScheduledProbe >= 0)
3712 		{
3713 		m->NextScheduledProbe = m->timenow + 0x78000000;
3714 
3715 		if (m->CurrentRecord) LogMsg("SendQueries:   ERROR m->CurrentRecord already set");
3716 		m->CurrentRecord = m->ResourceRecords;
3717 		while (m->CurrentRecord)
3718 			{
3719 			AuthRecord *rr = m->CurrentRecord;
3720 			m->CurrentRecord = rr->next;
3721 			if (rr->resrec.RecordType == kDNSRecordTypeUnique)			// For all records that are still probing...
3722 				{
3723 				// 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
3724 				if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
3725 					{
3726 					SetNextAnnounceProbeTime(m, rr);
3727 					}
3728 				// 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
3729 				else if (rr->ProbeCount)
3730 					{
3731 					// Mark for sending. (If no active interfaces, then don't even try.)
3732 					rr->SendRNow   = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
3733 					rr->LastAPTime = m->timenow;
3734 					rr->ProbeCount--;
3735 					SetNextAnnounceProbeTime(m, rr);
3736 					}
3737 				// else, if it has now finished probing, move it to state Verified,
3738 				// and update m->NextScheduledResponse so it will be announced
3739 				else
3740 					{
3741 					AuthRecord *r2;
3742 					rr->resrec.RecordType     = kDNSRecordTypeVerified;
3743 					rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
3744 					rr->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
3745 					SetNextAnnounceProbeTime(m, rr);
3746 					// If we have any records on our duplicate list that match this one, they have now also completed probing
3747 					for (r2 = m->DuplicateRecords; r2; r2=r2->next)
3748 						if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
3749 							r2->ProbeCount = 0;
3750 					AcknowledgeRecord(m, rr);
3751 					}
3752 				}
3753 			}
3754 		m->CurrentRecord = m->DuplicateRecords;
3755 		while (m->CurrentRecord)
3756 			{
3757 			AuthRecord *rr = m->CurrentRecord;
3758 			m->CurrentRecord = rr->next;
3759 			if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
3760 				AcknowledgeRecord(m, rr);
3761 			}
3762 		}
3763 
3764 	// 3. Now we know which queries and probes we're sending,
3765 	// go through our interface list sending the appropriate queries on each interface
3766 	while (intf)
3767 		{
3768 		AuthRecord *rr;
3769 		mDNSu8 *queryptr = m->omsg.data;
3770 		InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
3771 		if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
3772 		if (!KnownAnswerList)
3773 			{
3774 			// Start a new known-answer list
3775 			CacheRecord **kalistptr = &KnownAnswerList;
3776 			mDNSu32 answerforecast = 0;
3777 
3778 			// Put query questions in this packet
3779 			for (q = m->Questions; q; q=q->next)
3780 				if (q->SendQNow == intf->InterfaceID)
3781 					{
3782 					debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
3783 						SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting    ",
3784 						q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
3785 					// If we're suppressing this question, or we successfully put it, update its SendQNow state
3786 					if (SuppressOnThisInterface(q->DupSuppress, intf) ||
3787 						BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
3788 							q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3789 					}
3790 
3791 			// Put probe questions in this packet
3792 			for (rr = m->ResourceRecords; rr; rr=rr->next)
3793 				if (rr->SendRNow == intf->InterfaceID)
3794 					{
3795 					mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
3796 					mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
3797 					const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
3798 					mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
3799 					// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
3800 					mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
3801 					if (newptr && newptr + forecast < limit)
3802 						{
3803 						queryptr       = newptr;
3804 						answerforecast = forecast;
3805 						rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
3806 						rr->IncludeInProbe = mDNStrue;
3807 						verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
3808 							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
3809 						}
3810 					else
3811 						{
3812 						verbosedebugf("SendQueries:   Retracting Question %##s (%s)",
3813 							rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3814 						m->omsg.h.numQuestions--;
3815 						}
3816 					}
3817 				}
3818 
3819 		// Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
3820 		while (KnownAnswerList)
3821 			{
3822 			CacheRecord *rr = KnownAnswerList;
3823 			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
3824 			mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
3825 			if (newptr)
3826 				{
3827 				verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d",
3828 					rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
3829 				queryptr = newptr;
3830 				KnownAnswerList = rr->NextInKAList;
3831 				rr->NextInKAList = mDNSNULL;
3832 				}
3833 			else
3834 				{
3835 				// If we ran out of space and we have more than one question in the packet, that's an error --
3836 				// we shouldn't have put more than one question if there was a risk of us running out of space.
3837 				if (m->omsg.h.numQuestions > 1)
3838 					LogMsg("SendQueries:   Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
3839 				m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
3840 				break;
3841 				}
3842 			}
3843 
3844 		for (rr = m->ResourceRecords; rr; rr=rr->next)
3845 			if (rr->IncludeInProbe)
3846 				{
3847 				mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
3848 				rr->IncludeInProbe = mDNSfalse;
3849 				if (newptr) queryptr = newptr;
3850 				else LogMsg("SendQueries:   How did we fail to have space for the Update record %##s (%s)?",
3851 					rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3852 				}
3853 
3854 		if (queryptr > m->omsg.data)
3855 			{
3856 			if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
3857 				LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
3858 			debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
3859 				m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
3860 				m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
3861 				m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
3862 			if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
3863 			if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
3864 			if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
3865 			if (++pktcount >= 1000)
3866 				{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
3867 			// There might be more records left in the known answer list, or more questions to send
3868 			// on this interface, so go around one more time and try again.
3869 			}
3870 		else	// Nothing more to send on this interface; go to next
3871 			{
3872 			const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
3873 			#if MDNS_DEBUGMSGS && 0
3874 			const char *const msg = next ? "SendQueries:   Nothing more on %p; moving to %p" : "SendQueries:   Nothing more on %p";
3875 			debugf(msg, intf, next);
3876 			#endif
3877 			intf = next;
3878 			}
3879 		}
3880 
3881 	// 4. Final housekeeping
3882 
3883 	// 4a. Debugging check: Make sure we announced all our records
3884 	for (ar = m->ResourceRecords; ar; ar=ar->next)
3885 		if (ar->SendRNow)
3886 			{
3887 			if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
3888 				LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
3889 			ar->SendRNow = mDNSNULL;
3890 			}
3891 
3892 	// 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
3893 	// that their interface which went away might come back again, the logic will want to send queries
3894 	// for those records, but we can't because their interface isn't here any more, so to keep the
3895 	// state machine ticking over we just pretend we did so.
3896 	// If the interface does not come back in time, the cache record will expire naturally
3897 	FORALL_CACHERECORDS(slot, cg, cr)
3898 		if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
3899 			{
3900 			cr->UnansweredQueries++;
3901 			cr->CRActiveQuestion->SendQNow = mDNSNULL;
3902 			SetNextCacheCheckTime(m, cr);
3903 			}
3904 
3905 	// 4c. Debugging check: Make sure we sent all our planned questions
3906 	// Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
3907 	// we legitimately couldn't send because the interface is no longer available
3908 	for (q = m->Questions; q; q=q->next)
3909 		if (q->SendQNow)
3910 			{
3911 			LogMsg("SendQueries: No active interface to send: %##s %s", q->qname.c, DNSTypeName(q->qtype));
3912 			q->SendQNow = mDNSNULL;
3913 			}
3914 	}
3915 
3916 // ***************************************************************************
3917 #if COMPILER_LIKES_PRAGMA_MARK
3918 #pragma mark -
3919 #pragma mark - RR List Management & Task Management
3920 #endif
3921 
3922 // NOTE: AnswerQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
3923 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
AnswerQuestionWithResourceRecord(mDNS * const m,DNSQuestion * q,CacheRecord * rr,mDNSBool AddRecord)3924 mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
3925 	{
3926 	verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
3927 		q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
3928 
3929 	// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
3930 	// may be called twice, once when the record is received, and again when it's time to notify local clients.
3931 	// If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
3932 
3933 	rr->LastUsed = m->timenow;
3934 	if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
3935 		{
3936 		if (!rr->CRActiveQuestion) m->rrcache_active++;	// If not previously active, increment rrcache_active count
3937 		rr->CRActiveQuestion = q;						// We know q is non-null
3938 		SetNextCacheCheckTime(m, rr);
3939 		}
3940 
3941 	// If this is:
3942 	// (a) a no-cache add, where we've already done at least one 'QM' query, or
3943 	// (b) a normal add, where we have at least one unique-type answer,
3944 	// then there's no need to keep polling the network.
3945 	// (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
3946 	if ((AddRecord == 2 && !q->RequestUnicast) ||
3947 		(AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
3948 		if (ActiveQuestion(q))
3949 			{
3950 			q->LastQTime      = m->timenow;
3951 			q->LastQTxTime    = m->timenow;
3952 			q->RecentAnswerPkts = 0;
3953 			q->ThisQInterval  = MaxQuestionInterval;
3954 			q->RequestUnicast = mDNSfalse;
3955 			}
3956 
3957 	if (rr->DelayDelivery) return;		// We'll come back later when CacheRecordDeferredAdd() calls us
3958 
3959 	m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
3960 	if (q->QuestionCallback)
3961 		q->QuestionCallback(m, q, &rr->resrec, AddRecord);
3962 	m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
3963 	// CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
3964 	// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
3965 	// Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
3966 	// and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
3967 	// being deleted out from under them.
3968 	}
3969 
CacheRecordDeferredAdd(mDNS * const m,CacheRecord * rr)3970 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
3971 	{
3972 	rr->DelayDelivery = 0;		// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
3973 	if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
3974 	m->CurrentQuestion = m->Questions;
3975 	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3976 		{
3977 		DNSQuestion *q = m->CurrentQuestion;
3978 		m->CurrentQuestion = q->next;
3979 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3980 			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
3981 		}
3982 	m->CurrentQuestion = mDNSNULL;
3983 	}
3984 
CheckForSoonToExpireRecords(mDNS * const m,const domainname * const name,const mDNSu32 namehash,const mDNSu32 slot)3985 mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
3986 	{
3987 	const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond;	// See if there are any records expiring within one second
3988 	const mDNSs32 start      = m->timenow - 0x10000000;
3989 	mDNSs32 delay = start;
3990 	CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
3991 	CacheRecord *rr;
3992 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3993 		if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
3994 			if (threshhold - RRExpireTime(rr) >= 0)		// If we have records about to expire within a second
3995 				if (delay - RRExpireTime(rr) < 0)		// then delay until after they've been deleted
3996 					delay = RRExpireTime(rr);
3997 	if (delay - start > 0) return(NonZeroTime(delay));
3998 	else return(0);
3999 	}
4000 
4001 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4002 // If new questions are created as a result of invoking client callbacks, they will be added to
4003 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4004 // rr is a new CacheRecord just received into our cache
4005 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4006 // NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback,
4007 // which may change the record list and/or question list.
4008 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
CacheRecordAdd(mDNS * const m,CacheRecord * rr)4009 mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
4010 	{
4011 	if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
4012 	m->CurrentQuestion = m->Questions;
4013 	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4014 		{
4015 		DNSQuestion *q = m->CurrentQuestion;
4016 		m->CurrentQuestion = q->next;
4017 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4018 			{
4019 			// If this question is one that's actively sending queries, and it's received ten answers within one
4020 			// second of sending the last query packet, then that indicates some radical network topology change,
4021 			// so reset its exponential backoff back to the start. We must be at least at the eight-second interval
4022 			// to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
4023 			// because we will anyway send another query within a few seconds. The first reset query is sent out
4024 			// randomized over the next four seconds to reduce possible synchronization between machines.
4025 			if (q->LastAnswerPktNum != m->PktNum)
4026 				{
4027 				q->LastAnswerPktNum = m->PktNum;
4028 				if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
4029 					q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
4030 					{
4031 					LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
4032 						q->qname.c, DNSTypeName(q->qtype));
4033 					q->LastQTime      = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
4034 					q->ThisQInterval  = InitialQuestionInterval;
4035 					SetNextQueryTime(m,q);
4036 					}
4037 				}
4038 			verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
4039 				rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
4040 			q->CurrentAnswers++;
4041 			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4042 			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4043 			if (q->CurrentAnswers > 4000)
4044 				{
4045 				static int msgcount = 0;
4046 				if (msgcount++ < 10)
4047 					LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
4048 						q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
4049 				rr->resrec.rroriginalttl = 1;
4050 				rr->UnansweredQueries = MaxUnansweredQueries;
4051 				}
4052 			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4053 			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4054 			}
4055 		}
4056 	m->CurrentQuestion = mDNSNULL;
4057 	SetNextCacheCheckTime(m, rr);
4058 	}
4059 
4060 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
4061 // If new questions are created as a result of invoking client callbacks, they will be added to
4062 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4063 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
4064 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
4065 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
4066 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
4067 // NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
4068 // which may change the record list and/or question list.
4069 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
NoCacheAnswer(mDNS * const m,CacheRecord * rr)4070 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
4071 	{
4072 	LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
4073 	if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
4074 	m->CurrentQuestion = m->Questions;
4075 	while (m->CurrentQuestion)
4076 		{
4077 		DNSQuestion *q = m->CurrentQuestion;
4078 		m->CurrentQuestion = q->next;
4079 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4080 			AnswerQuestionWithResourceRecord(m, q, rr, 2);	// Value '2' indicates "don't expect 'remove' events for this"
4081 		// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4082 		}
4083 	m->CurrentQuestion = mDNSNULL;
4084 	}
4085 
4086 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute
4087 // If new questions are created as a result of invoking client callbacks, they will be added to
4088 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
4089 // rr is an existing cache CacheRecord that just expired and is being deleted
4090 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
4091 // NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback,
4092 // which may change the record list and/or question list.
4093 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
CacheRecordRmv(mDNS * const m,CacheRecord * rr)4094 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
4095 	{
4096 	if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set");
4097 	m->CurrentQuestion = m->Questions;
4098 	while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
4099 		{
4100 		DNSQuestion *q = m->CurrentQuestion;
4101 		m->CurrentQuestion = q->next;
4102 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4103 			{
4104 			verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
4105 			if (q->CurrentAnswers == 0)
4106 				LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
4107 					q, q->qname.c, DNSTypeName(q->qtype));
4108 			else
4109 				{
4110 				q->CurrentAnswers--;
4111 				if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
4112 				if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
4113 				}
4114 			if (q->CurrentAnswers == 0)
4115 				{
4116 				debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents",
4117 					q->qname.c, DNSTypeName(q->qtype));
4118 				ReconfirmAntecedents(m, q);
4119 				}
4120 			q->FlappingInterface = mDNSNULL;
4121 			AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse);
4122 			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4123 			}
4124 		}
4125 	m->CurrentQuestion = mDNSNULL;
4126 	}
4127 
ReleaseCacheEntity(mDNS * const m,CacheEntity * e)4128 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
4129 	{
4130 #if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
4131 	unsigned int i;
4132 	for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
4133 #endif
4134 	e->next = m->rrcache_free;
4135 	m->rrcache_free = e;
4136 	m->rrcache_totalused--;
4137 	}
4138 
ReleaseCacheGroup(mDNS * const m,CacheGroup ** cp)4139 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
4140 	{
4141 	CacheEntity *e = (CacheEntity *)(*cp);
4142 	//LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
4143 	if ((*cp)->rrcache_tail != &(*cp)->members)
4144 		LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
4145 	//if ((*cp)->name != (domainname*)((*cp)->namestorage))
4146 	//	LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
4147 	if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
4148 	(*cp)->name = mDNSNULL;
4149 	*cp = (*cp)->next;			// Cut record from list
4150 	ReleaseCacheEntity(m, e);
4151 	}
4152 
ReleaseCacheRecord(mDNS * const m,CacheRecord * r)4153 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
4154 	{
4155 	if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
4156 	r->resrec.rdata = mDNSNULL;
4157 	ReleaseCacheEntity(m, (CacheEntity *)r);
4158 	}
4159 
4160 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
4161 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
4162 // callbacks for old records are delivered before callbacks for newer records.
CheckCacheExpiration(mDNS * const m,CacheGroup * cg)4163 mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
4164 	{
4165 	CacheRecord **rp = &cg->members;
4166 
4167 	if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
4168 	m->lock_rrcache = 1;
4169 
4170 	while (*rp)
4171 		{
4172 		CacheRecord *const rr = *rp;
4173 		mDNSs32 event = RRExpireTime(rr);
4174 		if (m->timenow - event >= 0)	// If expired, delete it
4175 			{
4176 			*rp = rr->next;				// Cut it from the list
4177 			verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
4178 			if (rr->CRActiveQuestion)	// If this record has one or more active questions, tell them it's going away
4179 				{
4180 				CacheRecordRmv(m, rr);
4181 				m->rrcache_active--;
4182 				}
4183 			ReleaseCacheRecord(m, rr);
4184 			}
4185 		else							// else, not expired; see if we need to query
4186 			{
4187 			if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
4188 				event = rr->DelayDelivery;
4189 			else
4190 				{
4191 				if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
4192 				if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
4193 					{
4194 					if (m->timenow - rr->NextRequiredQuery < 0)		// If not yet time for next query
4195 						event = rr->NextRequiredQuery;				// then just record when we want the next query
4196 					else											// else trigger our question to go out now
4197 						{
4198 						// Set NextScheduledQuery to timenow so that SendQueries() will run.
4199 						// SendQueries() will see that we have records close to expiration, and send FEQs for them.
4200 						m->NextScheduledQuery = m->timenow;
4201 						// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
4202 						// which will correctly update m->NextCacheCheck for us.
4203 						event = m->timenow + 0x3FFFFFFF;
4204 						}
4205 					}
4206 				}
4207 			verbosedebugf("CheckCacheExpiration:%6d %5d %s",
4208 				(event-m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
4209 			if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
4210 				m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
4211 			rp = &rr->next;
4212 			}
4213 		}
4214 	if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
4215 	cg->rrcache_tail = rp;
4216 	m->lock_rrcache = 0;
4217 	}
4218 
AnswerNewQuestion(mDNS * const m)4219 mDNSlocal void AnswerNewQuestion(mDNS *const m)
4220 	{
4221 	mDNSBool ShouldQueryImmediately = mDNStrue;
4222 	CacheRecord *rr;
4223 	DNSQuestion *q = m->NewQuestions;		// Grab the question we're going to answer
4224 	const mDNSu32 slot = HashSlot(&q->qname);
4225 	CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4226 
4227 	verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4228 
4229 	if (cg) CheckCacheExpiration(m, cg);
4230 	m->NewQuestions = q->next;				// Advance NewQuestions to the next *after* calling CheckCacheExpiration();
4231 
4232 	if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
4233 	// This should be safe, because calling the client's question callback may cause the
4234 	// question list to be modified, but should not ever cause the rrcache list to be modified.
4235 	// If the client's question callback deletes the question, then m->CurrentQuestion will
4236 	// be advanced, and we'll exit out of the loop
4237 	m->lock_rrcache = 1;
4238 	if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
4239 	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4240 
4241 	if (q->InterfaceID == mDNSInterface_Any)	// If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
4242 		{
4243 		if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4244 		m->CurrentRecord = m->ResourceRecords;
4245 		while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4246 			{
4247 			AuthRecord *rr = m->CurrentRecord;
4248 			m->CurrentRecord = rr->next;
4249 			if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
4250 				if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4251 					{
4252 					AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4253 					// MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4254 					if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4255 					}
4256 			}
4257 		m->CurrentRecord   = mDNSNULL;
4258 		}
4259 
4260 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4261 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4262 			{
4263 			// SecsSinceRcvd is whole number of elapsed seconds, rounded down
4264 			mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
4265 			if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
4266 				{
4267 				LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
4268 					rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4269 				continue;	// Go to next one in loop
4270 				}
4271 
4272 			// If this record set is marked unique, then that means we can reasonably assume we have the whole set
4273 			// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
4274 			if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
4275 				ShouldQueryImmediately = mDNSfalse;
4276 			q->CurrentAnswers++;
4277 			if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
4278 			if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
4279 			AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
4280 			// MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
4281 			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4282 			}
4283 		else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
4284 			if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
4285 				ShouldQueryImmediately = mDNSfalse;
4286 
4287 	if (ShouldQueryImmediately && m->CurrentQuestion == q)
4288 		{
4289 		q->ThisQInterval  = InitialQuestionInterval;
4290 		q->LastQTime      = m->timenow - q->ThisQInterval;
4291 		m->NextScheduledQuery = m->timenow;
4292 		}
4293 	m->CurrentQuestion = mDNSNULL;
4294 	m->lock_rrcache = 0;
4295 	}
4296 
4297 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
4298 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
AnswerNewLocalOnlyQuestion(mDNS * const m)4299 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
4300 	{
4301 	DNSQuestion *q = m->NewLocalOnlyQuestions;		// Grab the question we're going to answer
4302 	m->NewLocalOnlyQuestions = q->next;				// Advance NewQuestions to the next (if any)
4303 
4304 	debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
4305 
4306 	if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
4307 	m->CurrentQuestion = q;		// Indicate which question we're answering, so we'll know if it gets deleted
4308 
4309 	if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
4310 	m->CurrentRecord = m->ResourceRecords;
4311 	while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
4312 		{
4313 		AuthRecord *rr = m->CurrentRecord;
4314 		m->CurrentRecord = rr->next;
4315 		if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4316 			{
4317 			AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
4318 			// MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
4319 			if (m->CurrentQuestion != q) break;		// If callback deleted q, then we're finished here
4320 			}
4321 		}
4322 
4323 	m->CurrentQuestion = mDNSNULL;
4324 	m->CurrentRecord   = mDNSNULL;
4325 	}
4326 
GetCacheEntity(mDNS * const m,const CacheGroup * const PreserveCG)4327 mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
4328 	{
4329 	CacheEntity *e = mDNSNULL;
4330 
4331 	if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
4332 	m->lock_rrcache = 1;
4333 
4334 	// If we have no free records, ask the client layer to give us some more memory
4335 	if (!m->rrcache_free && m->MainCallback)
4336 		{
4337 		if (m->rrcache_totalused != m->rrcache_size)
4338 			LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
4339 				m->rrcache_totalused, m->rrcache_size);
4340 
4341 		// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
4342 		// number of bogus records so that we keep growing our cache until the machine runs out of memory.
4343 		// To guard against this, if we're actively using less than 1/32 of our cache, then we
4344 		// purge all the unused records and recycle them, instead of allocating more memory.
4345 		if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active)
4346 			debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
4347 				m->rrcache_size, m->rrcache_active);
4348 		else
4349 			{
4350 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
4351 			m->MainCallback(m, mStatus_GrowCache);
4352 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
4353 			}
4354 		}
4355 
4356 	// If we still have no free records, recycle all the records we can.
4357 	// Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
4358 	if (!m->rrcache_free)
4359 		{
4360 		#if MDNS_DEBUGMSGS
4361 		mDNSu32 oldtotalused = m->rrcache_totalused;
4362 		#endif
4363 		mDNSu32 slot;
4364 		for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4365 			{
4366 			CacheGroup **cp = &m->rrcache_hash[slot];
4367 			while (*cp)
4368 				{
4369 				CacheRecord **rp = &(*cp)->members;
4370 				while (*rp)
4371 					{
4372 					// Records that answer still-active questions are not candidates for recycling
4373 					// Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
4374 					if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
4375 						rp=&(*rp)->next;
4376 					else
4377 						{
4378 						CacheRecord *rr = *rp;
4379 						*rp = (*rp)->next;			// Cut record from list
4380 						ReleaseCacheRecord(m, rr);
4381 						}
4382 					}
4383 				if ((*cp)->rrcache_tail != rp)
4384 					verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
4385 				(*cp)->rrcache_tail = rp;
4386 				if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
4387 				else ReleaseCacheGroup(m, cp);
4388 				}
4389 			}
4390 		#if MDNS_DEBUGMSGS
4391 		debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
4392 		#endif
4393 		}
4394 
4395 	if (m->rrcache_free)	// If there are records in the free list, take one
4396 		{
4397 		e = m->rrcache_free;
4398 		m->rrcache_free = e->next;
4399 		if (++m->rrcache_totalused >= m->rrcache_report)
4400 			{
4401 			debugf("RR Cache now using %ld objects", m->rrcache_totalused);
4402 			if (m->rrcache_report < 100) m->rrcache_report += 10;
4403 			else                         m->rrcache_report += 100;
4404 			}
4405 		mDNSPlatformMemZero(e, sizeof(*e));
4406 		}
4407 
4408 	m->lock_rrcache = 0;
4409 
4410 	return(e);
4411 	}
4412 
GetCacheRecord(mDNS * const m,CacheGroup * cg,mDNSu16 RDLength)4413 mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
4414 	{
4415 	CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
4416 	if (r)
4417 		{
4418 		r->resrec.rdata = (RData*)&r->rdatastorage;	// By default, assume we're usually going to be using local storage
4419 		if (RDLength > InlineCacheRDSize)			// If RDLength is too big, allocate extra storage
4420 			{
4421 			r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
4422 			if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
4423 			else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
4424 			}
4425 		}
4426 	return(r);
4427 	}
4428 
GetCacheGroup(mDNS * const m,const mDNSu32 slot,const ResourceRecord * const rr)4429 mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
4430 	{
4431 	mDNSu16 namelen = DomainNameLength(rr->name);
4432 	CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
4433 	if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
4434 	cg->next         = m->rrcache_hash[slot];
4435 	cg->namehash     = rr->namehash;
4436 	cg->members      = mDNSNULL;
4437 	cg->rrcache_tail = &cg->members;
4438 	cg->name         = (domainname*)cg->namestorage;
4439 	//LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
4440 	//	(namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
4441 	if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
4442 	if (!cg->name)
4443 		{
4444 		LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
4445 		ReleaseCacheEntity(m, (CacheEntity*)cg);
4446 		return(mDNSNULL);
4447 		}
4448 	AssignDomainName(cg->name, rr->name);
4449 
4450 	if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
4451 	m->rrcache_hash[slot] = cg;
4452 	if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
4453 
4454 	return(cg);
4455 	}
4456 
PurgeCacheResourceRecord(mDNS * const m,CacheRecord * rr)4457 mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
4458 	{
4459 	// Make sure we mark this record as thoroughly expired -- we don't ever want to give
4460 	// a positive answer using an expired record (e.g. from an interface that has gone away).
4461 	// We don't want to clear CRActiveQuestion here, because that would leave the record subject to
4462 	// summary deletion without giving the proper callback to any questions that are monitoring it.
4463 	// By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
4464 	rr->TimeRcvd          = m->timenow - mDNSPlatformOneSecond * 60;
4465 	rr->UnansweredQueries = MaxUnansweredQueries;
4466 	rr->resrec.rroriginalttl     = 0;
4467 	SetNextCacheCheckTime(m, rr);
4468 	}
4469 
mDNS_TimeNow(const mDNS * const m)4470 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
4471 	{
4472 	mDNSs32 time;
4473 	mDNSPlatformLock(m);
4474 	if (m->mDNS_busy)
4475 		{
4476 		LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
4477 		if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
4478 		}
4479 
4480 	if (m->timenow) time = m->timenow;
4481 	else            time = mDNS_TimeNow_NoLock(m);
4482 	mDNSPlatformUnlock(m);
4483 	return(time);
4484 	}
4485 
mDNS_Execute(mDNS * const m)4486 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
4487 	{
4488 	mDNS_Lock(m);	// Must grab lock before trying to read m->timenow
4489 
4490 	if (m->timenow - m->NextScheduledEvent >= 0)
4491 		{
4492 		int i;
4493 
4494 		verbosedebugf("mDNS_Execute");
4495 		if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set");
4496 
4497 		// 1. If we're past the probe suppression time, we can clear it
4498 		if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
4499 
4500 		// 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
4501 		if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
4502 
4503 		// 3. Purge our cache of stale old records
4504 		if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
4505 			{
4506 			mDNSu32 slot;
4507 			m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
4508 			for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
4509 				{
4510 				CacheGroup **cp = &m->rrcache_hash[slot];
4511 				while (*cp)
4512 					{
4513 					CheckCacheExpiration(m, *cp);
4514 					if ((*cp)->members) cp=&(*cp)->next;
4515 					else ReleaseCacheGroup(m, cp);
4516 					}
4517 				}
4518 			LogOperation("Cache checked. Next in %ld ticks", m->NextCacheCheck - m->timenow);
4519 			}
4520 
4521 		// 4. See if we can answer any of our new local questions from the cache
4522 		for (i=0; m->NewQuestions && i<1000; i++)
4523 			{
4524 			if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
4525 			AnswerNewQuestion(m);
4526 			}
4527 		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
4528 
4529 		for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
4530 		if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
4531 
4532 		for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
4533 			{
4534 			AuthRecord *rr = m->NewLocalRecords;
4535 			m->NewLocalRecords = m->NewLocalRecords->next;
4536 			AnswerLocalQuestions(m, rr, mDNStrue);
4537 			}
4538 		if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
4539 
4540 		// 5. See what packets we need to send
4541 		if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
4542 		else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)
4543 			{
4544 			// If the platform code is ready, and we're not suppressing packet generation right now
4545 			// then send our responses, probes, and questions.
4546 			// We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
4547 			// We send queries next, because there might be final-stage probes that complete their probing here, causing
4548 			// them to advance to announcing state, and we want those to be included in any announcements we send out.
4549 			// Finally, we send responses, including the previously mentioned records that just completed probing.
4550 			m->SuppressSending = 0;
4551 
4552 			// 6. Send Query packets. This may cause some probing records to advance to announcing state
4553 			if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
4554 			if (m->timenow - m->NextScheduledQuery >= 0)
4555 				{
4556 				LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second");
4557 				m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
4558 				}
4559 			if (m->timenow - m->NextScheduledProbe >= 0)
4560 				{
4561 				LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second");
4562 				m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
4563 				}
4564 
4565 			// 7. Send Response packets, including probing records just advanced to announcing state
4566 			if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
4567 			if (m->timenow - m->NextScheduledResponse >= 0)
4568 				{
4569 				LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
4570 				m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
4571 				}
4572 			}
4573 
4574 		// Clear RandomDelay values, ready to pick a new different value next time
4575 		m->RandomQueryDelay     = 0;
4576 		m->RandomReconfirmDelay = 0;
4577 		}
4578 
4579 	// Note about multi-threaded systems:
4580 	// On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
4581 	// performing mDNS API operations that change our next scheduled event time.
4582 	//
4583 	// On multi-threaded systems (like the current Windows implementation) that have a single main thread
4584 	// calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
4585 	// of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
4586 	// signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
4587 	// more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
4588 	// in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
4589 	// does, the state of the signal will be noticed, causing the blocking primitive to return immediately
4590 	// without blocking. This avoids the race condition between the signal from the other thread arriving
4591 	// just *before* or just *after* the main thread enters the blocking primitive.
4592 	//
4593 	// On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
4594 	// with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
4595 	// set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
4596 	// callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
4597 	// by the time it gets to the timer callback function).
4598 
4599 #ifndef UNICAST_DISABLED
4600 	uDNS_Execute(m);
4601 #endif
4602 	mDNS_Unlock(m);		// Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
4603 	return(m->NextScheduledEvent);
4604 	}
4605 
4606 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
4607 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
4608 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
4609 // Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
4610 // mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
4611 // found itself in a new network environment. For example, if the Ethernet hardware indicates that the
4612 // cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
4613 // to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
4614 // While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
4615 // traffic, so it should only be called when there is legitimate reason to believe the machine
4616 // may have become attached to a new network.
mDNSCoreMachineSleep(mDNS * const m,mDNSBool sleepstate)4617 mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
4618 	{
4619 	AuthRecord *rr;
4620 
4621 	mDNS_Lock(m);
4622 
4623 	m->SleepState = sleepstate;
4624 	LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
4625 
4626 	if (sleepstate)
4627 		{
4628 #ifndef UNICAST_DISABLED
4629 		uDNS_Sleep(m);
4630 #endif
4631 		// Mark all the records we need to deregister and send them
4632 		for (rr = m->ResourceRecords; rr; rr=rr->next)
4633 			if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
4634 				rr->ImmedAnswer = mDNSInterfaceMark;
4635 		SendResponses(m);
4636 		}
4637 	else
4638 		{
4639 		DNSQuestion *q;
4640 		mDNSu32 slot;
4641 		CacheGroup *cg;
4642 		CacheRecord *cr;
4643 
4644 #ifndef UNICAST_DISABLED
4645 		uDNS_Wake(m);
4646 #endif
4647         // 1. Retrigger all our questions
4648 		for (q = m->Questions; q; q=q->next)				// Scan our list of questions
4649 			if (ActiveQuestion(q))
4650 				{
4651 				q->ThisQInterval    = InitialQuestionInterval;	// MUST be > zero for an active question
4652 				q->RequestUnicast   = 2;						// Set to 2 because is decremented once *before* we check it
4653 				q->LastQTime        = m->timenow - q->ThisQInterval;
4654 				q->RecentAnswerPkts = 0;
4655 				ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
4656 				m->NextScheduledQuery = m->timenow;
4657 				}
4658 
4659 		// 2. Re-validate our cache records
4660 		m->NextCacheCheck  = m->timenow;
4661 		FORALL_CACHERECORDS(slot, cg, cr)
4662 			mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
4663 
4664 		// 3. Retrigger probing and announcing for all our authoritative records
4665 		for (rr = m->ResourceRecords; rr; rr=rr->next)
4666 			{
4667 			if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
4668 			rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
4669 			rr->AnnounceCount  = InitialAnnounceCount;
4670 			rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
4671 			InitializeLastAPTime(m, rr);
4672 			}
4673 		}
4674 
4675 	mDNS_Unlock(m);
4676 	}
4677 
4678 // ***************************************************************************
4679 #if COMPILER_LIKES_PRAGMA_MARK
4680 #pragma mark -
4681 #pragma mark - Packet Reception Functions
4682 #endif
4683 
4684 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
4685 
GenerateUnicastResponse(const DNSMessage * const query,const mDNSu8 * const end,const mDNSInterfaceID InterfaceID,mDNSBool LegacyQuery,DNSMessage * const response,AuthRecord * ResponseRecords)4686 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
4687 	const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
4688 	{
4689 	mDNSu8          *responseptr     = response->data;
4690 	const mDNSu8    *const limit     = response->data + sizeof(response->data);
4691 	const mDNSu8    *ptr             = query->data;
4692 	AuthRecord  *rr;
4693 	mDNSu32          maxttl = 0x70000000;
4694 	int i;
4695 
4696 	// Initialize the response fields so we can answer the questions
4697 	InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
4698 
4699 	// ***
4700 	// *** 1. Write out the list of questions we are actually going to answer with this packet
4701 	// ***
4702 	if (LegacyQuery)
4703 		{
4704 		maxttl = 10;
4705 		for (i=0; i<query->h.numQuestions; i++)						// For each question...
4706 			{
4707 			DNSQuestion q;
4708 			ptr = getQuestion(query, ptr, end, InterfaceID, &q);	// get the question...
4709 			if (!ptr) return(mDNSNULL);
4710 
4711 			for (rr=ResponseRecords; rr; rr=rr->NextResponse)		// and search our list of proposed answers
4712 				{
4713 				if (rr->NR_AnswerTo == ptr)							// If we're going to generate a record answering this question
4714 					{												// then put the question in the question section
4715 					responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
4716 					if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
4717 					break;		// break out of the ResponseRecords loop, and go on to the next question
4718 					}
4719 				}
4720 			}
4721 
4722 		if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
4723 		}
4724 
4725 	// ***
4726 	// *** 2. Write Answers
4727 	// ***
4728 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4729 		if (rr->NR_AnswerTo)
4730 			{
4731 			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl);
4732 			if (p) responseptr = p;
4733 			else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
4734 			}
4735 
4736 	// ***
4737 	// *** 3. Write Additionals
4738 	// ***
4739 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4740 		if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
4741 			{
4742 			mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl);
4743 			if (p) responseptr = p;
4744 			else debugf("GenerateUnicastResponse: No more space for additionals");
4745 			}
4746 
4747 	return(responseptr);
4748 	}
4749 
4750 // AuthRecord *our is our Resource Record
4751 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
4752 // Returns 0 if there is no conflict
4753 // Returns +1 if there was a conflict and we won
4754 // Returns -1 if there was a conflict and we lost and have to rename
CompareRData(AuthRecord * our,CacheRecord * pkt)4755 mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
4756 	{
4757 	mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
4758 	mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
4759 	if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
4760 	if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
4761 
4762 	ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
4763 	pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
4764 	while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
4765 	if (ourptr >= ourend && pktptr >= pktend) return(0);			// If data identical, not a conflict
4766 
4767 	if (ourptr >= ourend) return(-1);								// Our data ran out first; We lost
4768 	if (pktptr >= pktend) return(+1);								// Packet data ran out first; We won
4769 	if (*pktptr > *ourptr) return(-1);								// Our data is numerically lower; We lost
4770 	if (*pktptr < *ourptr) return(+1);								// Packet data is numerically lower; We won
4771 
4772 	LogMsg("CompareRData ERROR: Invalid state");
4773 	return(-1);
4774 	}
4775 
4776 // See if we have an authoritative record that's identical to this packet record,
4777 // whose canonical DependentOn record is the specified master record.
4778 // The DependentOn pointer is typically used for the TXT record of service registrations
4779 // It indicates that there is no inherent conflict detection for the TXT record
4780 // -- it depends on the SRV record to resolve name conflicts
4781 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
4782 // pointer chain (if any) to make sure we reach the canonical DependentOn record
4783 // If the record has no DependentOn, then just return that record's pointer
4784 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
MatchDependentOn(const mDNS * const m,const CacheRecord * const pktrr,const AuthRecord * const master)4785 mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
4786 	{
4787 	const AuthRecord *r1;
4788 	for (r1 = m->ResourceRecords; r1; r1=r1->next)
4789 		{
4790 		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4791 			{
4792 			const AuthRecord *r2 = r1;
4793 			while (r2->DependentOn) r2 = r2->DependentOn;
4794 			if (r2 == master) return(mDNStrue);
4795 			}
4796 		}
4797 	for (r1 = m->DuplicateRecords; r1; r1=r1->next)
4798 		{
4799 		if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
4800 			{
4801 			const AuthRecord *r2 = r1;
4802 			while (r2->DependentOn) r2 = r2->DependentOn;
4803 			if (r2 == master) return(mDNStrue);
4804 			}
4805 		}
4806 	return(mDNSfalse);
4807 	}
4808 
4809 // Find the canonical RRSet pointer for this RR received in a packet.
4810 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
4811 // pointers (if any) to make sure we return the canonical member of this name/type/class
4812 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
FindRRSet(const mDNS * const m,const CacheRecord * const pktrr)4813 mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
4814 	{
4815 	const AuthRecord *rr;
4816 	for (rr = m->ResourceRecords; rr; rr=rr->next)
4817 		{
4818 		if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
4819 			{
4820 			while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
4821 			return(rr);
4822 			}
4823 		}
4824 	return(mDNSNULL);
4825 	}
4826 
4827 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
4828 // as one of our records (our) but different rdata.
4829 // 1. If our record is not a type that's supposed to be unique, we don't care.
4830 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
4831 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
4832 //     points to our record, ignore this conflict (e.g. the packet record matches one of our
4833 //     TXT records, and that record is marked as dependent on 'our', its SRV record).
4834 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
4835 //    are members of the same RRSet, then this is not a conflict.
PacketRRConflict(const mDNS * const m,const AuthRecord * const our,const CacheRecord * const pktrr)4836 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
4837 	{
4838 	const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
4839 
4840 	// If not supposed to be unique, not a conflict
4841 	if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
4842 
4843 	// If a dependent record, not a conflict
4844 	if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
4845 
4846 	// If the pktrr matches a member of ourset, not a conflict
4847 	if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse);
4848 
4849 	// Okay, this is a conflict
4850 	return(mDNStrue);
4851 	}
4852 
4853 // NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
4854 // the record list and/or question list.
4855 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
ResolveSimultaneousProbe(mDNS * const m,const DNSMessage * const query,const mDNSu8 * const end,DNSQuestion * q,AuthRecord * our)4856 mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4857 	DNSQuestion *q, AuthRecord *our)
4858 	{
4859 	int i;
4860 	const mDNSu8 *ptr = LocateAuthorities(query, end);
4861 	mDNSBool FoundUpdate = mDNSfalse;
4862 
4863 	for (i = 0; i < query->h.numAuthorities; i++)
4864 		{
4865 		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
4866 		if (!ptr) break;
4867 		if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
4868 			{
4869 			FoundUpdate = mDNStrue;
4870 			if (PacketRRConflict(m, our, &m->rec.r))
4871 				{
4872 				int result          = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
4873 				if (!result) result = (int)our->resrec.rrtype  - (int)m->rec.r.resrec.rrtype;
4874 				if (!result) result = CompareRData(our, &m->rec.r);
4875 				if (result > 0)
4876 					debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4877 				else if (result < 0)
4878 					{
4879 					debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4880 					mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
4881 					goto exit;
4882 					}
4883 				}
4884 			}
4885 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
4886 		}
4887 	if (!FoundUpdate)
4888 		debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
4889 exit:
4890 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
4891 	}
4892 
FindIdenticalRecordInCache(const mDNS * const m,ResourceRecord * pktrr)4893 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
4894 	{
4895 	mDNSu32 slot = HashSlot(pktrr->name);
4896 	CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
4897 	CacheRecord *rr;
4898 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4899 		if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
4900 	return(rr);
4901 	}
4902 
4903 // ProcessQuery examines a received query to see if we have any answers to give
ProcessQuery(mDNS * const m,const DNSMessage * const query,const mDNSu8 * const end,const mDNSAddr * srcaddr,const mDNSInterfaceID InterfaceID,mDNSBool LegacyQuery,mDNSBool QueryWasMulticast,mDNSBool QueryWasLocalUnicast,DNSMessage * const response)4904 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
4905 	const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
4906 	mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
4907 	{
4908 	mDNSBool      FromLocalSubnet    = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
4909 	AuthRecord   *ResponseRecords    = mDNSNULL;
4910 	AuthRecord  **nrp                = &ResponseRecords;
4911 	CacheRecord  *ExpectedAnswers    = mDNSNULL;			// Records in our cache we expect to see updated
4912 	CacheRecord **eap                = &ExpectedAnswers;
4913 	DNSQuestion  *DupQuestions       = mDNSNULL;			// Our questions that are identical to questions in this packet
4914 	DNSQuestion **dqp                = &DupQuestions;
4915 	mDNSs32       delayresponse      = 0;
4916 	mDNSBool      SendLegacyResponse = mDNSfalse;
4917 	const mDNSu8 *ptr                = query->data;
4918 	mDNSu8       *responseptr        = mDNSNULL;
4919 	AuthRecord   *rr;
4920 	int i;
4921 
4922 	// ***
4923 	// *** 1. Parse Question Section and mark potential answers
4924 	// ***
4925 	for (i=0; i<query->h.numQuestions; i++)						// For each question...
4926 		{
4927 		mDNSBool QuestionNeedsMulticastResponse;
4928 		int NumAnswersForThisQuestion = 0;
4929 		DNSQuestion pktq, *q;
4930 		ptr = getQuestion(query, ptr, end, InterfaceID, &pktq);	// get the question...
4931 		if (!ptr) goto exit;
4932 
4933 		// The only queries that *need* a multicast response are:
4934 		// * Queries sent via multicast
4935 		// * from port 5353
4936 		// * that don't have the kDNSQClass_UnicastResponse bit set
4937 		// These queries need multicast responses because other clients will:
4938 		// * suppress their own identical questions when they see these questions, and
4939 		// * expire their cache records if they don't see the expected responses
4940 		// For other queries, we may still choose to send the occasional multicast response anyway,
4941 		// to keep our neighbours caches warm, and for ongoing conflict detection.
4942 		QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
4943 		// Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
4944 		pktq.qclass &= ~kDNSQClass_UnicastResponse;
4945 
4946 		// Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
4947 		// can result in user callbacks which may change the record list and/or question list.
4948 		// Also note: we just mark potential answer records here, without trying to build the
4949 		// "ResponseRecords" list, because we don't want to risk user callbacks deleting records
4950 		// from that list while we're in the middle of trying to build it.
4951 		if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set");
4952 		m->CurrentRecord = m->ResourceRecords;
4953 		while (m->CurrentRecord)
4954 			{
4955 			rr = m->CurrentRecord;
4956 			m->CurrentRecord = rr->next;
4957 			if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
4958 				{
4959 				if (rr->resrec.RecordType == kDNSRecordTypeUnique)
4960 					ResolveSimultaneousProbe(m, query, end, &pktq, rr);
4961 				else if (ResourceRecordIsValidAnswer(rr))
4962 					{
4963 					NumAnswersForThisQuestion++;
4964 					// Notes:
4965 					// NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
4966 					// NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
4967 					// NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
4968 					// If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
4969 					// but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
4970 					// then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
4971 					if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
4972 						{
4973 						// We only mark this question for sending if it is at least one second since the last time we multicast it
4974 						// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
4975 						// This is to guard against the case where someone blasts us with queries as fast as they can.
4976 						if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
4977 							(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
4978 							rr->NR_AnswerTo = (mDNSu8*)~0;
4979 						}
4980 					else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
4981 					}
4982 				}
4983 			}
4984 
4985 		// If we couldn't answer this question, someone else might be able to,
4986 		// so use random delay on response to reduce collisions
4987 		if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond;	// Divided by 50 = 20ms
4988 
4989 		// We only do the following accelerated cache expiration processing and duplicate question suppression processing
4990 		// for multicast queries with multicast responses.
4991 		// For any query generating a unicast response we don't do this because we can't assume we will see the response
4992 		if (QuestionNeedsMulticastResponse)
4993 			{
4994 			const mDNSu32 slot = HashSlot(&pktq.qname);
4995 			CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
4996 			CacheRecord *rr;
4997 
4998 			// Make a list indicating which of our own cache records we expect to see updated as a result of this query
4999 			// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
5000 			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5001 				if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
5002 					if (!rr->NextInKAList && eap != &rr->NextInKAList)
5003 						{
5004 						*eap = rr;
5005 						eap = &rr->NextInKAList;
5006 						if (rr->MPUnansweredQ == 0 || m->timenow - rr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
5007 							{
5008 							// Although MPUnansweredQ is only really used for multi-packet query processing,
5009 							// we increment it for both single-packet and multi-packet queries, so that it stays in sync
5010 							// with the MPUnansweredKA value, which by necessity is incremented for both query types.
5011 							rr->MPUnansweredQ++;
5012 							rr->MPLastUnansweredQT = m->timenow;
5013 							rr->MPExpectingKA = mDNStrue;
5014 							}
5015 						}
5016 
5017 			// Check if this question is the same as any of mine.
5018 			// We only do this for non-truncated queries. Right now it would be too complicated to try
5019 			// to keep track of duplicate suppression state between multiple packets, especially when we
5020 			// can't guarantee to receive all of the Known Answer packets that go with a particular query.
5021 			if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5022 				for (q = m->Questions; q; q=q->next)
5023 					if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
5024 						if (!q->InterfaceID || q->InterfaceID == InterfaceID)
5025 							if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
5026 								if (q->qtype == pktq.qtype &&
5027 									q->qclass == pktq.qclass &&
5028 									q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
5029 									{ *dqp = q; dqp = &q->NextInDQList; }
5030 			}
5031 		}
5032 
5033 	// ***
5034 	// *** 2. Now we can safely build the list of marked answers
5035 	// ***
5036 	for (rr = m->ResourceRecords; rr; rr=rr->next)				// Now build our list of potential answers
5037 		if (rr->NR_AnswerTo)									// If we marked the record...
5038 			AddRecordToResponseList(&nrp, rr, mDNSNULL);		// ... add it to the list
5039 
5040 	// ***
5041 	// *** 3. Add additional records
5042 	// ***
5043 	AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
5044 
5045 	// ***
5046 	// *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
5047 	// ***
5048 	for (i=0; i<query->h.numAnswers; i++)						// For each record in the query's answer section...
5049 		{
5050 		// Get the record...
5051 		AuthRecord *rr;
5052 		CacheRecord *ourcacherr;
5053 		ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
5054 		if (!ptr) goto exit;
5055 
5056 		// See if this Known-Answer suppresses any of our currently planned answers
5057 		for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5058 			if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5059 				{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5060 
5061 		// See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
5062 		for (rr=m->ResourceRecords; rr; rr=rr->next)
5063 			{
5064 			// If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
5065 			if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
5066 				{
5067 				if (srcaddr->type == mDNSAddrType_IPv4)
5068 					{
5069 					if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
5070 					}
5071 				else if (srcaddr->type == mDNSAddrType_IPv6)
5072 					{
5073 					if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
5074 					}
5075 				if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
5076 					{
5077 					rr->ImmedAnswer  = mDNSNULL;
5078 					rr->ImmedUnicast = mDNSfalse;
5079 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5080 					LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
5081 #endif
5082 					}
5083 				}
5084 			}
5085 
5086 		// See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
5087 		// 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).
5088 		ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
5089 		if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
5090 			{
5091 			ourcacherr->MPUnansweredKA++;
5092 			ourcacherr->MPExpectingKA = mDNSfalse;
5093 			}
5094 
5095 		// Having built our ExpectedAnswers list from the questions in this packet, we can definitively
5096 		// remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
5097 		// For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
5098 		eap = &ExpectedAnswers;
5099 		while (*eap)
5100 			{
5101 			CacheRecord *rr = *eap;
5102 			if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5103 				{ *eap = rr->NextInKAList; rr->NextInKAList = mDNSNULL; }
5104 			else eap = &rr->NextInKAList;
5105 			}
5106 
5107 		// See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
5108 		if (!ourcacherr)
5109 			{
5110 			dqp = &DupQuestions;
5111 			while (*dqp)
5112 				{
5113 				DNSQuestion *q = *dqp;
5114 				if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
5115 					{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
5116 				else dqp = &q->NextInDQList;
5117 				}
5118 			}
5119 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5120 		}
5121 
5122 	// ***
5123 	// *** 5. Cancel any additionals that were added because of now-deleted records
5124 	// ***
5125 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5126 		if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
5127 			{ rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
5128 
5129 	// ***
5130 	// *** 6. Mark the send flags on the records we plan to send
5131 	// ***
5132 	for (rr=ResponseRecords; rr; rr=rr->NextResponse)
5133 		{
5134 		if (rr->NR_AnswerTo)
5135 			{
5136 			mDNSBool SendMulticastResponse = mDNSfalse;		// Send modern multicast response
5137 			mDNSBool SendUnicastResponse   = mDNSfalse;		// Send modern unicast response (not legacy unicast response)
5138 
5139 			// If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
5140 			if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
5141 				{
5142 				SendMulticastResponse = mDNStrue;
5143 				// If this record was marked for modern (delayed) unicast response, then mark it as promoted to
5144 				// multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
5145 				// If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
5146 				if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
5147 				}
5148 
5149 			// If the client insists on a multicast response, then we'd better send one
5150 			if      (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
5151 			else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse   = mDNStrue;
5152 			else if (rr->NR_AnswerTo)                SendLegacyResponse    = mDNStrue;
5153 
5154 			if (SendMulticastResponse || SendUnicastResponse)
5155 				{
5156 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5157 				rr->ImmedAnswerMarkTime = m->timenow;
5158 #endif
5159 				m->NextScheduledResponse = m->timenow;
5160 				// If we're already planning to send this on another interface, just send it on all interfaces
5161 				if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
5162 					rr->ImmedAnswer = mDNSInterfaceMark;
5163 				else
5164 					{
5165 					rr->ImmedAnswer = InterfaceID;			// Record interface to send it on
5166 					if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
5167 					if (srcaddr->type == mDNSAddrType_IPv4)
5168 						{
5169 						if      (mDNSIPv4AddressIsZero(rr->v4Requester))                rr->v4Requester = srcaddr->ip.v4;
5170 						else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
5171 						}
5172 					else if (srcaddr->type == mDNSAddrType_IPv6)
5173 						{
5174 						if      (mDNSIPv6AddressIsZero(rr->v6Requester))                rr->v6Requester = srcaddr->ip.v6;
5175 						else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
5176 						}
5177 					}
5178 				}
5179 			// If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
5180 			// so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
5181 			// else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
5182 			// else, for a simple unique record reply, we can reply immediately; no need for delay
5183 			if      (query->h.flags.b[0] & kDNSFlag0_TC)            delayresponse = mDNSPlatformOneSecond * 20;	// Divided by 50 = 400ms
5184 			else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond;		// Divided by 50 = 20ms
5185 			}
5186 		else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
5187 			{
5188 			// Since additional records are an optimization anyway, we only ever send them on one interface at a time
5189 			// If two clients on different interfaces do queries that invoke the same optional additional answer,
5190 			// then the earlier client is out of luck
5191 			rr->ImmedAdditional = InterfaceID;
5192 			// No need to set m->NextScheduledResponse here
5193 			// We'll send these additional records when we send them, or not, as the case may be
5194 			}
5195 		}
5196 
5197 	// ***
5198 	// *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
5199 	// ***
5200 	if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
5201 		{
5202 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5203 		mDNSs32 oldss = m->SuppressSending;
5204 		if (oldss && delayresponse)
5205 			LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
5206 #endif
5207 		// Pick a random delay:
5208 		// We start with the base delay chosen above (typically either 1 second or 20 seconds),
5209 		// and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
5210 		// This is an integer value, with resolution determined by the platform clock rate.
5211 		// We then divide that by 50 to get the delay value in ticks. We defer the division until last
5212 		// to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
5213 		// The +49 before dividing is to ensure we round up, not down, to ensure that even
5214 		// on platforms where the native clock rate is less than fifty ticks per second,
5215 		// we still guarantee that the final calculated delay is at least one platform tick.
5216 		// We want to make sure we don't ever allow the delay to be zero ticks,
5217 		// because if that happens we'll fail the Bonjour Conformance Test.
5218 		// Our final computed delay is 20-120ms for normal delayed replies,
5219 		// or 400-500ms in the case of multi-packet known-answer lists.
5220 		m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
5221 		if (m->SuppressSending == 0) m->SuppressSending = 1;
5222 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
5223 		if (oldss && delayresponse)
5224 			LogMsg("Set     SuppressSending to   %5ld", m->SuppressSending - m->timenow);
5225 #endif
5226 		}
5227 
5228 	// ***
5229 	// *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
5230 	// ***
5231 	if (SendLegacyResponse)
5232 		responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
5233 
5234 exit:
5235 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5236 
5237 	// ***
5238 	// *** 9. Finally, clear our link chains ready for use next time
5239 	// ***
5240 	while (ResponseRecords)
5241 		{
5242 		rr = ResponseRecords;
5243 		ResponseRecords = rr->NextResponse;
5244 		rr->NextResponse    = mDNSNULL;
5245 		rr->NR_AnswerTo     = mDNSNULL;
5246 		rr->NR_AdditionalTo = mDNSNULL;
5247 		}
5248 
5249 	while (ExpectedAnswers)
5250 		{
5251 		CacheRecord *rr;
5252 		rr = ExpectedAnswers;
5253 		ExpectedAnswers = rr->NextInKAList;
5254 		rr->NextInKAList = mDNSNULL;
5255 
5256 		// For non-truncated queries, we can definitively say that we should expect
5257 		// to be seeing a response for any records still left in the ExpectedAnswers list
5258 		if (!(query->h.flags.b[0] & kDNSFlag0_TC))
5259 			if (rr->UnansweredQueries == 0 || m->timenow - rr->LastUnansweredTime >= mDNSPlatformOneSecond)
5260 				{
5261 				rr->UnansweredQueries++;
5262 				rr->LastUnansweredTime = m->timenow;
5263 				if (rr->UnansweredQueries > 1)
5264 					debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
5265 						rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5266 				SetNextCacheCheckTime(m, rr);
5267 				}
5268 
5269 		// If we've seen multiple unanswered queries for this record,
5270 		// then mark it to expire in five seconds if we don't get a response by then.
5271 		if (rr->UnansweredQueries >= MaxUnansweredQueries)
5272 			{
5273 			// Only show debugging message if this record was not about to expire anyway
5274 			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5275 				debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5276 					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5277 			mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5278 			}
5279 		// Make a guess, based on the multi-packet query / known answer counts, whether we think we
5280 		// should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
5281 		// possible packet loss of up to 20% of the additional KA packets.)
5282 		else if (rr->MPUnansweredQ * 4 > rr->MPUnansweredKA * 5 + 8)
5283 			{
5284 			// We want to do this conservatively.
5285 			// If there are so many machines on the network that they have to use multi-packet known-answer lists,
5286 			// then we don't want them to all hit the network simultaneously with their final expiration queries.
5287 			// By setting the record to expire in four minutes, we achieve two things:
5288 			// (a) the 90-95% final expiration queries will be less bunched together
5289 			// (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
5290 			mDNSu32 remain = (mDNSu32)(RRExpireTime(rr) - m->timenow) / 4;
5291 			if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
5292 				remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
5293 
5294 			// Only show debugging message if this record was not about to expire anyway
5295 			if (RRExpireTime(rr) - m->timenow > 4 * mDNSPlatformOneSecond)
5296 				debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
5297 					rr->UnansweredQueries, rr->MPUnansweredQ, rr->MPUnansweredKA, CRDisplayString(m, rr));
5298 
5299 			if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
5300 				rr->UnansweredQueries++;	// Treat this as equivalent to one definite unanswered query
5301 			rr->MPUnansweredQ  = 0;			// Clear MPQ/MPKA statistics
5302 			rr->MPUnansweredKA = 0;
5303 			rr->MPExpectingKA  = mDNSfalse;
5304 
5305 			if (remain < kDefaultReconfirmTimeForNoAnswer)
5306 				remain = kDefaultReconfirmTimeForNoAnswer;
5307 			mDNS_Reconfirm_internal(m, rr, remain);
5308 			}
5309 		}
5310 
5311 	while (DupQuestions)
5312 		{
5313 		int i;
5314 		DNSQuestion *q = DupQuestions;
5315 		DupQuestions = q->NextInDQList;
5316 		q->NextInDQList = mDNSNULL;
5317 		i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
5318 		debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
5319 			srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
5320 		}
5321 
5322 	return(responseptr);
5323 	}
5324 
mDNSCoreReceiveQuery(mDNS * const m,const DNSMessage * const msg,const mDNSu8 * const end,const mDNSAddr * srcaddr,const mDNSIPPort srcport,const mDNSAddr * dstaddr,mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5325 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
5326 	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5327 	const mDNSInterfaceID InterfaceID)
5328 	{
5329 	mDNSu8    *responseend = mDNSNULL;
5330 	mDNSBool   QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
5331 
5332 	if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
5333 		{
5334 		LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5335 			"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
5336 			srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5337 			msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
5338 			msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
5339 			msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
5340 			msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5341 		return;
5342 		}
5343 
5344 	verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
5345 		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5346 		srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
5347 		msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
5348 		msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
5349 		msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
5350 		msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
5351 
5352 	responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
5353 		(srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
5354 
5355 	if (responseend)	// If responseend is non-null, that means we built a unicast response packet
5356 		{
5357 		debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
5358 			m->omsg.h.numQuestions,   m->omsg.h.numQuestions   == 1 ? "" : "s",
5359 			m->omsg.h.numAnswers,     m->omsg.h.numAnswers     == 1 ? "" : "s",
5360 			m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
5361 			srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
5362 		mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
5363 		}
5364 	}
5365 
5366 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
5367 // the record list and/or question list.
5368 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSCoreReceiveResponse(mDNS * const m,const DNSMessage * const response,const mDNSu8 * end,const mDNSAddr * srcaddr,const mDNSIPPort srcport,const mDNSAddr * dstaddr,mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5369 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
5370 	const DNSMessage *const response, const mDNSu8 *end,
5371 	const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
5372 	const mDNSInterfaceID InterfaceID)
5373 	{
5374 	int i;
5375 
5376 	// We ignore questions (if any) in a DNS response packet
5377 	const mDNSu8 *ptr = LocateAnswers(response, end);
5378 
5379 	// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
5380 	// We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
5381 	// set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
5382 	CacheRecord *CacheFlushRecords = (CacheRecord*)1;
5383 	CacheRecord **cfp = &CacheFlushRecords;
5384 
5385 	// All records in a DNS response packet are treated as equally valid statements of truth. If we want
5386 	// to guard against spoof responses, then the only credible protection against that is cryptographic
5387 	// security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
5388 	int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
5389 
5390 	(void)srcaddr;	// Currently used only for display in debugging message
5391 	(void)srcport;
5392 	(void)dstport;
5393 
5394 	verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with "
5395 		"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
5396 		srcaddr, dstaddr, InterfaceID,
5397 		response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
5398 		response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
5399 		response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
5400 		response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
5401 
5402 	// If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
5403 	if (!mDNSAddrIsDNSMulticast(dstaddr))
5404 		{
5405 		if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
5406 			return;
5407 		// For now we don't put standard wide-area unicast responses in our main cache
5408 		// (Later we should fix this and cache all known results in a unified manner.)
5409 		if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
5410 			return;
5411 		}
5412 
5413 	for (i = 0; i < totalrecords && ptr && ptr < end; i++)
5414 		{
5415 		const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
5416 		ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
5417 		if (!ptr) goto exit;		// Break out of the loop and clean up our CacheFlushRecords list before exiting
5418 
5419 		// 1. Check that this packet resource record does not conflict with any of ours
5420 		if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
5421 		m->CurrentRecord = m->ResourceRecords;
5422 		while (m->CurrentRecord)
5423 			{
5424 			AuthRecord *rr = m->CurrentRecord;
5425 			m->CurrentRecord = rr->next;
5426 			if (PacketRRMatchesSignature(&m->rec.r, rr))		// If interface, name, type (if shared record) and class match...
5427 				{
5428 				// ... check to see if type and rdata are identical
5429 				if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
5430 					{
5431 					// If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
5432 					if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
5433 						{
5434 						// If we were planning to send on this -- and only this -- interface, then we don't need to any more
5435 						if      (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
5436 						}
5437 					else
5438 						{
5439 						if      (rr->ImmedAnswer == mDNSNULL)    { rr->ImmedAnswer = InterfaceID;       m->NextScheduledResponse = m->timenow; }
5440 						else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5441 						}
5442 					}
5443 				// else, the packet RR has different type or different rdata -- check to see if this is a conflict
5444 				else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
5445 					{
5446 					debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->     resrec.rdatahash, ARDisplayString(m, rr));
5447 					debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
5448 
5449 					// If this record is marked DependentOn another record for conflict detection purposes,
5450 					// then *that* record has to be bumped back to probing state to resolve the conflict
5451 					while (rr->DependentOn) rr = rr->DependentOn;
5452 
5453 					// If we've just whacked this record's ProbeCount, don't need to do it again
5454 					if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
5455 						{
5456 						// If we'd previously verified this record, put it back to probing state and try again
5457 						if (rr->resrec.RecordType == kDNSRecordTypeVerified)
5458 							{
5459 							debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5460 							rr->resrec.RecordType     = kDNSRecordTypeUnique;
5461 							rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
5462 							rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
5463 							InitializeLastAPTime(m, rr);
5464 							RecordProbeFailure(m, rr);	// Repeated late conflicts also cause us to back off to the slower probing rate
5465 							}
5466 						// If we're probing for this record, we just failed
5467 						else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
5468 							{
5469 							debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5470 							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5471 							}
5472 						// We assumed this record must be unique, but we were wrong.
5473 						// (e.g. There are two mDNSResponders on the same machine giving
5474 						// different answers for the reverse mapping record.)
5475 						// This is simply a misconfiguration, and we don't try to recover from it.
5476 						else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
5477 							{
5478 							debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
5479 								rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5480 							mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
5481 							}
5482 						else
5483 							debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
5484 								rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
5485 						}
5486 					}
5487 				// Else, matching signature, different type or rdata, but not a considered a conflict.
5488 				// If the packet record has the cache-flush bit set, then we check to see if we
5489 				// have any record(s) of the same type that we should re-assert to rescue them
5490 				// (see note about "multi-homing and bridged networks" at the end of this function).
5491 				else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
5492 					if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
5493 						{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
5494 				}
5495 			}
5496 
5497 		// 2. See if we want to add this packet resource record to our cache
5498 		if (m->rrcache_size)	// Only try to cache answers if we have a cache to put them in
5499 			{
5500 			const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
5501 			CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
5502 			CacheRecord *rr;
5503 			// 2a. Check if this packet resource record is already in our cache
5504 			for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5505 				{
5506 				// If we found this exact resource record, refresh its TTL
5507 				if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
5508 					{
5509 					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5510 						verbosedebugf("Found record size %5d interface %p already in cache: %s",
5511 							m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
5512 					rr->TimeRcvd  = m->timenow;
5513 
5514 					if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5515 						{
5516 						// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
5517 						if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
5518 							{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5519 
5520 						// If this packet record is marked unique, and our previous cached copy was not, then fix it
5521 						if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
5522 							{
5523 							DNSQuestion *q;
5524 							for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
5525 							rr->resrec.RecordType = m->rec.r.resrec.RecordType;
5526 							}
5527 						}
5528 
5529 					if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
5530 						{
5531 						// If the rdata of the packet record differs in name capitalization from the record in our cache
5532 						// then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
5533 						// a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
5534 						rr->resrec.rroriginalttl = 0;
5535 						rr->UnansweredQueries = MaxUnansweredQueries;
5536 						SetNextCacheCheckTime(m, rr);
5537 						// DO NOT break out here -- we want to continue as if we never found it
5538 						}
5539 					else if (m->rec.r.resrec.rroriginalttl > 0)
5540 						{
5541 						rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
5542 						rr->UnansweredQueries = 0;
5543 						rr->MPUnansweredQ     = 0;
5544 						rr->MPUnansweredKA    = 0;
5545 						rr->MPExpectingKA     = mDNSfalse;
5546 						SetNextCacheCheckTime(m, rr);
5547 						break;
5548 						}
5549 					else
5550 						{
5551 						// If the packet TTL is zero, that means we're deleting this record.
5552 						// To give other hosts on the network a chance to protest, we push the deletion
5553 						// out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
5554 						// Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
5555 						// lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
5556 						rr->resrec.rroriginalttl = 1;
5557 						rr->UnansweredQueries = MaxUnansweredQueries;
5558 						SetNextCacheCheckTime(m, rr);
5559 						break;
5560 						}
5561 					}
5562 				}
5563 
5564 			// If packet resource record not in our cache, add it now
5565 			// (unless it is just a deletion of a record we never had, in which case we don't care)
5566 			if (!rr && m->rec.r.resrec.rroriginalttl > 0)
5567 				{
5568 				// If we don't have a CacheGroup for this name, make one now
5569 				if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
5570 				if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength);	// Make a cache record, being careful not to recycle cg
5571 				if (!rr) NoCacheAnswer(m, &m->rec.r);
5572 				else
5573 					{
5574 					RData *saveptr = rr->resrec.rdata;		// Save the rr->resrec.rdata pointer
5575 					*rr = m->rec.r;							// Block copy the CacheRecord object
5576 					rr->resrec.rdata = saveptr;				// Restore rr->resrec.rdata after the structure assignment
5577 					rr->resrec.name  = cg->name;			// And set rr->resrec.name to point into our CacheGroup header
5578 					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
5579 						{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
5580 					// If this is an oversized record with external storage allocated, copy rdata to external storage
5581 					if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
5582 						LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
5583 					if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
5584 						mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
5585 					rr->next = mDNSNULL;					// Clear 'next' pointer
5586 					*(cg->rrcache_tail) = rr;				// Append this record to tail of cache slot list
5587 					cg->rrcache_tail = &(rr->next);			// Advance tail pointer
5588 					if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)	// If marked unique, assume we may have
5589 						rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond;	// to delay delivery of this 'add' event
5590 					else
5591 						rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
5592 					CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
5593 					}
5594 				}
5595 			}
5596 		m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5597 		}
5598 
5599 exit:
5600 	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
5601 
5602 	// If we've just received one or more records with their cache flush bits set,
5603 	// then scan that cache slot to see if there are any old stale records we need to flush
5604 	while (CacheFlushRecords != (CacheRecord*)1)
5605 		{
5606 		CacheRecord *r1 = CacheFlushRecords, *r2;
5607 		const mDNSu32 slot = HashSlot(r1->resrec.name);
5608 		CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
5609 		CacheFlushRecords = CacheFlushRecords->NextInCFList;
5610 		r1->NextInCFList = mDNSNULL;
5611 		for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
5612 			if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
5613 				{
5614 				// If record was recently positively received
5615 				// (i.e. not counting goodbye packets or cache flush events that set the TTL to 1)
5616 				// then we need to ensure the whole RRSet has the same TTL (as required by DNS semantics)
5617 				if (r2->resrec.rroriginalttl > 1 && m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
5618 					{
5619 					if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl)
5620 						LogMsg("Correcting TTL from %4d to %4d for %s",
5621 							r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
5622 					r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
5623 					r2->TimeRcvd = m->timenow;
5624 					}
5625 				else				// else, if record is old, mark it to be flushed
5626 					{
5627 					verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
5628 					// We set stale records to expire in one second.
5629 					// This gives the owner a chance to rescue it if necessary.
5630 					// This is important in the case of multi-homing and bridged networks:
5631 					//   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
5632 					//   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
5633 					//   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
5634 					//   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
5635 					//   By delaying the deletion by one second, we give X a change to notice that this bridging has
5636 					//   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
5637 					// We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
5638 					// final expiration queries for this record.
5639 					r2->resrec.rroriginalttl = 1;
5640 					r2->TimeRcvd          = m->timenow;
5641 					r2->UnansweredQueries = MaxUnansweredQueries;
5642 					}
5643 				SetNextCacheCheckTime(m, r2);
5644 				}
5645 		if (r1->DelayDelivery)	// If we were planning to delay delivery of this record, see if we still need to
5646 			{
5647 			// Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
5648 			r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
5649 			if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
5650 			}
5651 		}
5652 	}
5653 
mDNSCoreReceive(mDNS * const m,void * const pkt,const mDNSu8 * const end,const mDNSAddr * const srcaddr,const mDNSIPPort srcport,const mDNSAddr * const dstaddr,const mDNSIPPort dstport,const mDNSInterfaceID InterfaceID)5654 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
5655 	const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
5656 	const mDNSInterfaceID InterfaceID)
5657 	{
5658 	DNSMessage  *msg  = (DNSMessage *)pkt;
5659 	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
5660 	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
5661 	mDNSu8 QR_OP;
5662 	mDNSu8 *ptr = mDNSNULL;
5663 	const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
5664 
5665 #ifndef UNICAST_DISABLED
5666 	if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
5667 		{
5668 		mDNS_Lock(m);
5669 		uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
5670 		mDNS_Unlock(m);
5671 		return;
5672 		}
5673 #endif
5674 	if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
5675 	QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
5676 	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
5677 	ptr = (mDNSu8 *)&msg->h.numQuestions;
5678 	msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
5679 	msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
5680 	msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
5681 	msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
5682 
5683 	if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
5684 
5685 	// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
5686 	// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
5687 	if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
5688 
5689 	mDNS_Lock(m);
5690 	m->PktNum++;
5691 #ifndef UNICAST_DISABLED
5692 	if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
5693 		uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5694 		// Note: mDNSCore also needs to get access to received unicast responses
5695 #endif
5696 	if      (QR_OP == StdQ) mDNSCoreReceiveQuery   (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5697 	else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
5698 	else if (QR_OP != UpdateR)
5699 		LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
5700 			msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
5701 
5702 	// Packet reception often causes a change to the task list:
5703 	// 1. Inbound queries can cause us to need to send responses
5704 	// 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
5705 	// 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
5706 	// 4. Response packets that answer questions may cause our client to issue new questions
5707 	mDNS_Unlock(m);
5708 	}
5709 
5710 // ***************************************************************************
5711 #if COMPILER_LIKES_PRAGMA_MARK
5712 #pragma mark -
5713 #pragma mark -
5714 #pragma mark - Searcher Functions
5715 #endif
5716 
5717 #define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
5718 
FindDuplicateQuestion(const mDNS * const m,const DNSQuestion * const question)5719 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
5720 	{
5721 	DNSQuestion *q;
5722 	// Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
5723 	// This prevents circular references, where two questions are each marked as a duplicate of the other.
5724 	// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
5725 	// further in the list.
5726 	for (q = m->Questions; q && q != question; q=q->next)		// Scan our list of questions
5727 		if (q->InterfaceID == question->InterfaceID &&			// for another question with the same InterfaceID,
5728 			SameQTarget(q, question)                &&			// and same unicast/multicast target settings
5729 			q->qtype       == question->qtype       &&			// type,
5730 			q->qclass      == question->qclass      &&			// class,
5731 			q->qnamehash   == question->qnamehash   &&
5732 			SameDomainName(&q->qname, &question->qname))		// and name
5733 			return(q);
5734 	return(mDNSNULL);
5735 	}
5736 
5737 // This is called after a question is deleted, in case other identical questions were being
5738 // suppressed as duplicates
UpdateQuestionDuplicates(mDNS * const m,const DNSQuestion * const question)5739 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question)
5740 	{
5741 	DNSQuestion *q;
5742 	for (q = m->Questions; q; q=q->next)		// Scan our list of questions
5743 		if (q->DuplicateOf == question)			// To see if any questions were referencing this as their duplicate
5744 			{
5745 			q->ThisQInterval    = question->ThisQInterval;
5746 			q->RequestUnicast   = question->RequestUnicast;
5747 			q->LastQTime        = question->LastQTime;
5748 			q->RecentAnswerPkts = 0;
5749 			q->DuplicateOf      = FindDuplicateQuestion(m, q);
5750 			q->LastQTxTime      = question->LastQTxTime;
5751 			SetNextQueryTime(m,q);
5752 			}
5753 	}
5754 
5755 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
5756 	((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
5757 
mDNS_StartQuery_internal(mDNS * const m,DNSQuestion * const question)5758 mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
5759 	{
5760 	if (question->Target.type && !ValidQuestionTarget(question))
5761 		{
5762 		LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
5763 			question->Target.type, mDNSVal16(question->TargetPort));
5764 		question->Target.type = mDNSAddrType_None;
5765 		}
5766 
5767 	if (!question->Target.type)		// No question->Target specified, so clear TargetPort and TargetQID
5768 		{
5769 		question->TargetPort = zeroIPPort;
5770 		question->TargetQID  = zeroID;
5771 		}
5772 
5773 #ifndef UNICAST_DISABLED
5774 	// If the client has specified 'kDNSServiceFlagsForceMulticast'
5775 	// then we do a multicast query on that interface, even for unicast domains.
5776     if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5777     	question->uDNS_info.id = zeroID;
5778     else return uDNS_StartQuery(m, question);
5779 #else
5780     question->uDNS_info.id = zeroID;
5781 #endif // UNICAST_DISABLED
5782 
5783 	//LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5784 
5785 	if (m->rrcache_size == 0)	// Can't do queries if we have no cache space allocated
5786 		return(mStatus_NoCache);
5787 	else
5788 		{
5789 		int i;
5790 		// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
5791 		DNSQuestion **q = &m->Questions;
5792 		if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5793 		while (*q && *q != question) q=&(*q)->next;
5794 
5795 		if (*q)
5796 			{
5797 			LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
5798 				question->qname.c, DNSTypeName(question->qtype));
5799 			return(mStatus_AlreadyRegistered);
5800 			}
5801 
5802 		// If this question is referencing a specific interface, verify it exists
5803 		if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
5804 			{
5805 			NetworkInterfaceInfo *intf;
5806 			for (intf = m->HostInterfaces; intf; intf = intf->next)
5807 				if (intf->InterfaceID == question->InterfaceID) break;
5808 			if (!intf)
5809 				LogMsg("Note: InterfaceID %p for question %##s not currently found in active interface list",
5810 					question->InterfaceID, question->qname.c);
5811 			}
5812 
5813 		if (!ValidateDomainName(&question->qname))
5814 			{
5815 			LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5816 			return(mStatus_Invalid);
5817 			}
5818 
5819 		// Note: In the case where we already have the answer to this question in our cache, that may be all the client
5820 		// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
5821 		// be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
5822 		// that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
5823 		if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
5824 
5825 		question->next              = mDNSNULL;
5826 		question->qnamehash         = DomainNameHashValue(&question->qname);	// MUST do this before FindDuplicateQuestion()
5827 		question->DelayAnswering    = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
5828 		question->ThisQInterval     = InitialQuestionInterval * 2;			// MUST be > zero for an active question
5829 		question->RequestUnicast    = 2;										// Set to 2 because is decremented once *before* we check it
5830 		question->LastQTime         = m->timenow - m->RandomQueryDelay;		// Avoid inter-machine synchronization
5831 		question->LastAnswerPktNum  = m->PktNum;
5832 		question->RecentAnswerPkts  = 0;
5833 		question->CurrentAnswers    = 0;
5834 		question->LargeAnswers      = 0;
5835 		question->UniqueAnswers     = 0;
5836 		question->FlappingInterface = mDNSNULL;
5837 		question->DuplicateOf       = FindDuplicateQuestion(m, question);
5838 		question->NextInDQList      = mDNSNULL;
5839 		for (i=0; i<DupSuppressInfoSize; i++)
5840 			question->DupSuppress[i].InterfaceID = mDNSNULL;
5841 		// question->InterfaceID must be already set by caller
5842 		question->SendQNow          = mDNSNULL;
5843 		question->SendOnAll         = mDNSfalse;
5844 		question->LastQTxTime       = m->timenow;
5845 
5846 		if (!question->DuplicateOf)
5847 			verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started",
5848 				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5849 				question->LastQTime + question->ThisQInterval - m->timenow, question);
5850 		else
5851 			verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)",
5852 				question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
5853 				question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
5854 
5855 		*q = question;
5856 		if (question->InterfaceID == mDNSInterface_LocalOnly)
5857 			{
5858 			if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
5859 			}
5860 		else
5861 			{
5862 			if (!m->NewQuestions) m->NewQuestions = question;
5863 			SetNextQueryTime(m,question);
5864 			}
5865 
5866 		return(mStatus_NoError);
5867 		}
5868 	}
5869 
mDNS_StopQuery_internal(mDNS * const m,DNSQuestion * const question)5870 mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
5871 	{
5872 	const mDNSu32 slot = HashSlot(&question->qname);
5873 	CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
5874 	CacheRecord *rr;
5875 	DNSQuestion **q = &m->Questions;
5876 
5877     if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
5878 
5879 	if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5880 	while (*q && *q != question) q=&(*q)->next;
5881 	if (*q) *q = (*q)->next;
5882 	else
5883 		{
5884 		if (question->ThisQInterval >= 0)	// Only log error message if the query was supposed to be active
5885 			LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
5886 				question->qname.c, DNSTypeName(question->qtype));
5887 		return(mStatus_BadReferenceErr);
5888 		}
5889 
5890 	// Take care to cut question from list *before* calling UpdateQuestionDuplicates
5891 	UpdateQuestionDuplicates(m, question);
5892 	// But don't trash ThisQInterval until afterwards.
5893 	question->ThisQInterval = -1;
5894 
5895 	// If there are any cache records referencing this as their active question, then see if any other
5896 	// question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
5897 	for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5898 		{
5899 		if (rr->CRActiveQuestion == question)
5900 			{
5901 			DNSQuestion *q;
5902 			for (q = m->Questions; q; q=q->next)		// Scan our list of questions
5903 				if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
5904 					break;
5905 			verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p",
5906 				rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
5907 			rr->CRActiveQuestion = q;		// Question used to be active; new value may or may not be null
5908 			if (!q) m->rrcache_active--;	// If no longer active, decrement rrcache_active count
5909 			}
5910 		}
5911 
5912 	// If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at,
5913 	// bump its pointer forward one question.
5914 	if (m->CurrentQuestion == question)
5915 		{
5916 		debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
5917 			question->qname.c, DNSTypeName(question->qtype));
5918 		m->CurrentQuestion = question->next;
5919 		}
5920 
5921 	if (m->NewQuestions == question)
5922 		{
5923 		debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
5924 			question->qname.c, DNSTypeName(question->qtype));
5925 		m->NewQuestions = question->next;
5926 		}
5927 
5928 	if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
5929 
5930 	// Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
5931 	question->next = mDNSNULL;
5932 	return(mStatus_NoError);
5933 	}
5934 
mDNS_StartQuery(mDNS * const m,DNSQuestion * const question)5935 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
5936 	{
5937 	mStatus status;
5938 	mDNS_Lock(m);
5939 	status = mDNS_StartQuery_internal(m, question);
5940 	mDNS_Unlock(m);
5941 	return(status);
5942 	}
5943 
mDNS_StopQuery(mDNS * const m,DNSQuestion * const question)5944 mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
5945 	{
5946 	mStatus status;
5947 	mDNS_Lock(m);
5948 	status = mDNS_StopQuery_internal(m, question);
5949 	mDNS_Unlock(m);
5950 	return(status);
5951 	}
5952 
mDNS_Reconfirm(mDNS * const m,CacheRecord * const rr)5953 mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr)
5954 	{
5955 	mStatus status;
5956 	mDNS_Lock(m);
5957 	status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
5958 	mDNS_Unlock(m);
5959 	return(status);
5960 	}
5961 
mDNS_ReconfirmByValue(mDNS * const m,ResourceRecord * const rr)5962 mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
5963 	{
5964 	mStatus status = mStatus_BadReferenceErr;
5965 	CacheRecord *cr;
5966 	mDNS_Lock(m);
5967 	cr = FindIdenticalRecordInCache(m, rr);
5968 	if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5969 	mDNS_Unlock(m);
5970 	return(status);
5971 	}
5972 
mDNS_StartBrowse(mDNS * const m,DNSQuestion * const question,const domainname * const srv,const domainname * const domain,const mDNSInterfaceID InterfaceID,mDNSBool ForceMCast,mDNSQuestionCallback * Callback,void * Context)5973 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
5974 	const domainname *const srv, const domainname *const domain,
5975 	const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
5976 	{
5977 	question->InterfaceID      = InterfaceID;
5978 	question->Target           = zeroAddr;
5979 	question->qtype            = kDNSType_PTR;
5980 	question->qclass           = kDNSClass_IN;
5981 	question->LongLived        = mDNSfalse;
5982 	question->ExpectUnique     = mDNSfalse;
5983 	question->ForceMCast       = ForceMCast;
5984 	question->QuestionCallback = Callback;
5985 	question->QuestionContext  = Context;
5986 	if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
5987 
5988 #ifndef UNICAST_DISABLED
5989     if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
5990     	{
5991 		question->LongLived = mDNSfalse;
5992 		question->uDNS_info.id = zeroID;
5993 		return(mDNS_StartQuery(m, question));
5994 		}
5995 	else
5996 		{
5997 		mStatus status;
5998 		// Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
5999 		mDNS_Lock(m);
6000 		question->LongLived = mDNStrue;
6001 		status = uDNS_StartQuery(m, question);
6002 		mDNS_Unlock(m);
6003 		return(status);
6004 		}
6005 #else
6006 	return(mDNS_StartQuery(m, question));
6007 #endif // UNICAST_DISABLED
6008 	}
6009 
MachineHasActiveIPv6(mDNS * const m)6010 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
6011 	{
6012 	NetworkInterfaceInfo *intf;
6013 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6014 	if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
6015 	return(mDNSfalse);
6016 	}
6017 
FoundServiceInfoSRV(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6018 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6019 	{
6020 	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6021 	mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger);
6022 	if (!AddRecord) return;
6023 	if (answer->rrtype != kDNSType_SRV) return;
6024 
6025 	query->info->port = answer->rdata->u.srv.port;
6026 
6027 	// If this is our first answer, then set the GotSRV flag and start the address query
6028 	if (!query->GotSRV)
6029 		{
6030 		query->GotSRV             = mDNStrue;
6031 		query->qAv4.InterfaceID   = answer->InterfaceID;
6032 		AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6033 		query->qAv6.InterfaceID   = answer->InterfaceID;
6034 		AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6035 		mDNS_StartQuery(m, &query->qAv4);
6036 		// Only do the AAAA query if this machine actually has IPv6 active
6037 		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6038 		}
6039 	// If this is not our first answer, only re-issue the address query if the target host name has changed
6040 	else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
6041 		!SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
6042 		{
6043 		mDNS_StopQuery(m, &query->qAv4);
6044 		if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
6045 		if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
6046 			{
6047 			// If we get here, it means:
6048 			// 1. This is not our first SRV answer
6049 			// 2. The interface ID is different, but the target host and port are the same
6050 			// This implies that we're seeing the exact same SRV record on more than one interface, so we should
6051 			// make our address queries at least as broad as the original SRV query so that we catch all the answers.
6052 			query->qAv4.InterfaceID = query->qSRV.InterfaceID;	// Will be mDNSInterface_Any, or a specific interface
6053 			query->qAv6.InterfaceID = query->qSRV.InterfaceID;
6054 			}
6055 		else
6056 			{
6057 			query->qAv4.InterfaceID   = answer->InterfaceID;
6058 			AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
6059 			query->qAv6.InterfaceID   = answer->InterfaceID;
6060 			AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
6061 			}
6062 		debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
6063 		mDNS_StartQuery(m, &query->qAv4);
6064 		// Only do the AAAA query if this machine actually has IPv6 active
6065 		if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
6066 		}
6067 	else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
6068 		{
6069 		if (++query->Answers >= 100)
6070 			debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
6071 				query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
6072 				mDNSVal16(answer->rdata->u.srv.port));
6073 		query->ServiceInfoQueryCallback(m, query);
6074 		}
6075 	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6076 	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6077 	}
6078 
FoundServiceInfoTXT(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6079 mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6080 	{
6081 	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6082 	if (!AddRecord) return;
6083 	if (answer->rrtype != kDNSType_TXT) return;
6084 	if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
6085 
6086 	query->GotTXT       = mDNStrue;
6087 	query->info->TXTlen = answer->rdlength;
6088 	query->info->TXTinfo[0] = 0;		// In case answer->rdlength is zero
6089 	mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
6090 
6091 	verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
6092 
6093 	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6094 	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6095 	if (query->ServiceInfoQueryCallback && query->GotADD)
6096 		{
6097 		if (++query->Answers >= 100)
6098 			debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
6099 				query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
6100 		query->ServiceInfoQueryCallback(m, query);
6101 		}
6102 	}
6103 
FoundServiceInfo(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,mDNSBool AddRecord)6104 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
6105 	{
6106 	ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
6107 	//LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
6108 	if (!AddRecord) return;
6109 
6110 	if (answer->rrtype == kDNSType_A)
6111 		{
6112 		query->info->ip.type = mDNSAddrType_IPv4;
6113 		query->info->ip.ip.v4 = answer->rdata->u.ipv4;
6114 		}
6115 	else if (answer->rrtype == kDNSType_AAAA)
6116 		{
6117 		query->info->ip.type = mDNSAddrType_IPv6;
6118 		query->info->ip.ip.v6 = answer->rdata->u.ipv6;
6119 		}
6120 	else
6121 		{
6122 		debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
6123 		return;
6124 		}
6125 
6126 	query->GotADD = mDNStrue;
6127 	query->info->InterfaceID = answer->InterfaceID;
6128 
6129 	verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
6130 
6131 	// CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
6132 	// callback function is allowed to do anything, including deleting this query and freeing its memory.
6133 	if (query->ServiceInfoQueryCallback && query->GotTXT)
6134 		{
6135 		if (++query->Answers >= 100)
6136 			debugf(answer->rrtype == kDNSType_A ?
6137 				"**** WARNING **** have given %lu answers for %##s (A) %.4a" :
6138 				"**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
6139 				query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
6140 		query->ServiceInfoQueryCallback(m, query);
6141 		}
6142 	}
6143 
6144 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
6145 // If the query is not interface-specific, then InterfaceID may be zero
6146 // Each time the Callback is invoked, the remainder of the fields will have been filled in
6147 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
mDNS_StartResolveService(mDNS * const m,ServiceInfoQuery * query,ServiceInfo * info,mDNSServiceInfoQueryCallback * Callback,void * Context)6148 mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
6149 	ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
6150 	{
6151 	mStatus status;
6152 	mDNS_Lock(m);
6153 
6154 	query->qSRV.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6155 	query->qSRV.InterfaceID         = info->InterfaceID;
6156 	query->qSRV.Target              = zeroAddr;
6157 	AssignDomainName(&query->qSRV.qname, &info->name);
6158 	query->qSRV.qtype               = kDNSType_SRV;
6159 	query->qSRV.qclass              = kDNSClass_IN;
6160 	query->qSRV.LongLived           = mDNSfalse;
6161 	query->qSRV.ExpectUnique        = mDNStrue;
6162 	query->qSRV.ForceMCast          = mDNSfalse;
6163 	query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
6164 	query->qSRV.QuestionContext     = query;
6165 
6166 	query->qTXT.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6167 	query->qTXT.InterfaceID         = info->InterfaceID;
6168 	query->qTXT.Target              = zeroAddr;
6169 	AssignDomainName(&query->qTXT.qname, &info->name);
6170 	query->qTXT.qtype               = kDNSType_TXT;
6171 	query->qTXT.qclass              = kDNSClass_IN;
6172 	query->qTXT.LongLived           = mDNSfalse;
6173 	query->qTXT.ExpectUnique        = mDNStrue;
6174 	query->qTXT.ForceMCast          = mDNSfalse;
6175 	query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
6176 	query->qTXT.QuestionContext     = query;
6177 
6178 	query->qAv4.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6179 	query->qAv4.InterfaceID         = info->InterfaceID;
6180 	query->qAv4.Target              = zeroAddr;
6181 	query->qAv4.qname.c[0]          = 0;
6182 	query->qAv4.qtype               = kDNSType_A;
6183 	query->qAv4.qclass              = kDNSClass_IN;
6184 	query->qAv4.LongLived           = mDNSfalse;
6185 	query->qAv4.ExpectUnique        = mDNStrue;
6186 	query->qAv4.ForceMCast          = mDNSfalse;
6187 	query->qAv4.QuestionCallback    = FoundServiceInfo;
6188 	query->qAv4.QuestionContext     = query;
6189 
6190 	query->qAv6.ThisQInterval       = -1;		// So that mDNS_StopResolveService() knows whether to cancel this question
6191 	query->qAv6.InterfaceID         = info->InterfaceID;
6192 	query->qAv6.Target              = zeroAddr;
6193 	query->qAv6.qname.c[0]          = 0;
6194 	query->qAv6.qtype               = kDNSType_AAAA;
6195 	query->qAv6.qclass              = kDNSClass_IN;
6196 	query->qAv6.LongLived           = mDNSfalse;
6197 	query->qAv6.ExpectUnique        = mDNStrue;
6198 	query->qAv6.ForceMCast          = mDNSfalse;
6199 	query->qAv6.QuestionCallback    = FoundServiceInfo;
6200 	query->qAv6.QuestionContext     = query;
6201 
6202 	query->GotSRV                   = mDNSfalse;
6203 	query->GotTXT                   = mDNSfalse;
6204 	query->GotADD                   = mDNSfalse;
6205 	query->Answers                  = 0;
6206 
6207 	query->info                     = info;
6208 	query->ServiceInfoQueryCallback = Callback;
6209 	query->ServiceInfoQueryContext  = Context;
6210 
6211 //	info->name      = Must already be set up by client
6212 //	info->interface = Must already be set up by client
6213 	info->ip        = zeroAddr;
6214 	info->port      = zeroIPPort;
6215 	info->TXTlen    = 0;
6216 
6217 	// We use mDNS_StartQuery_internal here because we're already holding the lock
6218 	status = mDNS_StartQuery_internal(m, &query->qSRV);
6219 	if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
6220 	if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
6221 
6222 	mDNS_Unlock(m);
6223 	return(status);
6224 	}
6225 
mDNS_StopResolveService(mDNS * const m,ServiceInfoQuery * q)6226 mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
6227 	{
6228 	mDNS_Lock(m);
6229 	// We use mDNS_StopQuery_internal here because we're already holding the lock
6230 	if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
6231 	if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
6232 	if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
6233 	if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
6234 	mDNS_Unlock(m);
6235 	}
6236 
mDNS_GetDomains(mDNS * const m,DNSQuestion * const question,mDNS_DomainType DomainType,const domainname * dom,const mDNSInterfaceID InterfaceID,mDNSQuestionCallback * Callback,void * Context)6237 mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
6238 	const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
6239 	{
6240 	question->InterfaceID      = InterfaceID;
6241 	question->Target           = zeroAddr;
6242 	question->qtype            = kDNSType_PTR;
6243 	question->qclass           = kDNSClass_IN;
6244 	question->LongLived        = mDNSfalse;
6245 	question->ExpectUnique     = mDNSfalse;
6246 	question->ForceMCast       = mDNSfalse;
6247 	question->QuestionCallback = Callback;
6248 	question->QuestionContext  = Context;
6249 	if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
6250 	if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
6251 	if (!dom) dom = &localdomain;
6252 	if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
6253 	return(mDNS_StartQuery(m, question));
6254 	}
6255 
6256 // ***************************************************************************
6257 #if COMPILER_LIKES_PRAGMA_MARK
6258 #pragma mark -
6259 #pragma mark - Responder Functions
6260 #endif
6261 
mDNS_Register(mDNS * const m,AuthRecord * const rr)6262 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
6263 	{
6264 	mStatus status;
6265 	mDNS_Lock(m);
6266 	status = mDNS_Register_internal(m, rr);
6267 	mDNS_Unlock(m);
6268 	return(status);
6269 	}
6270 
mDNS_Update(mDNS * const m,AuthRecord * const rr,mDNSu32 newttl,const mDNSu16 newrdlength,RData * const newrdata,mDNSRecordUpdateCallback * Callback)6271 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
6272 	const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
6273 	{
6274 #ifndef UNICAST_DISABLED
6275 	mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
6276 #else
6277 	mDNSBool unicast = mDNSfalse;
6278 #endif
6279 
6280 	if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
6281 		{
6282 		LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
6283 		return(mStatus_Invalid);
6284 		}
6285 
6286 	mDNS_Lock(m);
6287 
6288 	// If TTL is unspecified, leave TTL unchanged
6289 	if (newttl == 0) newttl = rr->resrec.rroriginalttl;
6290 
6291 	// If we already have an update queued up which has not gone through yet,
6292 	// give the client a chance to free that memory
6293 	if (!unicast && rr->NewRData)
6294 		{
6295 		RData *n = rr->NewRData;
6296 		rr->NewRData = mDNSNULL;			// Clear the NewRData pointer ...
6297 		if (rr->UpdateCallback)
6298 			rr->UpdateCallback(m, rr, n);	// ...and let the client free this memory, if necessary
6299 		}
6300 
6301 	rr->NewRData             = newrdata;
6302 	rr->newrdlength          = newrdlength;
6303 	rr->UpdateCallback       = Callback;
6304 
6305 	if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
6306 
6307 	if (rr->resrec.rroriginalttl == newttl &&
6308 		rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
6309 		CompleteRDataUpdate(m, rr);
6310 	else
6311 		{
6312 		domainlabel name;
6313 		domainname type, domain;
6314 		DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
6315 		rr->AnnounceCount = InitialAnnounceCount;
6316 		// iChat often does suprious record updates where no data has changed. For the _presence service type, using
6317 		// name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
6318 		// update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
6319 		// even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
6320 		// To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
6321 		if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
6322 		rr->ThisAPInterval       = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6323 		InitializeLastAPTime(m, rr);
6324 		while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
6325 		if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
6326 		if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
6327 		if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
6328 		if (rr->UpdateCredits <= 5)
6329 			{
6330 			mDNSu32 delay = 6 - rr->UpdateCredits;		// Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
6331 			if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
6332 			rr->ThisAPInterval *= 4;
6333 			rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
6334 			LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
6335 				rr->resrec.name->c, delay, delay > 1 ? "s" : "");
6336 			}
6337 		rr->resrec.rroriginalttl = newttl;
6338 		}
6339 
6340 	mDNS_Unlock(m);
6341 	return(mStatus_NoError);
6342 	}
6343 
6344 // NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
6345 // the record list and/or question list.
6346 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_Deregister(mDNS * const m,AuthRecord * const rr)6347 mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
6348 	{
6349 	mStatus status;
6350 	mDNS_Lock(m);
6351 	status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
6352 	mDNS_Unlock(m);
6353 	return(status);
6354 	}
6355 
6356 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
6357 
FindFirstAdvertisedInterface(mDNS * const m)6358 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
6359 	{
6360 	NetworkInterfaceInfo *intf;
6361 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6362 		if (intf->Advertise) break;
6363 	return(intf);
6364 	}
6365 
AdvertiseInterface(mDNS * const m,NetworkInterfaceInfo * set)6366 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6367 	{
6368 	char buffer[256];
6369 	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6370 	if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
6371 
6372 	// Send dynamic update for non-linklocal IPv4 Addresses
6373 	mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kHostNameTTL, kDNSRecordTypeUnique,      mDNS_HostNameCallback, set);
6374 	mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6375 	mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique,      mDNSNULL, mDNSNULL);
6376 
6377 #if ANSWER_REMOTE_HOSTNAME_QUERIES
6378 	set->RR_A    .AllowRemoteQuery  = mDNStrue;
6379 	set->RR_PTR  .AllowRemoteQuery  = mDNStrue;
6380 	set->RR_HINFO.AllowRemoteQuery  = mDNStrue;
6381 #endif
6382 	// 1. Set up Address record to map from host name ("foo.local.") to IP address
6383 	// 2. Set up reverse-lookup PTR record to map from our address back to our host name
6384 	AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
6385 	if (set->ip.type == mDNSAddrType_IPv4)
6386 		{
6387 		set->RR_A.resrec.rrtype = kDNSType_A;
6388 		set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
6389 		// Note: This is reverse order compared to a normal dotted-decimal IP address
6390 		mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
6391 			set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
6392 		}
6393 	else if (set->ip.type == mDNSAddrType_IPv6)
6394 		{
6395 		int i;
6396 		set->RR_A.resrec.rrtype = kDNSType_AAAA;
6397 		set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
6398 		for (i = 0; i < 16; i++)
6399 			{
6400 			static const char hexValues[] = "0123456789ABCDEF";
6401 			buffer[i * 4    ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
6402 			buffer[i * 4 + 1] = '.';
6403 			buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
6404 			buffer[i * 4 + 3] = '.';
6405 			}
6406 		mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
6407 		}
6408 
6409 	MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
6410 	set->RR_PTR.HostTarget = mDNStrue;	// Tell mDNS that the target of this PTR is to be kept in sync with our host name
6411 	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
6412 
6413 	set->RR_A.RRSet = &primary->RR_A;	// May refer to self
6414 
6415 	mDNS_Register_internal(m, &set->RR_A);
6416 	mDNS_Register_internal(m, &set->RR_PTR);
6417 
6418 	if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
6419 		{
6420 		mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
6421 		AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
6422 		set->RR_HINFO.DependentOn = &set->RR_A;
6423 		mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
6424 		p += 1 + (int)p[0];
6425 		mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]);
6426 		mDNS_Register_internal(m, &set->RR_HINFO);
6427 		}
6428 	else
6429 		{
6430 		debugf("Not creating HINFO record: platform support layer provided no information");
6431 		set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
6432 		}
6433 	}
6434 
DeadvertiseInterface(mDNS * const m,NetworkInterfaceInfo * set)6435 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6436 	{
6437 	NetworkInterfaceInfo *intf;
6438 
6439     // If we still have address records referring to this one, update them
6440 	NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6441 	AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
6442 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6443 		if (intf->RR_A.RRSet == &set->RR_A)
6444 			intf->RR_A.RRSet = A;
6445 
6446 	// Unregister these records.
6447 	// When doing the mDNS_Close processing, we first call DeadvertiseInterface for each interface, so by the time the platform
6448 	// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
6449 	// Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
6450 	// To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
6451 	if (set->RR_A.    resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A,     mDNS_Dereg_normal);
6452 	if (set->RR_PTR.  resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR,   mDNS_Dereg_normal);
6453 	if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
6454 	}
6455 
mDNS_SetFQDN(mDNS * const m)6456 mDNSexport void mDNS_SetFQDN(mDNS *const m)
6457 	{
6458 	domainname newmname;
6459 	NetworkInterfaceInfo *intf;
6460 	AuthRecord *rr;
6461 	newmname.c[0] = 0;
6462 
6463 	if (!AppendDomainLabel(&newmname, &m->hostlabel))  { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6464 	if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6465 	if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
6466 
6467 	mDNS_Lock(m);
6468 	AssignDomainName(&m->MulticastHostname, &newmname);
6469 
6470 	// 1. Stop advertising our address records on all interfaces
6471 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6472 		if (intf->Advertise) DeadvertiseInterface(m, intf);
6473 
6474 	// 2. Start advertising our address records using the new name
6475 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6476 		if (intf->Advertise) AdvertiseInterface(m, intf);
6477 
6478 	// 3. Make sure that any SRV records (and the like) that reference our
6479 	// host name in their rdata get updated to reference this new host name
6480 	for (rr = m->ResourceRecords;  rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6481 	for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
6482 
6483 	mDNS_Unlock(m);
6484 	}
6485 
mDNS_HostNameCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6486 mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6487 	{
6488 	(void)rr;	// Unused parameter
6489 
6490 	#if MDNS_DEBUGMSGS
6491 		{
6492 		char *msg = "Unknown result";
6493 		if      (result == mStatus_NoError)      msg = "Name registered";
6494 		else if (result == mStatus_NameConflict) msg = "Name conflict";
6495 		debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6496 		}
6497 	#endif
6498 
6499 	if (result == mStatus_NoError)
6500 		{
6501 		// Notify the client that the host name is successfully registered
6502 		if (m->MainCallback)
6503 			{
6504 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6505 			m->MainCallback(m, result);
6506 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6507 			}
6508 		}
6509 	else if (result == mStatus_NameConflict)
6510 		{
6511 		domainlabel oldlabel = m->hostlabel;
6512 
6513 		// 1. First give the client callback a chance to pick a new name
6514 		if (m->MainCallback)
6515 			{
6516 			m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
6517 			m->MainCallback(m, mStatus_NameConflict);
6518 			m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
6519 			}
6520 
6521 		// 2. If the client callback didn't do it, add (or increment) an index ourselves
6522 		if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
6523 			IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
6524 
6525 		// 3. Generate the FQDNs from the hostlabel,
6526 		// and make sure all SRV records, etc., are updated to reference our new hostname
6527 		mDNS_SetFQDN(m);
6528 		LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
6529 		}
6530 	else if (result == mStatus_MemFree)
6531 		{
6532 		// .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
6533 		// mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
6534 		debugf("mDNS_HostNameCallback: MemFree (ignored)");
6535 		}
6536 	else
6537 		LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name->c);
6538 	}
6539 
UpdateInterfaceProtocols(mDNS * const m,NetworkInterfaceInfo * active)6540 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
6541 	{
6542 	NetworkInterfaceInfo *intf;
6543 	active->IPv4Available = mDNSfalse;
6544 	active->IPv6Available = mDNSfalse;
6545 	for (intf = m->HostInterfaces; intf; intf = intf->next)
6546 		if (intf->InterfaceID == active->InterfaceID)
6547 			{
6548 			if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
6549 			if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
6550 			}
6551 	}
6552 
mDNS_RegisterInterface(mDNS * const m,NetworkInterfaceInfo * set,mDNSBool flapping)6553 mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6554 	{
6555 	mDNSBool FirstOfType = mDNStrue;
6556 	NetworkInterfaceInfo **p = &m->HostInterfaces;
6557 
6558 	if (!set->InterfaceID)
6559 		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
6560 
6561 	if (!mDNSAddressIsValidNonZero(&set->mask))
6562 		{ LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
6563 
6564 	mDNS_Lock(m);
6565 
6566 	// Assume this interface will be active now, unless we find a duplicate already in the list
6567 	set->InterfaceActive = mDNStrue;
6568 	set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
6569 	set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
6570 
6571 	// Scan list to see if this InterfaceID is already represented
6572 	while (*p)
6573 		{
6574 		if (*p == set)
6575 			{
6576 			LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
6577 			mDNS_Unlock(m);
6578 			return(mStatus_AlreadyRegistered);
6579 			}
6580 
6581 		if ((*p)->InterfaceID == set->InterfaceID)
6582 			{
6583 			// This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
6584 			set->InterfaceActive = mDNSfalse;
6585 			if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
6586 			if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
6587 			if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
6588 			}
6589 
6590 		p=&(*p)->next;
6591 		}
6592 
6593 	set->next = mDNSNULL;
6594 	*p = set;
6595 
6596 	if (set->Advertise)
6597 		AdvertiseInterface(m, set);
6598 
6599 	LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
6600 		set->InterfaceActive ?
6601 			"not represented in list; marking active and retriggering queries" :
6602 			"already represented in list; marking inactive for now");
6603 
6604 	// In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6605 	// giving the false impression that there's an active representative of this interface when there really isn't.
6606 	// Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
6607 	// even if we believe that we previously had an active representative of this interface.
6608 	if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
6609 		{
6610 		DNSQuestion *q;
6611 		AuthRecord *rr;
6612 		// If flapping, delay between first and second queries is eight seconds instead of one
6613 		mDNSs32 delay    = flapping ? mDNSPlatformOneSecond   * 5 : 0;
6614 		mDNSu8  announce = flapping ? (mDNSu8)1                   : InitialAnnounceCount;
6615 
6616 		// Use a small amount of randomness:
6617 		// In the case of a network administrator turning on an Ethernet hub so that all the
6618 		// connected machines establish link at exactly the same time, we don't want them all
6619 		// to go and hit the network with identical queries at exactly the same moment.
6620 		if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
6621 
6622 		if (flapping)
6623 			{
6624 			LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
6625 			if (!m->SuppressProbes ||
6626 				m->SuppressProbes - (m->timenow + delay) < 0)
6627 				m->SuppressProbes = (m->timenow + delay);
6628 			}
6629 
6630 		for (q = m->Questions; q; q=q->next)							// Scan our list of questions
6631 			if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)	// If non-specific Q, or Q on this specific interface,
6632 				{														// then reactivate this question
6633 				mDNSs32 initial  = (flapping && q->FlappingInterface != set->InterfaceID) ? InitialQuestionInterval * 8 : InitialQuestionInterval;
6634 				mDNSs32 qdelay   = (flapping && q->FlappingInterface != set->InterfaceID) ? mDNSPlatformOneSecond   * 5 : 0;
6635 				if (flapping && q->FlappingInterface == set->InterfaceID)
6636 					LogOperation("No cache records for %##s (%s) expired; no need for immediate question", q->qname.c, DNSTypeName(q->qtype));
6637 
6638 				if (!q->ThisQInterval || q->ThisQInterval > initial)
6639 					{
6640 					q->ThisQInterval = initial;
6641 					q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
6642 					}
6643 				if (q->LastQTime - (m->timenow - q->ThisQInterval + qdelay) > 0)
6644 					q->LastQTime = (m->timenow - q->ThisQInterval + qdelay);
6645 				q->RecentAnswerPkts = 0;
6646 				SetNextQueryTime(m,q);
6647 				}
6648 
6649 		// For all our non-specific authoritative resource records (and any dormant records specific to this interface)
6650 		// we now need them to re-probe if necessary, and then re-announce.
6651 		for (rr = m->ResourceRecords; rr; rr=rr->next)
6652 			if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
6653 				{
6654 				if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
6655 				rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
6656 				if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
6657 				rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
6658 				InitializeLastAPTime(m, rr);
6659 				}
6660 		}
6661 
6662 	mDNS_Unlock(m);
6663 	return(mStatus_NoError);
6664 	}
6665 
6666 // NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
6667 // the record list and/or question list.
6668 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_DeregisterInterface(mDNS * const m,NetworkInterfaceInfo * set,mDNSBool flapping)6669 mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6670 	{
6671 	NetworkInterfaceInfo **p = &m->HostInterfaces;
6672 
6673 	mDNSBool revalidate = mDNSfalse;
6674 	// If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
6675 	// time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
6676 	// still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
6677 	if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
6678 
6679 	mDNS_Lock(m);
6680 
6681 	// Find this record in our list
6682 	while (*p && *p != set) p=&(*p)->next;
6683 	if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
6684 
6685 	// Unlink this record from our list
6686 	*p = (*p)->next;
6687 	set->next = mDNSNULL;
6688 
6689 	if (!set->InterfaceActive)
6690 		{
6691 		// If this interface not the active member of its set, update the v4/v6Available flags for the active member
6692 		NetworkInterfaceInfo *intf;
6693 		for (intf = m->HostInterfaces; intf; intf = intf->next)
6694 			if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
6695 				UpdateInterfaceProtocols(m, intf);
6696 		}
6697 	else
6698 		{
6699 		NetworkInterfaceInfo *intf;
6700 		for (intf = m->HostInterfaces; intf; intf = intf->next)
6701 			if (intf->InterfaceID == set->InterfaceID)
6702 				break;
6703 		if (intf)
6704 			{
6705 			LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
6706 				" making it active", set->InterfaceID, set->ifname, &set->ip);
6707 			intf->InterfaceActive = mDNStrue;
6708 			UpdateInterfaceProtocols(m, intf);
6709 
6710 			// See if another representative *of the same type* exists. If not, we mave have gone from
6711 			// dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
6712 			for (intf = m->HostInterfaces; intf; intf = intf->next)
6713 				if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
6714 					break;
6715 			if (!intf) revalidate = mDNStrue;
6716 			}
6717 		else
6718 			{
6719 			mDNSu32 slot;
6720 			CacheGroup *cg;
6721 			CacheRecord *rr;
6722 			DNSQuestion *q;
6723 			LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
6724 				" marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
6725 
6726 			if (flapping)
6727 				LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
6728 					set->ifname, &set->ip);
6729 
6730 			// 1. Deactivate any questions specific to this interface, and tag appropriate questions
6731 			// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
6732 			for (q = m->Questions; q; q=q->next)
6733 				{
6734 				if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
6735 				if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
6736 					q->FlappingInterface = set->InterfaceID;
6737 				}
6738 
6739 			// 2. Flush any cache records received on this interface
6740 			revalidate = mDNSfalse;		// Don't revalidate if we're flushing the records
6741 			FORALL_CACHERECORDS(slot, cg, rr)
6742 				if (rr->resrec.InterfaceID == set->InterfaceID)
6743 					{
6744 					// If this interface is deemed flapping,
6745 					// postpone deleting the cache records in case the interface comes back again
6746 					if (!flapping) PurgeCacheResourceRecord(m, rr);
6747 					else mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6748 					}
6749 			}
6750 		}
6751 
6752 	// If we were advertising on this interface, deregister those address and reverse-lookup records now
6753 	if (set->Advertise) DeadvertiseInterface(m, set);
6754 
6755 	// If we have any cache records received on this interface that went away, then re-verify them.
6756 	// In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6757 	// giving the false impression that there's an active representative of this interface when there really isn't.
6758 	// Don't need to do this when shutting down, because *all* interfaces are about to go away
6759 	if (revalidate && !m->mDNS_shutdown)
6760 		{
6761 		mDNSu32 slot;
6762 		CacheGroup *cg;
6763 		CacheRecord *rr;
6764 		m->NextCacheCheck = m->timenow;
6765 		FORALL_CACHERECORDS(slot, cg, rr)
6766 			if (rr->resrec.InterfaceID == set->InterfaceID)
6767 				mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6768 		}
6769 
6770 	mDNS_Unlock(m);
6771 	}
6772 
ServiceCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6773 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6774 	{
6775 	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6776 	(void)m;	// Unused parameter
6777 
6778 	#if MDNS_DEBUGMSGS
6779 		{
6780 		char *msg = "Unknown result";
6781 		if      (result == mStatus_NoError)      msg = "Name Registered";
6782 		else if (result == mStatus_NameConflict) msg = "Name Conflict";
6783 		else if (result == mStatus_MemFree)      msg = "Memory Free";
6784 		debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6785 		}
6786 	#endif
6787 
6788 	// Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
6789 	if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
6790 
6791 	// If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
6792 	if (result == mStatus_NameConflict)
6793 		{
6794 		sr->Conflict = mDNStrue;				// Record that this service set had a conflict
6795 		mDNS_DeregisterService(m, sr);			// Unlink the records from our list
6796 		return;
6797 		}
6798 
6799 	if (result == mStatus_MemFree)
6800 		{
6801 		// If the PTR record or any of the subtype PTR records are still in the process of deregistering,
6802 		// don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
6803 		mDNSu32 i;
6804 		if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
6805 		for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
6806 
6807 		// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
6808 		// then we can now report the NameConflict to the client
6809 		if (sr->Conflict) result = mStatus_NameConflict;
6810 		}
6811 
6812 	// CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
6813 	// function is allowed to do anything, including deregistering this service and freeing its memory.
6814 	if (sr->ServiceCallback)
6815 		sr->ServiceCallback(m, sr, result);
6816 	}
6817 
NSSCallback(mDNS * const m,AuthRecord * const rr,mStatus result)6818 mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6819 	{
6820 	ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6821 	if (sr->ServiceCallback)
6822 		sr->ServiceCallback(m, sr, result);
6823 	}
6824 
6825 // Note:
6826 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
6827 // Type is service type (e.g. "_ipp._tcp.")
6828 // Domain is fully qualified domain name (i.e. ending with a null label)
6829 // We always register a TXT, even if it is empty (so that clients are not
6830 // left waiting forever looking for a nonexistent record.)
6831 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
6832 // then the default host name (m->MulticastHostname) is automatically used
mDNS_RegisterService(mDNS * const m,ServiceRecordSet * sr,const domainlabel * const name,const domainname * const type,const domainname * const domain,const domainname * const host,mDNSIPPort port,const mDNSu8 txtinfo[],mDNSu16 txtlen,AuthRecord * SubTypes,mDNSu32 NumSubTypes,const mDNSInterfaceID InterfaceID,mDNSServiceCallback Callback,void * Context)6833 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
6834 	const domainlabel *const name, const domainname *const type, const domainname *const domain,
6835 	const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
6836 	AuthRecord *SubTypes, mDNSu32 NumSubTypes,
6837 	const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
6838 	{
6839 	mStatus err;
6840 	mDNSu32 i;
6841 
6842 	sr->ServiceCallback = Callback;
6843 	sr->ServiceContext  = Context;
6844 	sr->Extras          = mDNSNULL;
6845 	sr->NumSubTypes     = NumSubTypes;
6846 	sr->SubTypes        = SubTypes;
6847 	sr->Conflict        = mDNSfalse;
6848 	if (host && host->c[0]) sr->Host = *host;
6849 	else sr->Host.c[0] = 0;
6850 
6851 	// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
6852 	if (!port.NotAnInteger)
6853 		return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
6854 
6855 	// Initialize the AuthRecord objects to sane values
6856 	mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
6857 	mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared,   ServiceCallback, sr);
6858 	mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
6859 	mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique,   ServiceCallback, sr);
6860 
6861 	// If the client is registering an oversized TXT record,
6862 	// it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
6863 	if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
6864 		sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
6865 
6866 	// Set up the record names
6867 	// For now we only create an advisory record for the main type, not for subtypes
6868 	// We need to gain some operational experience before we decide if there's a need to create them for subtypes too
6869 	if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
6870 		return(mStatus_BadParamErr);
6871 	if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6872 	if (ConstructServiceName(sr->RR_SRV.resrec.name, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6873 	AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
6874 
6875 	// 1. Set up the ADV record rdata to advertise our service type
6876 	AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
6877 
6878 	// 2. Set up the PTR record rdata to point to our service name
6879 	// We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
6880 	AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6881 	sr->RR_PTR.Additional1 = &sr->RR_SRV;
6882 	sr->RR_PTR.Additional2 = &sr->RR_TXT;
6883 
6884 	// 2a. Set up any subtype PTRs to point to our service name
6885 	// If the client is using subtypes, it is the client's responsibility to have
6886 	// already set the first label of the record name to the subtype being registered
6887 	for (i=0; i<NumSubTypes; i++)
6888 		{
6889 		domainname st;
6890 		AssignDomainName(&st, sr->SubTypes[i].resrec.name);
6891 		st.c[1+st.c[0]] = 0;			// Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
6892 		AppendDomainName(&st, type);
6893 		mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6894 		if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
6895 		AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6896 		sr->SubTypes[i].Additional1 = &sr->RR_SRV;
6897 		sr->SubTypes[i].Additional2 = &sr->RR_TXT;
6898 		}
6899 
6900 	// 3. Set up the SRV record rdata.
6901 	sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
6902 	sr->RR_SRV.resrec.rdata->u.srv.weight   = 0;
6903 	sr->RR_SRV.resrec.rdata->u.srv.port     = port;
6904 
6905 	// Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
6906 	if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
6907 	else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
6908 
6909 	// 4. Set up the TXT record rdata,
6910 	// and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
6911 	if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
6912 	else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
6913 		{
6914 		sr->RR_TXT.resrec.rdlength = txtlen;
6915 		if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
6916 		mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen);
6917 		}
6918 	sr->RR_TXT.DependentOn = &sr->RR_SRV;
6919 
6920 #ifndef UNICAST_DISABLED
6921 	// If the client has specified an explicit InterfaceID,
6922 	// then we do a multicast registration on that interface, even for unicast domains.
6923 	if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6924 		{
6925 		mStatus status;
6926 		mDNS_Lock(m);
6927 		// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6928 		// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6929 		// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6930 		// (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
6931 		if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
6932 		status = uDNS_RegisterService(m, sr);
6933 		mDNS_Unlock(m);
6934 		return(status);
6935 		}
6936 #endif
6937 	mDNS_Lock(m);
6938 	err = mDNS_Register_internal(m, &sr->RR_SRV);
6939 	if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
6940 	// We register the RR_PTR last, because we want to be sure that in the event of a forced call to
6941 	// mDNS_Close, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
6942 	// the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
6943 	// the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
6944 	// make sure we've deregistered all our records and done any other necessary cleanup before that happens.
6945 	if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
6946 	for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
6947 	if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
6948 
6949 	mDNS_Unlock(m);
6950 
6951 	if (err) mDNS_DeregisterService(m, sr);
6952 	return(err);
6953 	}
6954 
mDNS_AddRecordToService(mDNS * const m,ServiceRecordSet * sr,ExtraResourceRecord * extra,RData * rdata,mDNSu32 ttl)6955 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
6956 	ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
6957 	{
6958 	ExtraResourceRecord **e;
6959 	mStatus status;
6960 
6961 	extra->next = mDNSNULL;
6962 	mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
6963 		extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
6964 	AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
6965 
6966 #ifndef UNICAST_DISABLED
6967 	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6968 		{
6969 		mDNS_Lock(m);
6970 		// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6971 		// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6972 		// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6973 		// (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
6974 		if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
6975 			{ extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
6976 		status = uDNS_AddRecordToService(m, sr, extra);
6977 		mDNS_Unlock(m);
6978 		return status;
6979 		}
6980 #endif
6981 
6982 	mDNS_Lock(m);
6983 	e = &sr->Extras;
6984 	while (*e) e = &(*e)->next;
6985 
6986 	if (ttl == 0) ttl = kStandardTTL;
6987 
6988 	extra->r.DependentOn = &sr->RR_SRV;
6989 
6990 	debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
6991 
6992 	status = mDNS_Register_internal(m, &extra->r);
6993 	if (status == mStatus_NoError) *e = extra;
6994 	mDNS_Unlock(m);
6995 	return(status);
6996 	}
6997 
mDNS_RemoveRecordFromService(mDNS * const m,ServiceRecordSet * sr,ExtraResourceRecord * extra,mDNSRecordCallback MemFreeCallback,void * Context)6998 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
6999 	mDNSRecordCallback MemFreeCallback, void *Context)
7000 	{
7001 	ExtraResourceRecord **e;
7002 	mStatus status;
7003 
7004 	mDNS_Lock(m);
7005 	e = &sr->Extras;
7006 	while (*e && *e != extra) e = &(*e)->next;
7007 	if (!*e)
7008 		{
7009 		debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
7010 		status = mStatus_BadReferenceErr;
7011 		}
7012 	else
7013 		{
7014 		debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
7015 		extra->r.RecordCallback = MemFreeCallback;
7016 		extra->r.RecordContext  = Context;
7017 		*e = (*e)->next;
7018 #ifndef UNICAST_DISABLED
7019 		if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7020 			status = uDNS_DeregisterRecord(m, &extra->r);
7021 		else
7022 #endif
7023 		status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
7024 		}
7025 	mDNS_Unlock(m);
7026 	return(status);
7027 	}
7028 
mDNS_RenameAndReregisterService(mDNS * const m,ServiceRecordSet * const sr,const domainlabel * newname)7029 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
7030 	{
7031 	// NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
7032 	// mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
7033 	domainlabel name1, name2;
7034 	domainname type, domain;
7035 	domainname *host = mDNSNULL;
7036 	ExtraResourceRecord *extras = sr->Extras;
7037 	mStatus err;
7038 
7039 	DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
7040 	if (!newname)
7041 		{
7042 		name2 = name1;
7043 		IncrementLabelSuffix(&name2, mDNStrue);
7044 		newname = &name2;
7045 		}
7046 
7047 	if (SameDomainName(&domain, &localdomain))
7048 		LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
7049 	else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
7050 
7051 	if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
7052 
7053 	err = mDNS_RegisterService(m, sr, newname, &type, &domain,
7054 		host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
7055 		sr->SubTypes, sr->NumSubTypes,
7056 		sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
7057 
7058 	// mDNS_RegisterService() just reset sr->Extras to NULL.
7059 	// Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
7060 	// through the old list of extra records, and re-add them to our freshly created service registration
7061 	while (!err && extras)
7062 		{
7063 		ExtraResourceRecord *e = extras;
7064 		extras = extras->next;
7065 		err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
7066 		}
7067 
7068 	return(err);
7069 	}
7070 
7071 // NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
7072 // which may change the record list and/or question list.
7073 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNS_DeregisterService(mDNS * const m,ServiceRecordSet * sr)7074 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
7075 	{
7076 	// If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
7077 	if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
7078 
7079 #ifndef UNICAST_DISABLED
7080 	if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
7081 		{
7082 		mStatus status;
7083 		mDNS_Lock(m);
7084 		status = uDNS_DeregisterService(m, sr);
7085 		mDNS_Unlock(m);
7086 		return(status);
7087 		}
7088 #endif
7089 	if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
7090 		{
7091 		debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
7092 		return(mStatus_BadReferenceErr);
7093 		}
7094 	else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
7095 		{
7096 		debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
7097 		return(mStatus_NoError);
7098 		}
7099 	else
7100 		{
7101 		mDNSu32 i;
7102 		mStatus status;
7103 		ExtraResourceRecord *e;
7104 		mDNS_Lock(m);
7105 		e = sr->Extras;
7106 
7107 		// We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
7108 		// SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
7109 		mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
7110 		mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
7111 
7112 		mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
7113 
7114 		// We deregister all of the extra records, but we leave the sr->Extras list intact
7115 		// in case the client wants to do a RenameAndReregister and reinstate the registration
7116 		while (e)
7117 			{
7118 			mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
7119 			e = e->next;
7120 			}
7121 
7122 		for (i=0; i<sr->NumSubTypes; i++)
7123 			mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
7124 
7125 		// Be sure to deregister the PTR last!
7126 		// Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
7127 		// which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
7128 		// which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
7129 		// we've deregistered all our records and done any other necessary cleanup before that happens.
7130 		status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
7131 		mDNS_Unlock(m);
7132 		return(status);
7133 		}
7134 	}
7135 
7136 // Create a registration that asserts that no such service exists with this name.
7137 // This can be useful where there is a given function is available through several protocols.
7138 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
7139 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
7140 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
7141 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
mDNS_RegisterNoSuchService(mDNS * const m,AuthRecord * const rr,const domainlabel * const name,const domainname * const type,const domainname * const domain,const domainname * const host,const mDNSInterfaceID InterfaceID,mDNSRecordCallback Callback,void * Context)7142 mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
7143 	const domainlabel *const name, const domainname *const type, const domainname *const domain,
7144 	const domainname *const host,
7145 	const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
7146 	{
7147 	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
7148 	if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
7149 	rr->resrec.rdata->u.srv.priority    = 0;
7150 	rr->resrec.rdata->u.srv.weight      = 0;
7151 	rr->resrec.rdata->u.srv.port        = zeroIPPort;
7152 	if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
7153 	else rr->HostTarget = mDNStrue;
7154 	return(mDNS_Register(m, rr));
7155 	}
7156 
mDNS_AdvertiseDomains(mDNS * const m,AuthRecord * rr,mDNS_DomainType DomainType,const mDNSInterfaceID InterfaceID,char * domname)7157 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
7158 	mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
7159 	{
7160 	mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
7161 	if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
7162 	if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
7163 	return(mDNS_Register(m, rr));
7164 	}
7165 
7166 // ***************************************************************************
7167 #if COMPILER_LIKES_PRAGMA_MARK
7168 #pragma mark -
7169 #pragma mark -
7170 #pragma mark - Startup and Shutdown
7171 #endif
7172 
mDNS_GrowCache_internal(mDNS * const m,CacheEntity * storage,mDNSu32 numrecords)7173 mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7174 	{
7175 	if (storage && numrecords)
7176 		{
7177 		mDNSu32 i;
7178 		debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
7179 		for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
7180 		storage[numrecords-1].next = m->rrcache_free;
7181 		m->rrcache_free = storage;
7182 		m->rrcache_size += numrecords;
7183 		}
7184 	}
7185 
mDNS_GrowCache(mDNS * const m,CacheEntity * storage,mDNSu32 numrecords)7186 mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
7187 	{
7188 	mDNS_Lock(m);
7189 	mDNS_GrowCache_internal(m, storage, numrecords);
7190 	mDNS_Unlock(m);
7191 	}
7192 
mDNS_Init(mDNS * const m,mDNS_PlatformSupport * const p,CacheEntity * rrcachestorage,mDNSu32 rrcachesize,mDNSBool AdvertiseLocalAddresses,mDNSCallback * Callback,void * Context)7193 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
7194 	CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
7195 	mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
7196 	{
7197 	mDNSu32 slot;
7198 	mDNSs32 timenow;
7199 	mStatus result;
7200 
7201 	if (!rrcachestorage) rrcachesize = 0;
7202 
7203 	m->p                       = p;
7204 	m->KnownBugs               = 0;
7205 	m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
7206 	m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
7207 	m->mDNSPlatformStatus      = mStatus_Waiting;
7208 	m->UnicastPort4            = zeroIPPort;
7209 	m->UnicastPort6            = zeroIPPort;
7210 	m->MainCallback            = Callback;
7211 	m->MainContext             = Context;
7212 	m->rec.r.resrec.RecordType = 0;
7213 
7214 	// For debugging: To catch and report locking failures
7215 	m->mDNS_busy               = 0;
7216 	m->mDNS_reentrancy         = 0;
7217 	m->mDNS_shutdown           = mDNSfalse;
7218 	m->lock_rrcache            = 0;
7219 	m->lock_Questions          = 0;
7220 	m->lock_Records            = 0;
7221 
7222 	// Task Scheduling variables
7223 	result = mDNSPlatformTimeInit();
7224 	if (result != mStatus_NoError) return(result);
7225 	m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
7226 	timenow = mDNS_TimeNow_NoLock(m);
7227 
7228 	m->timenow                 = 0;		// MUST only be set within mDNS_Lock/mDNS_Unlock section
7229 	m->timenow_last            = timenow;
7230 	m->NextScheduledEvent      = timenow;
7231 	m->SuppressSending         = timenow;
7232 	m->NextCacheCheck          = timenow + 0x78000000;
7233 	m->NextScheduledQuery      = timenow + 0x78000000;
7234 	m->NextScheduledProbe      = timenow + 0x78000000;
7235 	m->NextScheduledResponse   = timenow + 0x78000000;
7236 	m->ExpectUnicastResponse   = timenow + 0x78000000;
7237 	m->RandomQueryDelay        = 0;
7238 	m->RandomReconfirmDelay    = 0;
7239 	m->PktNum                  = 0;
7240 	m->SendDeregistrations     = mDNSfalse;
7241 	m->SendImmediateAnswers    = mDNSfalse;
7242 	m->SleepState              = mDNSfalse;
7243 
7244 	// These fields only required for mDNS Searcher...
7245 	m->Questions               = mDNSNULL;
7246 	m->NewQuestions            = mDNSNULL;
7247 	m->CurrentQuestion         = mDNSNULL;
7248 	m->LocalOnlyQuestions      = mDNSNULL;
7249 	m->NewLocalOnlyQuestions   = mDNSNULL;
7250 	m->rrcache_size            = 0;
7251 	m->rrcache_totalused       = 0;
7252 	m->rrcache_active          = 0;
7253 	m->rrcache_report          = 10;
7254 	m->rrcache_free            = mDNSNULL;
7255 
7256 	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
7257 
7258 	mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
7259 
7260 	// Fields below only required for mDNS Responder...
7261 	m->hostlabel.c[0]          = 0;
7262 	m->nicelabel.c[0]          = 0;
7263 	m->MulticastHostname.c[0]  = 0;
7264 	m->HIHardware.c[0]         = 0;
7265 	m->HISoftware.c[0]         = 0;
7266 	m->ResourceRecords         = mDNSNULL;
7267 	m->DuplicateRecords        = mDNSNULL;
7268 	m->NewLocalRecords         = mDNSNULL;
7269 	m->CurrentRecord           = mDNSNULL;
7270 	m->HostInterfaces          = mDNSNULL;
7271 	m->ProbeFailTime           = 0;
7272 	m->NumFailedProbes         = 0;
7273 	m->SuppressProbes          = 0;
7274 
7275 #ifndef UNICAST_DISABLED
7276 	uDNS_Init(m);
7277 	m->SuppressStdPort53Queries = 0;
7278 #endif
7279 	result = mDNSPlatformInit(m);
7280 
7281 	return(result);
7282 	}
7283 
mDNSCoreInitComplete(mDNS * const m,mStatus result)7284 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
7285 	{
7286 	m->mDNSPlatformStatus = result;
7287 	if (m->MainCallback)
7288 		{
7289 		mDNS_Lock(m);
7290 		m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
7291 		m->MainCallback(m, mStatus_NoError);
7292 		m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
7293 		mDNS_Unlock(m);
7294 		}
7295 	}
7296 
mDNS_Close(mDNS * const m)7297 mDNSexport void mDNS_Close(mDNS *const m)
7298 	{
7299 	mDNSu32 rrcache_active = 0;
7300 	mDNSu32 rrcache_totalused = 0;
7301 	mDNSu32 slot;
7302 	NetworkInterfaceInfo *intf;
7303 	mDNS_Lock(m);
7304 
7305 	m->mDNS_shutdown = mDNStrue;
7306 
7307 #ifndef UNICAST_DISABLED
7308 	uDNS_Close(m);
7309 #endif
7310 	rrcache_totalused = m->rrcache_totalused;
7311 	for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
7312 		{
7313 		while(m->rrcache_hash[slot])
7314 			{
7315 			CacheGroup *cg = m->rrcache_hash[slot];
7316 			while (cg->members)
7317 				{
7318 				CacheRecord *rr = cg->members;
7319 				cg->members = cg->members->next;
7320 				if (rr->CRActiveQuestion) rrcache_active++;
7321 				ReleaseCacheRecord(m, rr);
7322 				}
7323 			cg->rrcache_tail = &cg->members;
7324 			ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
7325 			}
7326 		}
7327 	debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
7328 	if (rrcache_active != m->rrcache_active)
7329 		LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
7330 
7331 	for (intf = m->HostInterfaces; intf; intf = intf->next)
7332 		if (intf->Advertise)
7333 			DeadvertiseInterface(m, intf);
7334 
7335 	// Make sure there are nothing but deregistering records remaining in the list
7336 	if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
7337 	m->CurrentRecord = m->ResourceRecords;
7338 	while (m->CurrentRecord)
7339 		{
7340 		AuthRecord *rr = m->CurrentRecord;
7341 		if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
7342 			{
7343 			debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
7344 			mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7345 			}
7346 		else
7347 			m->CurrentRecord = rr->next;
7348 		}
7349 
7350 	if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records");
7351 	else debugf("mDNS_Close: No deregistering records remain");
7352 
7353 	// If any deregistering records remain, send their deregistration announcements before we exit
7354 	if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
7355 	else if (m->ResourceRecords) SendResponses(m);
7356 	if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
7357 
7358 	mDNS_Unlock(m);
7359 	debugf("mDNS_Close: mDNSPlatformClose");
7360 	mDNSPlatformClose(m);
7361 	debugf("mDNS_Close: done");
7362 	}
7363