]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/mDNS.c
34a3c7c915b83a43c5216b92a42d1237eb362e20
[apple/mdnsresponder.git] / mDNSCore / mDNS.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here.
19 *
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform).
24
25 * Formatting notes:
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37
38 Change History (most recent first):
39
40 $Log: mDNS.c,v $
41 Revision 1.776 2008/04/17 20:14:14 cheshire
42 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
43
44 Revision 1.775 2008/03/26 01:53:34 mcguire
45 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
46
47 Revision 1.774 2008/03/17 17:46:08 mcguire
48 When activating an LLQ, reset all the important state and destroy any tcp connection,
49 so that everything will be restarted as if the question had just been asked.
50 Also reset servPort, so that the SOA query will be re-issued.
51
52 Revision 1.773 2008/03/14 22:52:36 mcguire
53 <rdar://problem/5321824> write status to the DS
54 Update status when any unicast LLQ is started
55
56 Revision 1.772 2008/03/06 02:48:34 mcguire
57 <rdar://problem/5321824> write status to the DS
58
59 Revision 1.771 2008/02/26 22:04:44 cheshire
60 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
61 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
62 question while it's still in our 'm->NewQuestions' section of the list
63
64 Revision 1.770 2008/02/22 23:09:02 cheshire
65 <rdar://problem/5338420> BTMM: Not processing additional records
66 Refinements:
67 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
68 2. Once we decide a record is acceptable, we can break out of the loop
69
70 Revision 1.769 2008/02/22 00:00:19 cheshire
71 <rdar://problem/5338420> BTMM: Not processing additional records
72
73 Revision 1.768 2008/02/19 23:26:50 cheshire
74 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
75
76 Revision 1.767 2007/12/22 02:25:29 cheshire
77 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
78
79 Revision 1.766 2007/12/15 01:12:27 cheshire
80 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
81
82 Revision 1.765 2007/12/15 00:18:51 cheshire
83 Renamed question->origLease to question->ReqLease
84
85 Revision 1.764 2007/12/14 00:49:53 cheshire
86 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
87 the CurrentServiceRecordSet mechanism to guard against services being deleted,
88 just like the record deregistration loop uses m->CurrentRecord.
89
90 Revision 1.763 2007/12/13 20:20:17 cheshire
91 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
92 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
93 inline a function defined in a different compilation unit) and therefore optimized better.
94
95 Revision 1.762 2007/12/13 00:13:03 cheshire
96 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
97
98 Revision 1.761 2007/12/13 00:03:31 cheshire
99 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
100
101 Revision 1.760 2007/12/08 00:36:19 cheshire
102 <rdar://problem/5636422> Updating TXT records is too slow
103 Remove unnecessary delays on announcing record updates, and on processing them on reception
104
105 Revision 1.759 2007/12/07 22:41:29 cheshire
106 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
107 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
108
109 Revision 1.758 2007/12/07 00:45:57 cheshire
110 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
111
112 Revision 1.757 2007/12/06 00:22:27 mcguire
113 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
114
115 Revision 1.756 2007/12/05 01:52:30 cheshire
116 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
117 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
118
119 Revision 1.755 2007/12/03 23:36:45 cheshire
120 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
121 Need to check GetServerForName() result is non-null before dereferencing pointer
122
123 Revision 1.754 2007/12/01 01:21:27 jgraessley
124 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
125
126 Revision 1.753 2007/12/01 00:44:15 cheshire
127 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
128
129 Revision 1.752 2007/11/14 01:10:51 cheshire
130 Fixed LogOperation() message wording
131
132 Revision 1.751 2007/10/30 23:49:41 cheshire
133 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
134 LLQ state was not being transferred properly between duplicate questions
135
136 Revision 1.750 2007/10/29 23:58:52 cheshire
137 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
138 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
139
140 Revision 1.749 2007/10/29 21:28:36 cheshire
141 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
142
143 Revision 1.748 2007/10/29 20:02:50 cheshire
144 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
145
146 Revision 1.747 2007/10/26 22:53:50 cheshire
147 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
148 instead of replicating the logic in both places
149
150 Revision 1.746 2007/10/25 22:48:50 cheshire
151 Added LogOperation message saying when we restart GetZoneData for record and service registrations
152
153 Revision 1.745 2007/10/25 20:48:47 cheshire
154 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
155
156 Revision 1.744 2007/10/25 20:06:14 cheshire
157 Don't try to do SOA queries using private DNS (TLS over TCP) queries
158
159 Revision 1.743 2007/10/25 00:12:46 cheshire
160 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
161 Retrigger service registrations whenever a new network interface is added
162
163 Revision 1.742 2007/10/24 22:40:06 cheshire
164 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
165 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
166
167 Revision 1.741 2007/10/24 00:50:29 cheshire
168 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
169 Retrigger record registrations whenever a new network interface is added
170
171 Revision 1.740 2007/10/23 00:38:03 cheshire
172 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
173 or code will spin sending the same cache expiration query repeatedly
174
175 Revision 1.739 2007/10/22 23:46:41 cheshire
176 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
177 Need to clear question->nta pointer after calling CancelGetZoneData()
178
179 Revision 1.738 2007/10/19 22:08:49 cheshire
180 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
181 Additional fixes and refinements
182
183 Revision 1.737 2007/10/18 23:06:42 cheshire
184 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
185 Additional fixes and refinements
186
187 Revision 1.736 2007/10/18 20:23:17 cheshire
188 Moved SuspendLLQs into mDNS.c, since it's only called from one place
189
190 Revision 1.735 2007/10/18 00:12:34 cheshire
191 Fixed "unused variable" compiler warning
192
193 Revision 1.734 2007/10/17 22:49:54 cheshire
194 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
195
196 Revision 1.733 2007/10/17 22:37:23 cheshire
197 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
198
199 Revision 1.732 2007/10/17 21:53:51 cheshire
200 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
201
202 Revision 1.731 2007/10/17 18:37:50 cheshire
203 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
204 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
205
206 Revision 1.730 2007/10/16 21:16:07 cheshire
207 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
208
209 Revision 1.729 2007/10/05 17:56:10 cheshire
210 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
211
212 Revision 1.728 2007/10/04 23:18:14 cheshire
213 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
214
215 Revision 1.727 2007/10/04 22:51:57 cheshire
216 Added debugging LogOperation message to show when we're sending cache expiration queries
217
218 Revision 1.726 2007/10/03 00:14:24 cheshire
219 Removed write to null to generate stack trace for SetNextQueryTime locking failure
220
221 Revision 1.725 2007/10/02 21:11:08 cheshire
222 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
223
224 Revision 1.724 2007/10/02 20:10:23 cheshire
225 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
226
227 Revision 1.723 2007/10/02 19:56:54 cheshire
228 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
229
230 Revision 1.722 2007/10/01 22:59:46 cheshire
231 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
232 Need to shut down NATTraversals on exit
233
234 Revision 1.721 2007/10/01 18:42:07 cheshire
235 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
236
237 Revision 1.720 2007/09/29 20:40:19 cheshire
238 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
239
240 Revision 1.719 2007/09/27 22:23:56 cheshire
241 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
242 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
243
244 Revision 1.718 2007/09/27 22:02:33 cheshire
245 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
246
247 Revision 1.717 2007/09/27 21:21:39 cheshire
248 Export CompleteDeregistration so it's callable from other files
249
250 Revision 1.716 2007/09/27 02:12:21 cheshire
251 Updated GrantCacheExtensions degugging message to show new record lifetime
252
253 Revision 1.715 2007/09/27 01:20:06 cheshire
254 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
255
256 Revision 1.714 2007/09/27 00:37:01 cheshire
257 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
258
259 Revision 1.713 2007/09/27 00:25:39 cheshire
260 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
261 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
262
263 Revision 1.712 2007/09/26 23:16:58 cheshire
264 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
265
266 Revision 1.711 2007/09/26 22:06:02 cheshire
267 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
268
269 Revision 1.710 2007/09/26 00:49:46 cheshire
270 Improve packet logging to show sent and received packets,
271 transport protocol (UDP/TCP/TLS) and source/destination address:port
272
273 Revision 1.709 2007/09/21 21:12:36 cheshire
274 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
275
276 Revision 1.708 2007/09/20 23:13:37 cheshire
277 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
278 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
279
280 Revision 1.707 2007/09/20 02:29:37 cheshire
281 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
282
283 Revision 1.706 2007/09/20 01:13:19 cheshire
284 Export CacheGroupForName so it's callable from other files
285
286 Revision 1.705 2007/09/20 01:12:06 cheshire
287 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
288
289 Revision 1.704 2007/09/19 22:47:25 cheshire
290 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
291
292 Revision 1.703 2007/09/14 01:46:59 cheshire
293 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
294
295 Revision 1.702 2007/09/13 22:06:46 cheshire
296 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
297 Need to accept DNS responses where the query ID field matches, even if the source address does not
298
299 Revision 1.701 2007/09/12 23:22:32 cheshire
300 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
301
302 Revision 1.700 2007/09/12 23:03:08 cheshire
303 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
304
305 Revision 1.699 2007/09/12 22:19:28 cheshire
306 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
307
308 Revision 1.698 2007/09/12 22:13:27 cheshire
309 Remove DynDNSHostNames cleanly on shutdown
310
311 Revision 1.697 2007/09/12 01:44:47 cheshire
312 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
313
314 Revision 1.696 2007/09/12 01:26:08 cheshire
315 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
316
317 Revision 1.695 2007/09/11 19:19:16 cheshire
318 Correct capitalization of "uPNP" to "UPnP"
319
320 Revision 1.694 2007/09/10 22:06:51 cheshire
321 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
322
323 Revision 1.693 2007/09/07 22:24:36 vazquez
324 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
325
326 Revision 1.692 2007/09/07 00:12:09 cheshire
327 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
328
329 Revision 1.691 2007/09/05 22:25:01 vazquez
330 <rdar://problem/5400521> update_record mDNSResponder leak
331
332 Revision 1.690 2007/09/05 21:48:01 cheshire
333 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
334 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
335 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
336 otherwise those records will expire and vanish from the cache.
337
338 Revision 1.689 2007/09/05 02:29:06 cheshire
339 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
340 Additional fixes to code implementing "NoAnswer" logic
341
342 Revision 1.688 2007/08/31 22:56:39 cheshire
343 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
344
345 Revision 1.687 2007/08/31 19:53:14 cheshire
346 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
347 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
348
349 Revision 1.686 2007/08/30 00:01:56 cheshire
350 Added comment about SetTargetToHostName()
351
352 Revision 1.685 2007/08/29 01:19:24 cheshire
353 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
354 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
355
356 Revision 1.684 2007/08/28 23:58:42 cheshire
357 Rename HostTarget -> AutoTarget
358
359 Revision 1.683 2007/08/28 23:53:21 cheshire
360 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
361
362 Revision 1.682 2007/08/27 20:28:19 cheshire
363 Improve "suspect uDNS response" log message
364
365 Revision 1.681 2007/08/24 23:37:23 cheshire
366 Added debugging message to show when ExtraResourceRecord callback gets invoked
367
368 Revision 1.680 2007/08/24 00:15:19 cheshire
369 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
370
371 Revision 1.679 2007/08/23 21:47:09 vazquez
372 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
373 make sure we clean up port mappings on base stations by sending a lease value of 0,
374 and only send NAT-PMP packets on private networks; also save some memory by
375 not using packet structs in NATTraversals.
376
377 Revision 1.678 2007/08/01 16:09:13 cheshire
378 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
379
380 Revision 1.677 2007/08/01 01:58:24 cheshire
381 Added RecordType sanity check in mDNS_Register_internal
382
383 Revision 1.676 2007/08/01 00:04:13 cheshire
384 <rdar://problem/5261696> Crash in tcpKQSocketCallback
385 Half-open TCP connections were not being cancelled properly
386
387 Revision 1.675 2007/07/31 02:28:35 vazquez
388 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
389
390 Revision 1.674 2007/07/31 01:57:23 cheshire
391 Adding code to respect TTL received in uDNS responses turned out to
392 expose other problems; backing out change for now.
393
394 Revision 1.673 2007/07/30 23:31:26 cheshire
395 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
396
397 Revision 1.672 2007/07/28 01:25:56 cheshire
398 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
399
400 Revision 1.671 2007/07/27 22:32:54 cheshire
401 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
402 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
403
404 Revision 1.670 2007/07/27 20:54:43 cheshire
405 Fixed code to respect real record TTL received in uDNS responses
406
407 Revision 1.669 2007/07/27 20:09:32 cheshire
408 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
409
410 Revision 1.668 2007/07/27 19:58:47 cheshire
411 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
412
413 Revision 1.667 2007/07/27 19:52:10 cheshire
414 Don't increment m->rrcache_active for no-cache add events
415
416 Revision 1.666 2007/07/27 19:30:39 cheshire
417 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
418 to properly reflect tri-state nature of the possible responses
419
420 Revision 1.665 2007/07/27 18:44:01 cheshire
421 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
422
423 Revision 1.664 2007/07/27 18:38:56 cheshire
424 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
425
426 Revision 1.663 2007/07/25 03:05:02 vazquez
427 Fixes for:
428 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
429 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
430 and a myriad of other security problems
431
432 Revision 1.662 2007/07/24 20:22:46 cheshire
433 Make sure all fields of main mDNS object are initialized correctly
434
435 Revision 1.661 2007/07/21 00:54:45 cheshire
436 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
437
438 Revision 1.660 2007/07/20 20:00:45 cheshire
439 "Legacy Browse" is better called "Automatic Browse"
440
441 Revision 1.659 2007/07/20 00:54:18 cheshire
442 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
443
444 Revision 1.658 2007/07/18 02:28:57 cheshire
445 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
446
447 Revision 1.657 2007/07/18 00:57:10 cheshire
448 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
449 Only need to call AddNewClientTunnel() for IPv6 addresses
450
451 Revision 1.656 2007/07/16 23:54:48 cheshire
452 <rdar://problem/5338850> Crash when removing or changing DNS keys
453
454 Revision 1.655 2007/07/16 20:11:37 vazquez
455 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
456 Init LNT stuff and handle SSDP packets
457
458 Revision 1.654 2007/07/12 23:30:23 cheshire
459 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
460
461 Revision 1.653 2007/07/12 02:51:27 cheshire
462 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
463
464 Revision 1.652 2007/07/11 23:43:42 cheshire
465 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
466
467 Revision 1.651 2007/07/11 22:44:40 cheshire
468 <rdar://problem/5328801> SIGHUP should purge the cache
469
470 Revision 1.650 2007/07/11 21:34:09 cheshire
471 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
472 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
473
474 Revision 1.649 2007/07/11 02:52:52 cheshire
475 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
476 In uDNS_RegisterService, set HostTarget for AutoTunnel services
477
478 Revision 1.648 2007/07/09 23:48:12 cheshire
479 Add parentheses around bitwise operation for clarity
480
481 Revision 1.647 2007/07/06 21:17:55 cheshire
482 Initialize m->retryGetAddr to timenow + 0x78000000;
483
484 Revision 1.646 2007/07/06 18:55:49 cheshire
485 Initialize m->NextScheduledNATOp
486
487 Revision 1.645 2007/06/29 22:55:54 cheshire
488 Move declaration of DNSServer *s; Fixed incomplete comment.
489
490 Revision 1.644 2007/06/29 00:07:29 vazquez
491 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
492
493 Revision 1.643 2007/06/20 01:10:12 cheshire
494 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
495
496 Revision 1.642 2007/06/15 21:54:50 cheshire
497 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
498
499 Revision 1.641 2007/05/25 00:30:24 cheshire
500 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
501 status matches. This is particularly important when doing a private query for an SOA record,
502 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
503 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
504
505 Revision 1.640 2007/05/25 00:25:44 cheshire
506 <rdar://problem/5227737> Need to enhance putRData to output all current known types
507
508 Revision 1.639 2007/05/23 00:51:33 cheshire
509 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
510 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
511 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
512
513 Revision 1.638 2007/05/23 00:43:16 cheshire
514 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
515
516 Revision 1.637 2007/05/14 23:53:00 cheshire
517 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
518
519 Revision 1.636 2007/05/10 23:27:15 cheshire
520 Update mDNS_Deregister_internal debugging messages
521
522 Revision 1.635 2007/05/07 20:43:45 cheshire
523 <rdar://problem/4241419> Reduce the number of queries and announcements
524
525 Revision 1.634 2007/05/04 22:09:08 cheshire
526 Only do "restarting exponential backoff sequence" for mDNS questions
527 In mDNS_RegisterInterface, only retrigger mDNS questions
528 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
529
530 Revision 1.633 2007/05/04 21:45:12 cheshire
531 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
532
533 Revision 1.632 2007/05/04 20:20:50 cheshire
534 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
535 Need to set srs->nta = mDNSNULL; when regState_NoTarget
536
537 Revision 1.631 2007/05/04 00:39:42 cheshire
538 <rdar://problem/4410011> Eliminate looping SOA lookups
539 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
540 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
541
542 Revision 1.630 2007/05/03 22:40:38 cheshire
543 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
544
545 Revision 1.629 2007/05/03 00:15:51 cheshire
546 <rdar://problem/4410011> Eliminate looping SOA lookups
547
548 Revision 1.628 2007/05/02 22:21:33 cheshire
549 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
550
551 Revision 1.627 2007/04/30 19:29:13 cheshire
552 Fix display of port number in "Updating DNS Server" message
553
554 Revision 1.626 2007/04/30 04:21:13 cheshire
555 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
556
557 Revision 1.625 2007/04/28 01:34:21 cheshire
558 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
559 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
560
561 Revision 1.624 2007/04/27 21:04:30 cheshire
562 On network configuration change, need to call uDNS_RegisterSearchDomains
563
564 Revision 1.623 2007/04/27 19:28:01 cheshire
565 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
566 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
567 -- it would start a query and then quickly cancel it, and then when
568 StartGetZoneData completed, it had a dangling pointer and crashed.)
569
570 Revision 1.622 2007/04/26 16:09:22 cheshire
571 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
572
573 Revision 1.621 2007/04/26 15:43:22 cheshire
574 Make sure DNSServer *s is non-null before using value in LogOperation
575
576 Revision 1.620 2007/04/26 13:11:05 cheshire
577 Fixed crash when logging out of VPN
578
579 Revision 1.619 2007/04/26 00:35:15 cheshire
580 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
581 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
582 inside the firewall may give answers where a public one gives none, and vice versa.)
583
584 Revision 1.618 2007/04/25 19:26:01 cheshire
585 m->NextScheduledQuery was getting set too early in SendQueries()
586 Improved "SendQueries didn't send all its queries" debugging message
587
588 Revision 1.617 2007/04/25 17:48:22 cheshire
589 Update debugging message
590
591 Revision 1.616 2007/04/25 16:38:32 cheshire
592 If negative cache entry already exists, reactivate it instead of creating a new one
593
594 Revision 1.615 2007/04/25 02:14:38 cheshire
595 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
596 Additional fixes to make LLQs work properly
597
598 Revision 1.614 2007/04/23 21:52:45 cheshire
599 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
600
601 Revision 1.613 2007/04/23 04:58:20 cheshire
602 <rdar://problem/5072548> Crash when setting extremely large TXT records
603
604 Revision 1.612 2007/04/22 20:39:38 cheshire
605 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
606
607 Revision 1.611 2007/04/22 18:16:29 cheshire
608 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
609
610 Revision 1.610 2007/04/22 06:02:02 cheshire
611 <rdar://problem/4615977> Query should immediately return failure when no server
612
613 Revision 1.609 2007/04/20 21:17:24 cheshire
614 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
615
616 Revision 1.608 2007/04/20 19:45:31 cheshire
617 In LogAllOperations mode, dump out unknown DNS packets in their entirety
618
619 Revision 1.607 2007/04/19 23:56:25 cheshire
620 Don't do cache-flush processing for LLQ answers
621
622 Revision 1.606 2007/04/19 22:50:53 cheshire
623 <rdar://problem/4246187> Identical client queries should reference a single shared core query
624
625 Revision 1.605 2007/04/19 20:06:41 cheshire
626 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
627
628 Revision 1.604 2007/04/19 18:03:04 cheshire
629 Add "const" declaration
630
631 Revision 1.603 2007/04/06 21:00:25 cheshire
632 Fix log message typo
633
634 Revision 1.602 2007/04/05 22:55:35 cheshire
635 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
636
637 Revision 1.601 2007/04/04 21:48:52 cheshire
638 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
639
640 Revision 1.600 2007/04/04 01:31:33 cheshire
641 Improve debugging message
642
643 Revision 1.599 2007/04/04 00:03:26 cheshire
644 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
645
646 Revision 1.598 2007/04/03 19:43:16 cheshire
647 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
648
649 Revision 1.597 2007/03/31 00:32:32 cheshire
650 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
651
652 Revision 1.596 2007/03/28 20:59:26 cheshire
653 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
654
655 Revision 1.595 2007/03/26 23:48:16 cheshire
656 <rdar://problem/4848295> Advertise model information via Bonjour
657 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
658
659 Revision 1.594 2007/03/26 23:05:05 cheshire
660 <rdar://problem/5089257> Don't cache TSIG records
661
662 Revision 1.593 2007/03/23 17:40:08 cheshire
663 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
664
665 Revision 1.592 2007/03/22 18:31:48 cheshire
666 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
667
668 Revision 1.591 2007/03/22 00:49:19 cheshire
669 <rdar://problem/4848295> Advertise model information via Bonjour
670
671 Revision 1.590 2007/03/21 23:05:59 cheshire
672 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
673
674 Revision 1.589 2007/03/20 15:37:19 cheshire
675 Delete unnecessary log message
676
677 Revision 1.588 2007/03/20 00:24:44 cheshire
678 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
679
680 Revision 1.587 2007/03/16 22:10:56 cheshire
681 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
682
683 Revision 1.586 2007/03/10 03:26:44 cheshire
684 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
685
686 Revision 1.585 2007/03/10 02:02:58 cheshire
687 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
688 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
689
690 Revision 1.584 2007/02/28 01:51:27 cheshire
691 Added comment about reverse-order IP address
692
693 Revision 1.583 2007/01/27 03:19:33 cheshire
694 Need to initialize question->sock
695
696 Revision 1.582 2007/01/25 00:40:16 cheshire
697 Unified CNAME-following functionality into cache management code (which means CNAME-following
698 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
699
700 Revision 1.581 2007/01/23 02:56:11 cheshire
701 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
702
703 Revision 1.580 2007/01/19 21:17:33 cheshire
704 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
705
706 Revision 1.579 2007/01/19 18:39:10 cheshire
707 Fix a bunch of parameters that should have been declared "const"
708
709 Revision 1.578 2007/01/10 22:51:57 cheshire
710 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
711
712 Revision 1.577 2007/01/10 02:05:21 cheshire
713 Delay uDNS_SetupDNSConfig() until *after* the platform layer
714 has set up the interface list and security credentials
715
716 Revision 1.576 2007/01/09 02:40:57 cheshire
717 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
718 moved it to mDNS_Init() in mDNS.c (core code)
719
720 Revision 1.575 2007/01/09 00:17:25 cheshire
721 Improve "ERROR m->CurrentRecord already set" debugging messages
722
723 Revision 1.574 2007/01/05 08:30:41 cheshire
724 Trim excessive "$Log" checkin history from before 2006
725 (checkin history still available via "cvs log ..." of course)
726
727 Revision 1.573 2007/01/05 06:34:03 cheshire
728 Improve "ERROR m->CurrentQuestion already set" debugging messages
729
730 Revision 1.572 2007/01/04 23:11:11 cheshire
731 <rdar://problem/4720673> uDNS: Need to start caching unicast records
732 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
733
734 Revision 1.571 2007/01/04 21:45:20 cheshire
735 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
736 to do additional lock sanity checking around callback invocations
737
738 Revision 1.570 2007/01/04 20:57:47 cheshire
739 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
740
741 Revision 1.569 2007/01/04 20:27:27 cheshire
742 Change a LogMsg() to debugf()
743
744 Revision 1.568 2007/01/04 02:39:53 cheshire
745 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
746
747 Revision 1.567 2006/12/21 00:01:37 cheshire
748 Tidy up code alignment
749
750 Revision 1.566 2006/12/20 04:07:34 cheshire
751 Remove uDNS_info substructure from AuthRecord_struct
752
753 Revision 1.565 2006/12/19 22:49:23 cheshire
754 Remove uDNS_info substructure from ServiceRecordSet_struct
755
756 Revision 1.564 2006/12/19 02:38:20 cheshire
757 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
758
759 Revision 1.563 2006/12/19 02:18:48 cheshire
760 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
761
762 Revision 1.562 2006/12/16 01:58:31 cheshire
763 <rdar://problem/4720673> uDNS: Need to start caching unicast records
764
765 Revision 1.561 2006/12/01 07:38:53 herscher
766 Only perform cache workaround fix if query is wide-area
767
768 Revision 1.560 2006/11/30 23:07:56 herscher
769 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
770
771 Revision 1.559 2006/11/27 08:20:57 cheshire
772 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
773
774 Revision 1.558 2006/11/10 07:44:03 herscher
775 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
776
777 Revision 1.557 2006/11/10 01:12:51 cheshire
778 <rdar://problem/4829718> Incorrect TTL corrections
779
780 Revision 1.556 2006/11/10 00:54:14 cheshire
781 <rdar://problem/4816598> Changing case of Computer Name doesn't work
782
783 Revision 1.555 2006/10/30 20:03:37 cheshire
784 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
785
786 Revision 1.554 2006/10/20 05:35:04 herscher
787 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
788
789 Revision 1.553 2006/10/05 03:42:43 herscher
790 Remove embedded uDNS_info struct in DNSQuestion_struct
791
792 Revision 1.552 2006/09/15 21:20:15 cheshire
793 Remove uDNS_info substructure from mDNS_struct
794
795 Revision 1.551 2006/08/14 23:24:22 cheshire
796 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
797
798 Revision 1.550 2006/07/27 17:58:34 cheshire
799 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
800
801 Revision 1.549 2006/07/20 22:07:31 mkrochma
802 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
803 More fixes for uninitialized variables
804
805 Revision 1.548 2006/07/20 19:30:19 mkrochma
806 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
807
808 Revision 1.547 2006/07/15 02:31:30 cheshire
809 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
810
811 Revision 1.546 2006/07/07 01:09:09 cheshire
812 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
813 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
814
815 Revision 1.545 2006/07/05 23:10:30 cheshire
816 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
817 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
818
819 Revision 1.544 2006/06/29 07:42:14 cheshire
820 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
821
822 Revision 1.543 2006/06/29 01:38:43 cheshire
823 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
824
825 Revision 1.542 2006/06/27 23:40:29 cheshire
826 Fix typo in comment: mis-spelled "compile"
827
828 Revision 1.541 2006/06/27 19:46:24 cheshire
829 Updated comments and debugging messages
830
831 Revision 1.540 2006/06/15 21:35:16 cheshire
832 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
833 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
834
835 Revision 1.539 2006/06/08 23:45:46 cheshire
836 Change SimultaneousProbe messages from debugf() to LogOperation()
837
838 Revision 1.538 2006/03/19 17:13:06 cheshire
839 <rdar://problem/4483117> Need faster purging of stale records
840 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
841 and reconfirm whole chain of antecedents ot once
842
843 Revision 1.537 2006/03/19 02:00:07 cheshire
844 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
845
846 Revision 1.536 2006/03/08 23:29:53 cheshire
847 <rdar://problem/4468716> Improve "Service Renamed" log message
848
849 Revision 1.535 2006/03/02 20:41:17 cheshire
850 <rdar://problem/4111464> After record update, old record sometimes remains in cache
851 Minor code tidying and comments to reduce the risk of similar programming errors in future
852
853 Revision 1.534 2006/03/02 03:25:46 cheshire
854 <rdar://problem/4111464> After record update, old record sometimes remains in cache
855 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
856
857 Revision 1.533 2006/02/26 00:54:41 cheshire
858 Fixes to avoid code generation warning/error on FreeBSD 7
859
860 */
861
862 #include "DNSCommon.h" // Defines general DNS untility routines
863 #include "uDNS.h" // Defines entry points into unicast-specific routines
864
865 // Disable certain benign warnings with Microsoft compilers
866 #if(defined(_MSC_VER))
867 // Disable "conditional expression is constant" warning for debug macros.
868 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
869 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
870 #pragma warning(disable:4127)
871
872 // Disable "assignment within conditional expression".
873 // Other compilers understand the convention that if you place the assignment expression within an extra pair
874 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
875 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
876 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
877 #pragma warning(disable:4706)
878 #endif
879
880 // ***************************************************************************
881 #if COMPILER_LIKES_PRAGMA_MARK
882 #pragma mark - Program Constants
883 #endif
884
885 #define NO_HINFO 1
886
887 mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
888
889 // Any records bigger than this are considered 'large' records
890 #define SmallRecordLimit 1024
891
892 #define kMaxUpdateCredits 10
893 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
894
895 mDNSexport const char *const mDNS_DomainTypeNames[] =
896 {
897 "b._dns-sd._udp.", // Browse
898 "db._dns-sd._udp.", // Default Browse
899 "lb._dns-sd._udp.", // Automatic Browse
900 "r._dns-sd._udp.", // Registration
901 "dr._dns-sd._udp." // Default Registration
902 };
903
904 #ifdef UNICAST_DISABLED
905 #define uDNS_IsActiveQuery(q, u) mDNSfalse
906 #endif
907
908 // ***************************************************************************
909 #if COMPILER_LIKES_PRAGMA_MARK
910 #pragma mark -
911 #pragma mark - General Utility Functions
912 #endif
913
914 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
915 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
916
917 mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
918 {
919 if (m->mDNS_busy != m->mDNS_reentrancy+1)
920 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
921
922 #if ForceAlerts
923 if (m->mDNS_busy != m->mDNS_reentrancy+1) *(long*)0 = 0;
924 #endif
925
926 if (ActiveQuestion(q))
927 {
928 mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
929
930 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
931 if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
932 sendtime = m->SuppressStdPort53Queries;
933
934 if (m->NextScheduledQuery - sendtime > 0)
935 m->NextScheduledQuery = sendtime;
936 }
937 }
938
939 mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
940 {
941 CacheGroup *cg;
942 for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
943 if (cg->namehash == namehash && SameDomainName(cg->name, name))
944 break;
945 return(cg);
946 }
947
948 mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
949 {
950 return(CacheGroupForName(m, slot, rr->namehash, rr->name));
951 }
952
953 mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
954 {
955 NetworkInterfaceInfo *intf;
956
957 if (addr->type == mDNSAddrType_IPv4)
958 {
959 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
960 if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
961 for (intf = m->HostInterfaces; intf; intf = intf->next)
962 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
963 if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
964 return(mDNStrue);
965 }
966
967 if (addr->type == mDNSAddrType_IPv6)
968 {
969 if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
970 for (intf = m->HostInterfaces; intf; intf = intf->next)
971 if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
972 if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
973 (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
974 (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
975 (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
976 return(mDNStrue);
977 }
978
979 return(mDNSfalse);
980 }
981
982 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
983 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
984 mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
985 {
986 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
987 if (AddRecord) rr->AnsweredLocalQ = mDNStrue;
988 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
989 if (q->QuestionCallback && !q->NoAnswer)
990 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
991 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
992 }
993
994 // When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
995 // to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
996 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
997 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
998 mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
999 {
1000 if (m->CurrentQuestion)
1001 LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
1002
1003 m->CurrentQuestion = m->LocalOnlyQuestions;
1004 while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
1005 {
1006 DNSQuestion *q = m->CurrentQuestion;
1007 m->CurrentQuestion = q->next;
1008 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1009 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
1010 }
1011
1012 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1013 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
1014 {
1015 m->CurrentQuestion = m->Questions;
1016 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
1017 {
1018 DNSQuestion *q = m->CurrentQuestion;
1019 m->CurrentQuestion = q->next;
1020 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
1021 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again
1022 }
1023 }
1024
1025 m->CurrentQuestion = mDNSNULL;
1026 }
1027
1028 // ***************************************************************************
1029 #if COMPILER_LIKES_PRAGMA_MARK
1030 #pragma mark -
1031 #pragma mark - Resource Record Utility Functions
1032 #endif
1033
1034 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1035
1036 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1037 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1038 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1039 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1040
1041 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1042 (ResourceRecordIsValidAnswer(RR) && \
1043 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1044
1045 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1046 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1047
1048 #define InitialAnnounceCount ((mDNSu8)8)
1049
1050 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1051 // This means that because the announce interval is doubled after sending the first packet, the first
1052 // observed on-the-wire inter-packet interval between announcements is actually one second.
1053 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1054 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1055 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1056 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1057
1058 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1059 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1060 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1061
1062 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1063 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1064 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1065 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1066
1067 #define MaxUnansweredQueries 4
1068
1069 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1070 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1071 // TTL and rdata may differ.
1072 // This is used for cache flush management:
1073 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1074 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1075
1076 mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const AuthRecord *const r2)
1077 {
1078 if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
1079 if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
1080 if (r1->resrec.InterfaceID &&
1081 r2->resrec.InterfaceID &&
1082 r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
1083 return(mDNSBool)(
1084 r1->resrec.rrtype == r2->resrec.rrtype &&
1085 r1->resrec.rrclass == r2->resrec.rrclass &&
1086 r1->resrec.namehash == r2->resrec.namehash &&
1087 SameDomainName(r1->resrec.name, r2->resrec.name));
1088 }
1089
1090 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1091 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1092 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1093 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1094 // so a response of any type should match, even if it is not actually the type the client plans to use.
1095 mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr)
1096 {
1097 if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); }
1098 if (!authrr) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse); }
1099 if (pktrr->resrec.InterfaceID &&
1100 authrr->resrec.InterfaceID &&
1101 pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
1102 if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
1103 return(mDNSBool)(
1104 pktrr->resrec.rrclass == authrr->resrec.rrclass &&
1105 pktrr->resrec.namehash == authrr->resrec.namehash &&
1106 SameDomainName(pktrr->resrec.name, authrr->resrec.name));
1107 }
1108
1109 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1110 // This is the information that the requester believes to be correct.
1111 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1112 // This is the information that we believe to be correct.
1113 // We've already determined that we plan to give this answer on this interface
1114 // (either the record is non-specific, or it is specific to this interface)
1115 // so now we just need to check the name, type, class, rdata and TTL.
1116 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
1117 {
1118 // If RR signature is different, or data is different, then don't suppress our answer
1119 if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
1120
1121 // If the requester's indicated TTL is less than half the real TTL,
1122 // we need to give our answer before the requester's copy expires.
1123 // If the requester's indicated TTL is at least half the real TTL,
1124 // then we can suppress our answer this time.
1125 // If the requester's indicated TTL is greater than the TTL we believe,
1126 // then that's okay, and we don't need to do anything about it.
1127 // (If two responders on the network are offering the same information,
1128 // that's okay, and if they are offering the information with different TTLs,
1129 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1130 return(mDNSBool)(ka->resrec.rroriginalttl >= rr->resrec.rroriginalttl / 2);
1131 }
1132
1133 mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const rr)
1134 {
1135 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1136 {
1137 //LogMsg("ProbeCount %d Next %ld %s",
1138 // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1139 if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1140 m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
1141 }
1142 else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
1143 {
1144 if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
1145 m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
1146 }
1147 }
1148
1149 mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 interval)
1150 {
1151 rr->ThisAPInterval = interval;
1152
1153 // To allow us to aggregate probes when a group of services are registered together,
1154 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1155 // 1/4 second wait; probe
1156 // 1/4 second wait; probe
1157 // 1/4 second wait; probe
1158 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1159
1160 if (rr->ProbeCount)
1161 {
1162 // If we have no probe suppression time set, or it is in the past, set it now
1163 if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
1164 {
1165 m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
1166 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1167 if (m->SuppressProbes - m->NextScheduledProbe >= 0)
1168 m->SuppressProbes = m->NextScheduledProbe;
1169 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1170 if (m->SuppressProbes - m->NextScheduledQuery >= 0)
1171 m->SuppressProbes = m->NextScheduledQuery;
1172 }
1173 }
1174
1175 rr->LastAPTime = m->SuppressProbes - interval;
1176 // Set LastMCTime to now, to inhibit multicast responses
1177 // (no need to send additional multicast responses when we're announcing anyway)
1178 rr->LastMCTime = m->timenow;
1179 rr->LastMCInterface = mDNSInterfaceMark;
1180
1181 // If this is a record type that's not going to probe, then delay its first announcement so that
1182 // it will go out synchronized with the first announcement for the other records that *are* probing.
1183 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1184 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1185 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1186 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1187 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1188 // The exception is unique records that have already been verified and are just being updated
1189 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1190 if (rr->resrec.RecordType == kDNSRecordTypeVerified)
1191 rr->LastAPTime = m->timenow - interval;
1192 else if (rr->resrec.RecordType != kDNSRecordTypeUnique)
1193 rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + interval / 2;
1194
1195 SetNextAnnounceProbeTime(m, rr);
1196 }
1197
1198 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1199 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1200 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
1201 {
1202 domainname *target = GetRRDomainNameTarget(&rr->resrec);
1203
1204 if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
1205
1206 if (target && SameDomainName(target, &m->MulticastHostname))
1207 debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
1208
1209 if (target && !SameDomainName(target, &m->MulticastHostname))
1210 {
1211 AssignDomainName(target, &m->MulticastHostname);
1212 SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
1213
1214 // If we're in the middle of probing this record, we need to start again,
1215 // because changing its rdata may change the outcome of the tie-breaker.
1216 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1217 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1218
1219 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1220 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1221 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1222 if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
1223 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1224 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1225
1226 rr->AnnounceCount = InitialAnnounceCount;
1227 rr->RequireGoodbye = mDNSfalse;
1228 InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
1229 }
1230 }
1231
1232 mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
1233 {
1234 if (rr->RecordCallback)
1235 {
1236 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1237 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1238 rr->Acknowledged = mDNStrue;
1239 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1240 rr->RecordCallback(m, rr, mStatus_NoError);
1241 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1242 }
1243 }
1244
1245 mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
1246 {
1247 rr->ProbeCount = 0;
1248 rr->AnnounceCount = 0;
1249 rr->ThisAPInterval = 5 * mDNSPlatformOneSecond; // After doubling, first retry will happen after ten seconds
1250 rr->LastAPTime = m->timenow - rr->ThisAPInterval;
1251 rr->state = regState_FetchingZoneData;
1252 rr->uselease = mDNStrue;
1253 }
1254
1255 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1256 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1257 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1258 #define RecordIsLocalDuplicate(A,B) \
1259 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1260
1261 // Exported so uDNS.c can call this
1262 mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
1263 {
1264 domainname *target = GetRRDomainNameTarget(&rr->resrec);
1265 AuthRecord *r;
1266 AuthRecord **p = &m->ResourceRecords;
1267 AuthRecord **d = &m->DuplicateRecords;
1268
1269 if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
1270 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1271
1272 if (!rr->resrec.RecordType)
1273 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
1274
1275 while (*p && *p != rr) p=&(*p)->next;
1276 while (*d && *d != rr) d=&(*d)->next;
1277 if (*d || *p)
1278 {
1279 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1280 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1281 return(mStatus_AlreadyRegistered);
1282 }
1283
1284 if (rr->DependentOn)
1285 {
1286 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
1287 rr->resrec.RecordType = kDNSRecordTypeVerified;
1288 else
1289 {
1290 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1291 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1292 return(mStatus_Invalid);
1293 }
1294 if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
1295 {
1296 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1297 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
1298 return(mStatus_Invalid);
1299 }
1300 }
1301
1302 // If this resource record is referencing a specific interface, make sure it exists
1303 if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
1304 {
1305 NetworkInterfaceInfo *intf;
1306 for (intf = m->HostInterfaces; intf; intf = intf->next)
1307 if (intf->InterfaceID == rr->resrec.InterfaceID) break;
1308 if (!intf)
1309 {
1310 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID);
1311 return(mStatus_BadReferenceErr);
1312 }
1313 }
1314
1315 rr->next = mDNSNULL;
1316
1317 // Field Group 1: The actual information pertaining to this resource record
1318 // Set up by client prior to call
1319
1320 // Field Group 2: Persistent metadata for Authoritative Records
1321 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1322 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1323 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1324 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1325 // rr->Callback = already set in mDNS_SetupResourceRecord
1326 // rr->Context = already set in mDNS_SetupResourceRecord
1327 // rr->RecordType = already set in mDNS_SetupResourceRecord
1328 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1329 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1330 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
1331 if (rr->AutoTarget && target) target->c[0] = 0;
1332
1333 // Field Group 3: Transient state for Authoritative Records
1334 rr->Acknowledged = mDNSfalse;
1335 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
1336 rr->AnnounceCount = InitialAnnounceCount;
1337 rr->RequireGoodbye = mDNSfalse;
1338 rr->AnsweredLocalQ = mDNSfalse;
1339 rr->IncludeInProbe = mDNSfalse;
1340 rr->ImmedAnswer = mDNSNULL;
1341 rr->ImmedUnicast = mDNSfalse;
1342 rr->ImmedAdditional = mDNSNULL;
1343 rr->SendRNow = mDNSNULL;
1344 rr->v4Requester = zerov4Addr;
1345 rr->v6Requester = zerov6Addr;
1346 rr->NextResponse = mDNSNULL;
1347 rr->NR_AnswerTo = mDNSNULL;
1348 rr->NR_AdditionalTo = mDNSNULL;
1349 if (!rr->AutoTarget) InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
1350 // rr->LastAPTime = Set for us in InitializeLastAPTime()
1351 // rr->LastMCTime = Set for us in InitializeLastAPTime()
1352 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
1353 rr->NewRData = mDNSNULL;
1354 rr->newrdlength = 0;
1355 rr->UpdateCallback = mDNSNULL;
1356 rr->UpdateCredits = kMaxUpdateCredits;
1357 rr->NextUpdateCredit = 0;
1358 rr->UpdateBlocked = 0;
1359
1360 // Field Group 4: Transient uDNS state for Authoritative Records
1361 rr->state = regState_Zero;
1362 rr->uselease = 0;
1363 rr->expire = 0;
1364 rr->Private = 0;
1365 rr->id = zeroID;
1366 rr->zone.c[0] = 0;
1367 rr->UpdateServer = zeroAddr;
1368 rr->UpdatePort = zeroIPPort;
1369 rr->nta = mDNSNULL;
1370 rr->tcp = mDNSNULL;
1371 rr->OrigRData = 0;
1372 rr->OrigRDLen = 0;
1373 rr->InFlightRData = 0;
1374 rr->InFlightRDLen = 0;
1375 rr->QueuedRData = 0;
1376 rr->QueuedRDLen = 0;
1377
1378 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
1379 // rr->resrec.name->c = MUST be set by client
1380 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
1381 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
1382 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
1383 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
1384
1385 if (rr->AutoTarget)
1386 SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
1387 else
1388 {
1389 rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
1390 rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
1391 }
1392
1393 if (!ValidateDomainName(rr->resrec.name))
1394 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1395
1396 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1397 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1398 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1399 if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
1400
1401 // Don't do this until *after* we've set rr->resrec.rdlength
1402 if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
1403 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
1404
1405 rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
1406 rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
1407
1408 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
1409 {
1410 // If this is supposed to be unique, make sure we don't have any name conflicts
1411 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1412 {
1413 const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
1414 for (r = m->ResourceRecords; r; r=r->next)
1415 {
1416 const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
1417 if (s1 != s2 && SameResourceRecordSignature(r, rr) && !SameRData(&r->resrec, &rr->resrec))
1418 break;
1419 }
1420 if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
1421 {
1422 debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1423 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
1424 rr->resrec.rroriginalttl = 0;
1425 rr->ImmedAnswer = mDNSInterfaceMark;
1426 m->NextScheduledResponse = m->timenow;
1427 }
1428 }
1429 }
1430
1431 // Now that we've finished building our new record, make sure it's not identical to one we already have
1432 for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
1433
1434 if (r)
1435 {
1436 debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
1437 *d = rr;
1438 // If the previous copy of this record is already verified unique,
1439 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
1440 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
1441 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
1442 if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
1443 rr->ProbeCount = 0;
1444 }
1445 else
1446 {
1447 debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
1448 if (!m->NewLocalRecords) m->NewLocalRecords = rr;
1449 *p = rr;
1450 }
1451
1452 if (!AuthRecord_uDNS(rr))
1453 {
1454 // For records that are not going to probe, acknowledge them right away
1455 if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
1456 AcknowledgeRecord(m, rr);
1457 }
1458 #ifndef UNICAST_DISABLED
1459 else
1460 {
1461 if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
1462 ActivateUnicastRegistration(m, rr);
1463 }
1464 #endif
1465
1466 return(mStatus_NoError);
1467 }
1468
1469 mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
1470 {
1471 m->ProbeFailTime = m->timenow;
1472 m->NumFailedProbes++;
1473 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
1474 // If a bunch of hosts have all been configured with the same name, then they'll all
1475 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
1476 // up to name-10. After that they'll start adding random increments in the range 1-100,
1477 // so they're more likely to branch out in the available namespace and settle on a set of
1478 // unique names quickly. If after five more tries the host is still conflicting, then we
1479 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
1480 if (m->NumFailedProbes >= 15)
1481 {
1482 m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
1483 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
1484 m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1485 }
1486 }
1487
1488 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
1489 {
1490 RData *OldRData = rr->resrec.rdata;
1491 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); // Update our rdata
1492 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
1493 if (rr->UpdateCallback)
1494 rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
1495 }
1496
1497 // NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
1498 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1499 // Exported so uDNS.c can call this
1500 mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
1501 {
1502 AuthRecord *r2;
1503 mDNSu8 RecordType = rr->resrec.RecordType;
1504 AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
1505
1506 while (*p && *p != rr) p=&(*p)->next;
1507
1508 if (*p)
1509 {
1510 // We found our record on the main list. See if there are any duplicates that need special handling.
1511 if (drt == mDNS_Dereg_conflict) // If this was a conflict, see that all duplicates get the same treatment
1512 {
1513 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
1514 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
1515 for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
1516 }
1517 else
1518 {
1519 // Before we delete the record (and potentially send a goodbye packet)
1520 // first see if we have a record on the duplicate list ready to take over from it.
1521 AuthRecord **d = &m->DuplicateRecords;
1522 while (*d && !RecordIsLocalDuplicate(*d, rr)) d=&(*d)->next;
1523 if (*d)
1524 {
1525 AuthRecord *dup = *d;
1526 debugf("Duplicate record %p taking over from %p %##s (%s)",
1527 dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1528 *d = dup->next; // Cut replacement record from DuplicateRecords list
1529 dup->next = rr->next; // And then...
1530 rr->next = dup; // ... splice it in right after the record we're about to delete
1531 dup->resrec.RecordType = rr->resrec.RecordType;
1532 dup->ProbeCount = rr->ProbeCount;
1533 dup->AnnounceCount = rr->AnnounceCount;
1534 dup->RequireGoodbye = rr->RequireGoodbye;
1535 dup->ImmedAnswer = rr->ImmedAnswer;
1536 dup->ImmedUnicast = rr->ImmedUnicast;
1537 dup->ImmedAdditional = rr->ImmedAdditional;
1538 dup->v4Requester = rr->v4Requester;
1539 dup->v6Requester = rr->v6Requester;
1540 dup->ThisAPInterval = rr->ThisAPInterval;
1541 dup->LastAPTime = rr->LastAPTime;
1542 dup->LastMCTime = rr->LastMCTime;
1543 dup->LastMCInterface = rr->LastMCInterface;
1544 rr->RequireGoodbye = mDNSfalse;
1545 }
1546 }
1547 }
1548 else
1549 {
1550 // We didn't find our record on the main list; try the DuplicateRecords list instead.
1551 p = &m->DuplicateRecords;
1552 while (*p && *p != rr) p=&(*p)->next;
1553 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
1554 if (*p) rr->RequireGoodbye = mDNSfalse;
1555 if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
1556 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1557 }
1558
1559 if (!*p)
1560 {
1561 // No need to log an error message if we already know this is a potentially repeated deregistration
1562 if (drt != mDNS_Dereg_repeat)
1563 LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
1564 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1565 return(mStatus_BadReferenceErr);
1566 }
1567
1568 // If this is a shared record and we've announced it at least once,
1569 // we need to retract that announcement before we delete the record
1570
1571 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local answers then
1572 // it's tempting to just do "AnswerLocalQuestions(m, rr, mDNSfalse)" here, but that would not not be safe.
1573 // The AnswerLocalQuestions routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
1574 // mechanism to cope with the client callback modifying the question list while that's happening.
1575 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
1576 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
1577 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
1578 // records, thereby invoking yet more callbacks, without limit.
1579 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
1580 // actual goodbye packets.
1581
1582 #ifndef UNICAST_DISABLED
1583 if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
1584 {
1585 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
1586 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
1587 uDNS_DeregisterRecord(m, rr);
1588 // At this point unconditionally we bail out
1589 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
1590 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
1591 // process and will complete asynchronously. Either way we don't need to do anything more here.
1592 return(mStatus_NoError);
1593 }
1594 #endif UNICAST_DISABLED
1595
1596 if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
1597 {
1598 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
1599 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
1600 rr->resrec.rroriginalttl = 0;
1601 rr->ImmedAnswer = mDNSInterfaceMark;
1602 if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
1603 m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
1604 }
1605 else
1606 {
1607 *p = rr->next; // Cut this record from the list
1608 // If someone is about to look at this, bump the pointer forward
1609 if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
1610 if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
1611 rr->next = mDNSNULL;
1612
1613 if (RecordType == kDNSRecordTypeUnregistered)
1614 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
1615 else if (RecordType == kDNSRecordTypeDeregistering)
1616 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
1617 else
1618 {
1619 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
1620 rr->resrec.RecordType = kDNSRecordTypeUnregistered;
1621 }
1622
1623 if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
1624 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
1625 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1626
1627 // If we have an update queued up which never executed, give the client a chance to free that memory
1628 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
1629
1630 if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
1631 if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
1632
1633 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1634 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1635 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
1636 // so any attempt to touch rr after this is likely to lead to a crash.
1637 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1638 if (drt != mDNS_Dereg_conflict)
1639 {
1640 if (rr->RecordCallback)
1641 rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
1642 }
1643 else
1644 {
1645 RecordProbeFailure(m, rr);
1646 if (rr->RecordCallback)
1647 rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
1648 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
1649 // Note that with all the client callbacks going on, by the time we get here all the
1650 // records we marked may have been explicitly deregistered by the client anyway.
1651 r2 = m->DuplicateRecords;
1652 while (r2)
1653 {
1654 if (r2->ProbeCount != 0xFF) r2 = r2->next;
1655 else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
1656 }
1657 }
1658 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1659 }
1660 return(mStatus_NoError);
1661 }
1662
1663 // ***************************************************************************
1664 #if COMPILER_LIKES_PRAGMA_MARK
1665 #pragma mark -
1666 #pragma mark - Packet Sending Functions
1667 #endif
1668
1669 mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *add)
1670 {
1671 if (rr->NextResponse == mDNSNULL && *nrpp != &rr->NextResponse)
1672 {
1673 **nrpp = rr;
1674 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
1675 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
1676 // The referenced record will definitely be acceptable (by recursive application of this rule)
1677 if (add && add->NR_AdditionalTo) add = add->NR_AdditionalTo;
1678 rr->NR_AdditionalTo = add;
1679 *nrpp = &rr->NextResponse;
1680 }
1681 debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
1682 }
1683
1684 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
1685 {
1686 AuthRecord *rr, *rr2;
1687 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // For each record we plan to put
1688 {
1689 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
1690 // later in the "for" loop, and we will follow further "additional" links then.)
1691 if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
1692 AddRecordToResponseList(nrpp, rr->Additional1, rr);
1693
1694 if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
1695 AddRecordToResponseList(nrpp, rr->Additional2, rr);
1696
1697 // For SRV records, automatically add the Address record(s) for the target host
1698 if (rr->resrec.rrtype == kDNSType_SRV)
1699 {
1700 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
1701 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
1702 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
1703 rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
1704 SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
1705 AddRecordToResponseList(nrpp, rr2, rr);
1706 }
1707 else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional
1708 {
1709 for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
1710 if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
1711 ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
1712 rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name
1713 SameDomainName(rr->resrec.name, rr2->resrec.name))
1714 AddRecordToResponseList(nrpp, rr2, rr);
1715 }
1716 else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record
1717 {
1718 if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
1719 SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
1720 AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
1721 }
1722 }
1723 }
1724
1725 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
1726 {
1727 AuthRecord *rr;
1728 AuthRecord *ResponseRecords = mDNSNULL;
1729 AuthRecord **nrp = &ResponseRecords;
1730
1731 // Make a list of all our records that need to be unicast to this destination
1732 for (rr = m->ResourceRecords; rr; rr=rr->next)
1733 {
1734 // If we find we can no longer unicast this answer, clear ImmedUnicast
1735 if (rr->ImmedAnswer == mDNSInterfaceMark ||
1736 mDNSSameIPv4Address(rr->v4Requester, onesIPv4Addr) ||
1737 mDNSSameIPv6Address(rr->v6Requester, onesIPv6Addr) )
1738 rr->ImmedUnicast = mDNSfalse;
1739
1740 if (rr->ImmedUnicast && rr->ImmedAnswer == InterfaceID)
1741 if ((dest->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->v4Requester, dest->ip.v4)) ||
1742 (dest->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->v6Requester, dest->ip.v6)))
1743 {
1744 rr->ImmedAnswer = mDNSNULL; // Clear the state fields
1745 rr->ImmedUnicast = mDNSfalse;
1746 rr->v4Requester = zerov4Addr;
1747 rr->v6Requester = zerov6Addr;
1748 if (rr->NextResponse == mDNSNULL && nrp != &rr->NextResponse) // rr->NR_AnswerTo
1749 { rr->NR_AnswerTo = (mDNSu8*)~0; *nrp = rr; nrp = &rr->NextResponse; }
1750 }
1751 }
1752
1753 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
1754
1755 while (ResponseRecords)
1756 {
1757 mDNSu8 *responseptr = m->omsg.data;
1758 mDNSu8 *newptr;
1759 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
1760
1761 // Put answers in the packet
1762 while (ResponseRecords && ResponseRecords->NR_AnswerTo)
1763 {
1764 rr = ResponseRecords;
1765 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1766 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
1767 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
1768 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
1769 if (!newptr && m->omsg.h.numAnswers) break; // If packet full, send it now
1770 if (newptr) responseptr = newptr;
1771 ResponseRecords = rr->NextResponse;
1772 rr->NextResponse = mDNSNULL;
1773 rr->NR_AnswerTo = mDNSNULL;
1774 rr->NR_AdditionalTo = mDNSNULL;
1775 rr->RequireGoodbye = mDNStrue;
1776 }
1777
1778 // Add additionals, if there's space
1779 while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
1780 {
1781 rr = ResponseRecords;
1782 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1783 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
1784 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &rr->resrec);
1785 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
1786
1787 if (newptr) responseptr = newptr;
1788 if (newptr && m->omsg.h.numAnswers) rr->RequireGoodbye = mDNStrue;
1789 else if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->ImmedAnswer = mDNSInterfaceMark;
1790 ResponseRecords = rr->NextResponse;
1791 rr->NextResponse = mDNSNULL;
1792 rr->NR_AnswerTo = mDNSNULL;
1793 rr->NR_AdditionalTo = mDNSNULL;
1794 }
1795
1796 if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
1797 }
1798 }
1799
1800 mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
1801 {
1802 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
1803 // it should go ahead and immediately dispose of this registration
1804 rr->resrec.RecordType = kDNSRecordTypeShared;
1805 rr->RequireGoodbye = mDNSfalse;
1806 if (rr->AnsweredLocalQ) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
1807 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
1808 }
1809
1810 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
1811 // the record list and/or question list.
1812 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1813 mDNSlocal void DiscardDeregistrations(mDNS *const m)
1814 {
1815 if (m->CurrentRecord)
1816 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
1817 m->CurrentRecord = m->ResourceRecords;
1818
1819 while (m->CurrentRecord)
1820 {
1821 AuthRecord *rr = m->CurrentRecord;
1822 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
1823 CompleteDeregistration(m, rr); // Don't touch rr after this
1824 else
1825 m->CurrentRecord = rr->next;
1826 }
1827 }
1828
1829 mDNSlocal void GrantUpdateCredit(AuthRecord *rr)
1830 {
1831 if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0;
1832 else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval);
1833 }
1834
1835 // Note about acceleration of announcements to facilitate automatic coalescing of
1836 // multiple independent threads of announcements into a single synchronized thread:
1837 // The announcements in the packet may be at different stages of maturity;
1838 // One-second interval, two-second interval, four-second interval, and so on.
1839 // After we've put in all the announcements that are due, we then consider
1840 // whether there are other nearly-due announcements that are worth accelerating.
1841 // To be eligible for acceleration, a record MUST NOT be older (further along
1842 // its timeline) than the most mature record we've already put in the packet.
1843 // In other words, younger records can have their timelines accelerated to catch up
1844 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
1845 // Older records cannot have their timelines accelerated; this would just widen
1846 // the gap between them and their younger bretheren and get them even more out of sync.
1847
1848 // NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
1849 // the record list and/or question list.
1850 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1851 mDNSlocal void SendResponses(mDNS *const m)
1852 {
1853 int pktcount = 0;
1854 AuthRecord *rr, *r2;
1855 mDNSs32 maxExistingAnnounceInterval = 0;
1856 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
1857
1858 m->NextScheduledResponse = m->timenow + 0x78000000;
1859
1860 for (rr = m->ResourceRecords; rr; rr=rr->next)
1861 if (rr->ImmedUnicast)
1862 {
1863 mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} };
1864 mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} };
1865 v4.ip.v4 = rr->v4Requester;
1866 v6.ip.v6 = rr->v6Requester;
1867 if (!mDNSIPv4AddressIsZero(rr->v4Requester)) SendDelayedUnicastResponse(m, &v4, rr->ImmedAnswer);
1868 if (!mDNSIPv6AddressIsZero(rr->v6Requester)) SendDelayedUnicastResponse(m, &v6, rr->ImmedAnswer);
1869 if (rr->ImmedUnicast)
1870 {
1871 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m, rr));
1872 rr->ImmedUnicast = mDNSfalse;
1873 }
1874 }
1875
1876 // ***
1877 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
1878 // ***
1879
1880 // Run through our list of records, and decide which ones we're going to announce on all interfaces
1881 for (rr = m->ResourceRecords; rr; rr=rr->next)
1882 {
1883 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
1884 if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
1885 {
1886 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
1887 if (maxExistingAnnounceInterval < rr->ThisAPInterval)
1888 maxExistingAnnounceInterval = rr->ThisAPInterval;
1889 if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
1890 }
1891 }
1892
1893 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
1894 // Eligible records that are more than half-way to their announcement time are accelerated
1895 for (rr = m->ResourceRecords; rr; rr=rr->next)
1896 if ((rr->resrec.InterfaceID && rr->ImmedAnswer) ||
1897 (rr->ThisAPInterval <= maxExistingAnnounceInterval &&
1898 TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) &&
1899 ResourceRecordIsValidAnswer(rr)))
1900 rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces
1901
1902 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
1903 // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
1904 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
1905 // then all that means is that it won't get sent -- which would not be the end of the world.
1906 for (rr = m->ResourceRecords; rr; rr=rr->next)
1907 {
1908 if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
1909 for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records
1910 if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ...
1911 ResourceRecordIsValidAnswer(r2) && // ... which are valid for answer ...
1912 rr->LastMCTime - r2->LastMCTime >= 0 && // ... which we have not sent recently ...
1913 rr->resrec.rdatahash == r2->resrec.namehash && // ... whose name is the name of the SRV target
1914 SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
1915 (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
1916 r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too
1917 // We also make sure we send the DeviceInfo TXT record too, if necessary
1918 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
1919 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
1920 if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR)
1921 if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
1922 {
1923 if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer;
1924 else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark;
1925 }
1926 }
1927
1928 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
1929 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
1930 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
1931 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
1932 // -- 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
1933 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
1934 for (rr = m->ResourceRecords; rr; rr=rr->next)
1935 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
1936 {
1937 if (rr->ImmedAnswer) // If we're sending this as answer, see that its whole RRSet is similarly marked
1938 {
1939 for (r2 = m->ResourceRecords; r2; r2=r2->next)
1940 if (ResourceRecordIsValidAnswer(r2))
1941 if (r2->ImmedAnswer != mDNSInterfaceMark &&
1942 r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
1943 r2->ImmedAnswer = rr->ImmedAnswer;
1944 }
1945 else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked
1946 {
1947 for (r2 = m->ResourceRecords; r2; r2=r2->next)
1948 if (ResourceRecordIsValidAnswer(r2))
1949 if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
1950 r2->ImmedAdditional = rr->ImmedAdditional;
1951 }
1952 }
1953
1954 // Now set SendRNow state appropriately
1955 for (rr = m->ResourceRecords; rr; rr=rr->next)
1956 {
1957 if (rr->ImmedAnswer == mDNSInterfaceMark) // Sending this record on all appropriate interfaces
1958 {
1959 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
1960 rr->ImmedAdditional = mDNSNULL; // No need to send as additional if sending as answer
1961 rr->LastMCTime = m->timenow;
1962 rr->LastMCInterface = rr->ImmedAnswer;
1963 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
1964 if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
1965 {
1966 rr->AnnounceCount--;
1967 rr->ThisAPInterval *= 2;
1968 rr->LastAPTime = m->timenow;
1969 debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
1970 }
1971 }
1972 else if (rr->ImmedAnswer) // Else, just respond to a single query on single interface:
1973 {
1974 rr->SendRNow = rr->ImmedAnswer; // Just respond on that interface
1975 rr->ImmedAdditional = mDNSNULL; // No need to send as additional too
1976 rr->LastMCTime = m->timenow;
1977 rr->LastMCInterface = rr->ImmedAnswer;
1978 }
1979 SetNextAnnounceProbeTime(m, rr);
1980 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
1981 }
1982
1983 // ***
1984 // *** 2. Loop through interface list, sending records as appropriate
1985 // ***
1986
1987 while (intf)
1988 {
1989 int numDereg = 0;
1990 int numAnnounce = 0;
1991 int numAnswer = 0;
1992 mDNSu8 *responseptr = m->omsg.data;
1993 mDNSu8 *newptr;
1994 InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
1995
1996 // First Pass. Look for:
1997 // 1. Deregistering records that need to send their goodbye packet
1998 // 2. Updated records that need to retract their old data
1999 // 3. Answers and announcements we need to send
2000 // In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
2001 // send this packet and then try again.
2002 // If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
2003 // because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
2004 for (rr = m->ResourceRecords; rr; rr=rr->next)
2005 if (rr->SendRNow == intf->InterfaceID)
2006 {
2007 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2008 {
2009 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2010 if (newptr) { responseptr = newptr; numDereg++; }
2011 else if (m->omsg.h.numAnswers) break;
2012 }
2013 else if (rr->NewRData && !m->SleepState) // If we have new data for this record
2014 {
2015 RData *OldRData = rr->resrec.rdata;
2016 mDNSu16 oldrdlength = rr->resrec.rdlength;
2017 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2018 if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
2019 {
2020 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
2021 if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
2022 else if (m->omsg.h.numAnswers) break;
2023 }
2024 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2025 SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
2026 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2027 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2028 newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
2029 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2030 if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
2031 SetNewRData(&rr->resrec, OldRData, oldrdlength);
2032 }
2033 else
2034 {
2035 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2036 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2037 newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
2038 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2039 if (newptr)
2040 {
2041 responseptr = newptr;
2042 rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
2043 if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
2044 }
2045 else if (m->omsg.h.numAnswers) break;
2046 }
2047 // If sending on all interfaces, go to next interface; else we're finished now
2048 if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
2049 rr->SendRNow = GetNextActiveInterfaceID(intf);
2050 else
2051 rr->SendRNow = mDNSNULL;
2052 }
2053
2054 // Second Pass. Add additional records, if there's space.
2055 newptr = responseptr;
2056 for (rr = m->ResourceRecords; rr; rr=rr->next)
2057 if (rr->ImmedAdditional == intf->InterfaceID)
2058 if (ResourceRecordIsValidAnswer(rr))
2059 {
2060 // If we have at least one answer already in the packet, then plan to add additionals too
2061 mDNSBool SendAdditional = (m->omsg.h.numAnswers > 0);
2062
2063 // If we're not planning to send any additionals, but this record is a unique one, then
2064 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2065 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2066 if (!SendAdditional && (rr->resrec.RecordType & kDNSRecordTypeUniqueMask))
2067 {
2068 const AuthRecord *a;
2069 for (a = m->ResourceRecords; a; a=a->next)
2070 if (a->LastMCTime == m->timenow &&
2071 a->LastMCInterface == intf->InterfaceID &&
2072 SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; }
2073 }
2074 if (!SendAdditional) // If we don't want to send this after all,
2075 rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field
2076 else if (newptr) // Else, try to add it if we can
2077 {
2078 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
2079 rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
2080 newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec);
2081 rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
2082 if (newptr)
2083 {
2084 responseptr = newptr;
2085 rr->ImmedAdditional = mDNSNULL;
2086 rr->RequireGoodbye = mDNStrue;
2087 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2088 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2089 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2090 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2091 rr->LastMCTime = m->timenow;
2092 rr->LastMCInterface = intf->InterfaceID;
2093 }
2094 }
2095 }
2096
2097 if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals)
2098 {
2099 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2100 numDereg, numDereg == 1 ? "" : "s",
2101 numAnnounce, numAnnounce == 1 ? "" : "s",
2102 numAnswer, numAnswer == 1 ? "" : "s",
2103 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
2104 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
2105 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
2106 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
2107 if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
2108 // There might be more things to send on this interface, so go around one more time and try again.
2109 }
2110 else // Nothing more to send on this interface; go to next
2111 {
2112 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
2113 #if MDNS_DEBUGMSGS && 0
2114 const char *const msg = next ? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
2115 debugf(msg, intf, next);
2116 #endif
2117 intf = next;
2118 }
2119 }
2120
2121 // ***
2122 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
2123 // ***
2124
2125 if (m->CurrentRecord)
2126 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
2127 m->CurrentRecord = m->ResourceRecords;
2128 while (m->CurrentRecord)
2129 {
2130 rr = m->CurrentRecord;
2131 m->CurrentRecord = rr->next;
2132
2133 if (rr->SendRNow)
2134 {
2135 if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
2136 LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
2137 rr->SendRNow = mDNSNULL;
2138 }
2139
2140 if (rr->ImmedAnswer)
2141 {
2142 if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
2143
2144 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2145 CompleteDeregistration(m, rr); // Don't touch rr after this
2146 else
2147 {
2148 rr->ImmedAnswer = mDNSNULL;
2149 rr->ImmedUnicast = mDNSfalse;
2150 rr->v4Requester = zerov4Addr;
2151 rr->v6Requester = zerov6Addr;
2152 }
2153 }
2154 }
2155 verbosedebugf("SendResponses: Next in %ld ticks", m->NextScheduledResponse - m->timenow);
2156 }
2157
2158 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
2159 // so we want to be lazy about how frequently we do it.
2160 // 1. If a cache record is currently referenced by *no* active questions,
2161 // then we don't mind expiring it up to a minute late (who will know?)
2162 // 2. Else, if a cache record is due for some of its final expiration queries,
2163 // we'll allow them to be late by up to 2% of the TTL
2164 // 3. Else, if a cache record has completed all its final expiration queries without success,
2165 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
2166 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
2167 // so allow at most 1/10 second lateness
2168 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
2169 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
2170 #define CacheCheckGracePeriod(RR) ( \
2171 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
2172 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
2173 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
2174 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
2175 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
2176
2177 // Note: MUST call SetNextCacheCheckTime any time we change:
2178 // rr->TimeRcvd
2179 // rr->resrec.rroriginalttl
2180 // rr->UnansweredQueries
2181 // rr->CRActiveQuestion
2182 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
2183 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
2184 mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
2185 {
2186 rr->NextRequiredQuery = RRExpireTime(rr);
2187
2188 // If we have an active question, then see if we want to schedule a refresher query for this record.
2189 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
2190 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
2191 {
2192 rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
2193 rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
2194 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
2195 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
2196 (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
2197 }
2198
2199 if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
2200 m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
2201
2202 if (rr->DelayDelivery)
2203 if (m->NextCacheCheck - rr->DelayDelivery > 0)
2204 m->NextCacheCheck = rr->DelayDelivery;
2205 }
2206
2207 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
2208 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
2209 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
2210 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
2211
2212 mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
2213 {
2214 if (interval < kMinimumReconfirmTime)
2215 interval = kMinimumReconfirmTime;
2216 if (interval > 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
2217 interval = 0x10000000;
2218
2219 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
2220 if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
2221 {
2222 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
2223 // For all the reconfirmations in a given batch, we want to use the same random value
2224 // so that the reconfirmation questions can be grouped into a single query packet
2225 if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
2226 interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
2227 rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
2228 rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
2229 SetNextCacheCheckTime(m, rr);
2230 }
2231 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
2232 RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
2233 return(mStatus_NoError);
2234 }
2235
2236 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
2237
2238 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
2239 // It also appends to the list of known answer records that need to be included,
2240 // and updates the forcast for the size of the known answer section.
2241 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
2242 CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
2243 {
2244 mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
2245 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
2246 const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
2247 mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
2248 if (!newptr)
2249 {
2250 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2251 return(mDNSfalse);
2252 }
2253 else if (newptr + *answerforecast >= limit)
2254 {
2255 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
2256 q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
2257 query->h.numQuestions--;
2258 return(mDNSfalse);
2259 }
2260 else
2261 {
2262 mDNSu32 forecast = *answerforecast;
2263 const mDNSu32 slot = HashSlot(&q->qname);
2264 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
2265 CacheRecord *rr;
2266 CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
2267
2268 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
2269 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
2270 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
2271 rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
2272 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
2273 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
2274 mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
2275 {
2276 *ka = rr; // Link this record into our known answer chain
2277 ka = &rr->NextInKAList;
2278 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2279 forecast += 12 + rr->resrec.rdestimate;
2280 // If we're trying to put more than one question in this packet, and it doesn't fit
2281 // then undo that last question and try again next time
2282 if (query->h.numQuestions > 1 && newptr + forecast >= limit)
2283 {
2284 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
2285 q->qname.c, DNSTypeName(q->qtype), newptr + forecast - query->data);
2286 query->h.numQuestions--;
2287 ka = *kalistptrptr; // Go back to where we started and retract these answer records
2288 while (*ka) { CacheRecord *c = *ka; *ka = mDNSNULL; ka = &c->NextInKAList; }
2289 return(mDNSfalse); // Return false, so we'll try again in the next packet
2290 }
2291 }
2292
2293 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
2294 *queryptr = newptr; // Update the packet pointer
2295 *answerforecast = forecast; // Update the forecast
2296 *kalistptrptr = ka; // Update the known answer list pointer
2297 if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
2298
2299 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
2300 if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
2301 rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
2302 SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
2303 {
2304 rr->UnansweredQueries++; // indicate that we're expecting a response
2305 rr->LastUnansweredTime = m->timenow;
2306 SetNextCacheCheckTime(m, rr);
2307 }
2308
2309 return(mDNStrue);
2310 }
2311 }
2312
2313 // When we have a query looking for a specified name, but there appear to be no answers with
2314 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
2315 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
2316 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
2317 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
2318 // A typical reconfirmation scenario might go like this:
2319 // Depth 0: Name "myhost.local" has no address records
2320 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
2321 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
2322 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
2323 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
2324 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
2325 mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth)
2326 {
2327 mDNSu32 slot;
2328 CacheGroup *cg;
2329 CacheRecord *cr;
2330 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c);
2331 FORALL_CACHERECORDS(slot, cg, cr)
2332 {
2333 domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
2334 if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
2335 {
2336 LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
2337 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
2338 if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1);
2339 }
2340 }
2341 }
2342
2343 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
2344 mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time)
2345 {
2346 int i;
2347 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
2348 }
2349
2350 mDNSlocal void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time, mDNSInterfaceID InterfaceID)
2351 {
2352 int i;
2353 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Time - time < 0) ds[i].InterfaceID = mDNSNULL;
2354 }
2355
2356 mDNSlocal mDNSBool SuppressOnThisInterface(const DupSuppressInfo ds[DupSuppressInfoSize], const NetworkInterfaceInfo * const intf)
2357 {
2358 int i;
2359 mDNSBool v4 = !intf->IPv4Available; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
2360 mDNSBool v6 = !intf->IPv6Available; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
2361 for (i=0; i<DupSuppressInfoSize; i++)
2362 if (ds[i].InterfaceID == intf->InterfaceID)
2363 {
2364 if (ds[i].Type == mDNSAddrType_IPv4) v4 = mDNStrue;
2365 else if (ds[i].Type == mDNSAddrType_IPv6) v6 = mDNStrue;
2366 if (v4 && v6) return(mDNStrue);
2367 }
2368 return(mDNSfalse);
2369 }
2370
2371 mDNSlocal int RecordDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 Time, mDNSInterfaceID InterfaceID, mDNSs32 Type)
2372 {
2373 int i, j;
2374
2375 // See if we have this one in our list somewhere already
2376 for (i=0; i<DupSuppressInfoSize; i++) if (ds[i].InterfaceID == InterfaceID && ds[i].Type == Type) break;
2377
2378 // If not, find a slot we can re-use
2379 if (i >= DupSuppressInfoSize)
2380 {
2381 i = 0;
2382 for (j=1; j<DupSuppressInfoSize && ds[i].InterfaceID; j++)
2383 if (!ds[j].InterfaceID || ds[j].Time - ds[i].Time < 0)
2384 i = j;
2385 }
2386
2387 // Record the info about this query we saw
2388 ds[i].Time = Time;
2389 ds[i].InterfaceID = InterfaceID;
2390 ds[i].Type = Type;
2391
2392 return(i);
2393 }
2394
2395 mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
2396 {
2397 // If more than 90% of the way to the query time, we should unconditionally accelerate it
2398 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/10))
2399 return(mDNStrue);
2400
2401 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
2402 if (TimeToSendThisQuestion(q, m->timenow + q->ThisQInterval/2))
2403 {
2404 // We forecast: qname (n) type (2) class (2)
2405 mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
2406 const mDNSu32 slot = HashSlot(&q->qname);
2407 const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
2408 CacheRecord *rr;
2409 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
2410 if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
2411 SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
2412 rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
2413 rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
2414 {
2415 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2416 forecast += 12 + rr->resrec.rdestimate;
2417 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
2418 }
2419 return(mDNStrue);
2420 }
2421
2422 return(mDNSfalse);
2423 }
2424
2425 // How Standard Queries are generated:
2426 // 1. The Question Section contains the question
2427 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
2428
2429 // How Probe Queries are generated:
2430 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
2431 // if some other host is already using *any* records with this name, we want to know about it.
2432 // 2. The Authority Section contains the proposed values we intend to use for one or more
2433 // of our records with that name (analogous to the Update section of DNS Update packets)
2434 // because if some other host is probing at the same time, we each want to know what the other is
2435 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
2436
2437 mDNSlocal void SendQueries(mDNS *const m)
2438 {
2439 mDNSu32 slot;
2440 CacheGroup *cg;
2441 CacheRecord *cr;
2442 AuthRecord *ar;
2443 int pktcount = 0;
2444 DNSQuestion *q;
2445 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
2446 mDNSs32 maxExistingQuestionInterval = 0;
2447 const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
2448 CacheRecord *KnownAnswerList = mDNSNULL;
2449
2450 // 1. If time for a query, work out what we need to do
2451 if (m->timenow - m->NextScheduledQuery >= 0)
2452 {
2453 CacheRecord *rr;
2454
2455 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
2456 // to their NextRequiredQuery to be worth batching them together with this one
2457 FORALL_CACHERECORDS(slot, cg, rr)
2458 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
2459 if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
2460 {
2461 LogOperation("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
2462 q = rr->CRActiveQuestion;
2463 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
2464 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
2465 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
2466 if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
2467 else if (!mDNSOpaque16IsZero(q->TargetQID)) { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; }
2468 else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID;
2469 else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
2470 }
2471
2472 if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
2473 m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
2474
2475 // Scan our list of questions to see which:
2476 // *WideArea* queries need to be sent
2477 // *unicast* queries need to be sent
2478 // *multicast* queries we're definitely going to send
2479 if (m->CurrentQuestion)
2480 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
2481 m->CurrentQuestion = m->Questions;
2482 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2483 {
2484 q = m->CurrentQuestion;
2485 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
2486 else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
2487 {
2488 mDNSu8 *qptr = m->omsg.data;
2489 const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
2490 InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
2491 qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
2492 mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
2493 q->ThisQInterval *= QuestionIntervalStep;
2494 if (q->ThisQInterval > MaxQuestionInterval)
2495 q->ThisQInterval = MaxQuestionInterval;
2496 q->LastQTime = m->timenow;
2497 q->LastQTxTime = m->timenow;
2498 q->RecentAnswerPkts = 0;
2499 q->SendQNow = mDNSNULL;
2500 q->ExpectUnicastResp = NonZeroTime(m->timenow);
2501 }
2502 else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
2503 {
2504 //LogOperation("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
2505 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
2506 if (maxExistingQuestionInterval < q->ThisQInterval)
2507 maxExistingQuestionInterval = q->ThisQInterval;
2508 }
2509 // If m->CurrentQuestion wasn't modified out from under us, advance it now
2510 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
2511 // m->CurrentQuestion point to the right question
2512 if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
2513 }
2514 m->CurrentQuestion = mDNSNULL;
2515
2516 // Scan our list of questions
2517 // (a) to see if there are any more that are worth accelerating, and
2518 // (b) to update the state variables for *all* the questions we're going to send
2519 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
2520 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
2521 // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
2522 m->NextScheduledQuery = m->timenow + 0x78000000;
2523 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
2524 {
2525 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
2526 (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
2527 {
2528 // If at least halfway to next query time, advance to next interval
2529 // If less than halfway to next query time, then
2530 // treat this as logically a repeat of the last transmission, without advancing the interval
2531 if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
2532 {
2533 //LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
2534 q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
2535 q->ThisQInterval *= QuestionIntervalStep;
2536 if (q->ThisQInterval > MaxQuestionInterval)
2537 q->ThisQInterval = MaxQuestionInterval;
2538 else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep2)
2539 {
2540 // Generally don't need to log this.
2541 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
2542 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
2543 // and when there simply happen to be no instances of the service the client is looking
2544 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
2545 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
2546 q->qname.c, DNSTypeName(q->qtype));
2547 // Sending third query, and no answers yet; time to begin doubting the source
2548 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
2549 }
2550 }
2551
2552 // Mark for sending. (If no active interfaces, then don't even try.)
2553 q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
2554 if (q->SendOnAll)
2555 {
2556 q->SendQNow = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
2557 q->LastQTime = m->timenow;
2558 }
2559
2560 // If we recorded a duplicate suppression for this question less than half an interval ago,
2561 // then we consider it recent enough that we don't need to do an identical query ourselves.
2562 ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
2563
2564 q->LastQTxTime = m->timenow;
2565 q->RecentAnswerPkts = 0;
2566 if (q->RequestUnicast) q->RequestUnicast--;
2567 }
2568 // For all questions (not just the ones we're sending) check what the next scheduled event will be
2569 SetNextQueryTime(m,q);
2570 }
2571 }
2572
2573 // 2. Scan our authoritative RR list to see what probes we might need to send
2574 if (m->timenow - m->NextScheduledProbe >= 0)
2575 {
2576 m->NextScheduledProbe = m->timenow + 0x78000000;
2577
2578 if (m->CurrentRecord)
2579 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
2580 m->CurrentRecord = m->ResourceRecords;
2581 while (m->CurrentRecord)
2582 {
2583 AuthRecord *rr = m->CurrentRecord;
2584 m->CurrentRecord = rr->next;
2585 if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique) // For all records that are still probing...
2586 {
2587 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
2588 if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
2589 {
2590 SetNextAnnounceProbeTime(m, rr);
2591 }
2592 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
2593 else if (rr->ProbeCount)
2594 {
2595 // Mark for sending. (If no active interfaces, then don't even try.)
2596 rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID;
2597 rr->LastAPTime = m->timenow;
2598 rr->ProbeCount--;
2599 SetNextAnnounceProbeTime(m, rr);
2600 if (rr->ProbeCount == 0)
2601 {
2602 // If this is the last probe for this record, then see if we have any matching records
2603 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
2604 AuthRecord *r2;
2605 for (r2 = m->DuplicateRecords; r2; r2=r2->next)
2606 if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
2607 r2->ProbeCount = 0;
2608 // ... then acknowledge this record to the client.
2609 // We do this optimistically, just as we're about to send the third probe.
2610 // This helps clients that both advertise and browse, and want to filter themselves
2611 // from the browse results list, because it helps ensure that the registration
2612 // confirmation will be delivered 1/4 second *before* the browse "add" event.
2613 // A potential downside is that we could deliver a registration confirmation and then find out
2614 // moments later that there's a name conflict, but applications have to be prepared to handle
2615 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
2616 if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
2617 }
2618 }
2619 // else, if it has now finished probing, move it to state Verified,
2620 // and update m->NextScheduledResponse so it will be announced
2621 else
2622 {
2623 if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow
2624 rr->resrec.RecordType = kDNSRecordTypeVerified;
2625 rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
2626 rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
2627 SetNextAnnounceProbeTime(m, rr);
2628 }
2629 }
2630 }
2631 m->CurrentRecord = m->DuplicateRecords;
2632 while (m->CurrentRecord)
2633 {
2634 AuthRecord *rr = m->CurrentRecord;
2635 m->CurrentRecord = rr->next;
2636 if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
2637 AcknowledgeRecord(m, rr);
2638 }
2639 }
2640
2641 // 3. Now we know which queries and probes we're sending,
2642 // go through our interface list sending the appropriate queries on each interface
2643 while (intf)
2644 {
2645 AuthRecord *rr;
2646 mDNSu8 *queryptr = m->omsg.data;
2647 InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
2648 if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
2649 if (!KnownAnswerList)
2650 {
2651 // Start a new known-answer list
2652 CacheRecord **kalistptr = &KnownAnswerList;
2653 mDNSu32 answerforecast = 0;
2654
2655 // Put query questions in this packet
2656 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
2657 {
2658 if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID))
2659 {
2660 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
2661 SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ",
2662 q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data);
2663 // If we're suppressing this question, or we successfully put it, update its SendQNow state
2664 if (SuppressOnThisInterface(q->DupSuppress, intf) ||
2665 BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
2666 q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
2667 }
2668 }
2669
2670 // Put probe questions in this packet
2671 for (rr = m->ResourceRecords; rr; rr=rr->next)
2672 if (rr->SendRNow == intf->InterfaceID)
2673 {
2674 mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
2675 mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
2676 const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
2677 mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
2678 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2679 mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
2680 if (newptr && newptr + forecast < limit)
2681 {
2682 queryptr = newptr;
2683 answerforecast = forecast;
2684 rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
2685 rr->IncludeInProbe = mDNStrue;
2686 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
2687 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
2688 }
2689 else
2690 {
2691 verbosedebugf("SendQueries: Retracting Question %##s (%s)",
2692 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2693 m->omsg.h.numQuestions--;
2694 }
2695 }
2696 }
2697
2698 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
2699 while (KnownAnswerList)
2700 {
2701 CacheRecord *ka = KnownAnswerList;
2702 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond;
2703 mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd);
2704 if (newptr)
2705 {
2706 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
2707 ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
2708 queryptr = newptr;
2709 KnownAnswerList = ka->NextInKAList;
2710 ka->NextInKAList = mDNSNULL;
2711 }
2712 else
2713 {
2714 // If we ran out of space and we have more than one question in the packet, that's an error --
2715 // we shouldn't have put more than one question if there was a risk of us running out of space.
2716 if (m->omsg.h.numQuestions > 1)
2717 LogMsg("SendQueries: Put %d answers; No more space for known answers", m->omsg.h.numAnswers);
2718 m->omsg.h.flags.b[0] |= kDNSFlag0_TC;
2719 break;
2720 }
2721 }
2722
2723 for (rr = m->ResourceRecords; rr; rr=rr->next)
2724 if (rr->IncludeInProbe)
2725 {
2726 mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
2727 rr->IncludeInProbe = mDNSfalse;
2728 if (newptr) queryptr = newptr;
2729 else LogMsg("SendQueries: How did we fail to have space for the Update record %##s (%s)?",
2730 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
2731 }
2732
2733 if (queryptr > m->omsg.data)
2734 {
2735 if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
2736 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
2737 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
2738 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
2739 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
2740 m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
2741 if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
2742 if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
2743 if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
2744 if (++pktcount >= 1000)
2745 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
2746 // There might be more records left in the known answer list, or more questions to send
2747 // on this interface, so go around one more time and try again.
2748 }
2749 else // Nothing more to send on this interface; go to next
2750 {
2751 const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
2752 #if MDNS_DEBUGMSGS && 0
2753 const char *const msg = next ? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
2754 debugf(msg, intf, next);
2755 #endif
2756 intf = next;
2757 }
2758 }
2759
2760 // 4. Final housekeeping
2761
2762 // 4a. Debugging check: Make sure we announced all our records
2763 for (ar = m->ResourceRecords; ar; ar=ar->next)
2764 if (ar->SendRNow)
2765 {
2766 if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
2767 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
2768 ar->SendRNow = mDNSNULL;
2769 }
2770
2771 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
2772 // that their interface which went away might come back again, the logic will want to send queries
2773 // for those records, but we can't because their interface isn't here any more, so to keep the
2774 // state machine ticking over we just pretend we did so.
2775 // If the interface does not come back in time, the cache record will expire naturally
2776 FORALL_CACHERECORDS(slot, cg, cr)
2777 if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
2778 {
2779 cr->UnansweredQueries++;
2780 cr->CRActiveQuestion->SendQNow = mDNSNULL;
2781 SetNextCacheCheckTime(m, cr);
2782 }
2783
2784 // 4c. Debugging check: Make sure we sent all our planned questions
2785 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
2786 // we legitimately couldn't send because the interface is no longer available
2787 for (q = m->Questions; q; q=q->next)
2788 if (q->SendQNow)
2789 {
2790 LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2791 q->SendQNow = mDNSNULL;
2792 }
2793 }
2794
2795 // ***************************************************************************
2796 #if COMPILER_LIKES_PRAGMA_MARK
2797 #pragma mark -
2798 #pragma mark - RR List Management & Task Management
2799 #endif
2800
2801 // NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
2802 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
2803 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
2804 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
2805 mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
2806 {
2807 DNSQuestion *const q = m->CurrentQuestion;
2808 mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
2809 rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
2810 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
2811
2812 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
2813 // may be called twice, once when the record is received, and again when it's time to notify local clients.
2814 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
2815
2816 rr->LastUsed = m->timenow;
2817 if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
2818 {
2819 if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
2820 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
2821 rr->CRActiveQuestion = q; // We know q is non-null
2822 SetNextCacheCheckTime(m, rr);
2823 }
2824
2825 // If this is:
2826 // (a) a no-cache add, where we've already done at least one 'QM' query, or
2827 // (b) a normal add, where we have at least one unique-type answer,
2828 // then there's no need to keep polling the network.
2829 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
2830 // We do this for mDNS questions and uDNS one-shot questions, but not for
2831 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
2832 if ((AddRecord == QC_addnocache && !q->RequestUnicast) ||
2833 (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
2834 if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
2835 {
2836 q->LastQTime = m->timenow;
2837 q->LastQTxTime = m->timenow;
2838 q->RecentAnswerPkts = 0;
2839 q->ThisQInterval = MaxQuestionInterval;
2840 q->RequestUnicast = mDNSfalse;
2841 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2842 }
2843
2844 if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
2845
2846 // Only deliver negative answers if client has explicitly requested them
2847 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!AddRecord || !q->ReturnIntermed)) return;
2848
2849 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
2850 if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed))
2851 {
2852 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
2853 q->QuestionCallback(m, q, &rr->resrec, AddRecord);
2854 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2855 }
2856 // NOTE: Proceed with caution here because client callback function is allowed to do anything,
2857 // including starting/stopping queries, registering/deregistering records, etc.
2858
2859 if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
2860 {
2861 const mDNSu32 c = q->CNAMEReferrals + 1;
2862 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
2863 // and track CNAMEs coming and going, we should really create a subbordinate query here,
2864 // which we would subsequently cancel and retract if the CNAME referral record were removed.
2865 // In reality this is such a corner case we'll ignore it until someone actually needs it.
2866 LogOperation("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
2867 mDNS_StopQuery_internal(m, q); // Stop old query
2868 AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname
2869 q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
2870 mDNS_StartQuery_internal(m, q); // start new query
2871 q->CNAMEReferrals = c; // and keep count of how many times we've done this
2872 }
2873 }
2874
2875 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
2876 {
2877 rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
2878 if (m->CurrentQuestion)
2879 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
2880 m->CurrentQuestion = m->Questions;
2881 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2882 {
2883 DNSQuestion *q = m->CurrentQuestion;
2884 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2885 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
2886 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
2887 m->CurrentQuestion = q->next;
2888 }
2889 m->CurrentQuestion = mDNSNULL;
2890 }
2891
2892 mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot)
2893 {
2894 const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second
2895 const mDNSs32 start = m->timenow - 0x10000000;
2896 mDNSs32 delay = start;
2897 CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
2898 CacheRecord *rr;
2899 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
2900 if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
2901 if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
2902 delay = RRExpireTime(rr);
2903 if (delay - start > 0) return(NonZeroTime(delay));
2904 else return(0);
2905 }
2906
2907 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
2908 // If new questions are created as a result of invoking client callbacks, they will be added to
2909 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
2910 // rr is a new CacheRecord just received into our cache
2911 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
2912 // NOTE: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
2913 // which may change the record list and/or question list.
2914 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2915 mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
2916 {
2917 DNSQuestion *q;
2918
2919 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
2920 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
2921 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
2922 {
2923 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2924 {
2925 // If this question is one that's actively sending queries, and it's received ten answers within one
2926 // second of sending the last query packet, then that indicates some radical network topology change,
2927 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
2928 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
2929 // because we will anyway send another query within a few seconds. The first reset query is sent out
2930 // randomized over the next four seconds to reduce possible synchronization between machines.
2931 if (q->LastAnswerPktNum != m->PktNum)
2932 {
2933 q->LastAnswerPktNum = m->PktNum;
2934 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
2935 q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
2936 {
2937 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
2938 q->qname.c, DNSTypeName(q->qtype));
2939 q->LastQTime = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
2940 q->ThisQInterval = InitialQuestionInterval;
2941 SetNextQueryTime(m,q);
2942 }
2943 }
2944 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
2945 rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
2946 q->CurrentAnswers++;
2947 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
2948 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
2949 if (q->CurrentAnswers > 4000)
2950 {
2951 static int msgcount = 0;
2952 if (msgcount++ < 10)
2953 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
2954 q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
2955 rr->resrec.rroriginalttl = 0;
2956 rr->UnansweredQueries = MaxUnansweredQueries;
2957 }
2958 }
2959 }
2960
2961 if (!rr->DelayDelivery)
2962 {
2963 if (m->CurrentQuestion)
2964 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
2965 m->CurrentQuestion = m->Questions;
2966 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
2967 {
2968 q = m->CurrentQuestion;
2969 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
2970 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
2971 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
2972 m->CurrentQuestion = q->next;
2973 }
2974 m->CurrentQuestion = mDNSNULL;
2975 }
2976
2977 SetNextCacheCheckTime(m, rr);
2978 }
2979
2980 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
2981 // If new questions are created as a result of invoking client callbacks, they will be added to
2982 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
2983 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
2984 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
2985 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
2986 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
2987 // NOTE: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
2988 // which may change the record list and/or question list.
2989 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2990 mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
2991 {
2992 LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
2993 if (m->CurrentQuestion)
2994 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
2995 m->CurrentQuestion = m->Questions;
2996 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
2997 // since we're not caching the record and we'll get no opportunity to do this later
2998 while (m->CurrentQuestion)
2999 {
3000 DNSQuestion *q = m->CurrentQuestion;
3001 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3002 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
3003 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3004 m->CurrentQuestion = q->next;
3005 }
3006 m->CurrentQuestion = mDNSNULL;
3007 }
3008
3009 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
3010 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
3011 // If new questions are created as a result of invoking client callbacks, they will be added to
3012 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3013 // rr is an existing cache CacheRecord that just expired and is being deleted
3014 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3015 // NOTE: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3016 // which may change the record list and/or question list.
3017 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3018 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
3019 {
3020 if (m->CurrentQuestion)
3021 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3022 m->CurrentQuestion = m->Questions;
3023
3024 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
3025 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
3026 while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
3027 {
3028 DNSQuestion *q = m->CurrentQuestion;
3029 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3030 {
3031 verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
3032 q->FlappingInterface1 = mDNSNULL;
3033 q->FlappingInterface2 = mDNSNULL;
3034 if (q->CurrentAnswers == 0)
3035 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
3036 q, q->qname.c, DNSTypeName(q->qtype));
3037 else
3038 {
3039 q->CurrentAnswers--;
3040 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
3041 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
3042 }
3043 if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
3044 {
3045 if (q->CurrentAnswers == 0)
3046 {
3047 LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
3048 q->qname.c, DNSTypeName(q->qtype));
3049 ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
3050 }
3051 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
3052 }
3053 }
3054 if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3055 m->CurrentQuestion = q->next;
3056 }
3057 m->CurrentQuestion = mDNSNULL;
3058 }
3059
3060 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
3061 {
3062 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
3063 unsigned int i;
3064 for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
3065 #endif
3066 e->next = m->rrcache_free;
3067 m->rrcache_free = e;
3068 m->rrcache_totalused--;
3069 }
3070
3071 mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
3072 {
3073 CacheEntity *e = (CacheEntity *)(*cp);
3074 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
3075 if ((*cp)->rrcache_tail != &(*cp)->members)
3076 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
3077 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
3078 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
3079 if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
3080 (*cp)->name = mDNSNULL;
3081 *cp = (*cp)->next; // Cut record from list
3082 ReleaseCacheEntity(m, e);
3083 }
3084
3085 mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
3086 {
3087 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
3088 if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
3089 r->resrec.rdata = mDNSNULL;
3090 ReleaseCacheEntity(m, (CacheEntity *)r);
3091 }
3092
3093 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
3094 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
3095 // callbacks for old records are delivered before callbacks for newer records.
3096 mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
3097 {
3098 CacheRecord **rp = &cg->members;
3099
3100 if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
3101 m->lock_rrcache = 1;
3102
3103 while (*rp)
3104 {
3105 CacheRecord *const rr = *rp;
3106 mDNSs32 event = RRExpireTime(rr);
3107 if (m->timenow - event >= 0) // If expired, delete it
3108 {
3109 *rp = rr->next; // Cut it from the list
3110 verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
3111 m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
3112 if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
3113 {
3114 CacheRecordRmv(m, rr);
3115 m->rrcache_active--;
3116 }
3117 ReleaseCacheRecord(m, rr);
3118 }
3119 else // else, not expired; see if we need to query
3120 {
3121 if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
3122 event = rr->DelayDelivery;
3123 else
3124 {
3125 if (rr->DelayDelivery) CacheRecordDeferredAdd(m, rr);
3126 if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
3127 {
3128 if (m->timenow - rr->NextRequiredQuery < 0) // If not yet time for next query
3129 event = rr->NextRequiredQuery; // then just record when we want the next query
3130 else // else trigger our question to go out now
3131 {
3132 // Set NextScheduledQuery to timenow so that SendQueries() will run.
3133 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
3134 m->NextScheduledQuery = m->timenow;
3135 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
3136 // which will correctly update m->NextCacheCheck for us.
3137 event = m->timenow + 0x3FFFFFFF;
3138 }
3139 }
3140 }
3141 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
3142 (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
3143 if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
3144 m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
3145 rp = &rr->next;
3146 }
3147 }
3148 if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
3149 cg->rrcache_tail = rp;
3150 m->lock_rrcache = 0;
3151 }
3152
3153 mDNSlocal void AnswerNewQuestion(mDNS *const m)
3154 {
3155 mDNSBool ShouldQueryImmediately = mDNStrue;
3156 DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer
3157 const mDNSu32 slot = HashSlot(&q->qname);
3158 CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3159
3160 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3161
3162 if (cg) CheckCacheExpiration(m, cg);
3163 m->NewQuestions = q->next; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
3164
3165 if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
3166 // This should be safe, because calling the client's question callback may cause the
3167 // question list to be modified, but should not ever cause the rrcache list to be modified.
3168 // If the client's question callback deletes the question, then m->CurrentQuestion will
3169 // be advanced, and we'll exit out of the loop
3170 m->lock_rrcache = 1;
3171 if (m->CurrentQuestion)
3172 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3173 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
3174
3175 if (q->NoAnswer == NoAnswer_Fail)
3176 {
3177 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3178 MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
3179 q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
3180 AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
3181 q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state
3182 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3183 }
3184
3185 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
3186 if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
3187 {
3188 if (m->CurrentRecord)
3189 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3190 m->CurrentRecord = m->ResourceRecords;
3191 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
3192 {
3193 AuthRecord *rr = m->CurrentRecord;
3194 m->CurrentRecord = rr->next;
3195 if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
3196 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3197 {
3198 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
3199 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
3200 }
3201 }
3202 m->CurrentRecord = mDNSNULL;
3203 }
3204
3205 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
3206
3207 if (m->CurrentQuestion == q)
3208 {
3209 CacheRecord *rr;
3210 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3211 if (SameNameRecordAnswersQuestion(&rr->resrec, q))
3212 {
3213 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
3214 mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
3215 if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
3216 {
3217 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s) %d %d",
3218 rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), m->timenow, rr->TimeRcvd);
3219 continue; // Go to next one in loop
3220 }
3221
3222 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
3223 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
3224 if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
3225 ShouldQueryImmediately = mDNSfalse;
3226 q->CurrentAnswers++;
3227 if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
3228 if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
3229 AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
3230 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
3231 }
3232 else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
3233 if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
3234 ShouldQueryImmediately = mDNSfalse;
3235 }
3236
3237 if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
3238
3239 if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
3240 {
3241 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3242 q->ThisQInterval = InitialQuestionInterval;
3243 q->LastQTime = m->timenow - q->ThisQInterval;
3244 if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries
3245 {
3246 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
3247 if (!m->RandomQueryDelay)
3248 m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
3249 q->LastQTime += m->RandomQueryDelay;
3250 }
3251
3252 if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
3253 m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
3254 }
3255
3256 m->CurrentQuestion = mDNSNULL;
3257 m->lock_rrcache = 0;
3258 }
3259
3260 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
3261 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
3262 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
3263 {
3264 DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
3265 m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any)
3266
3267 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3268
3269 if (m->CurrentQuestion)
3270 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3271 m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
3272
3273 if (m->CurrentRecord)
3274 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3275 m->CurrentRecord = m->ResourceRecords;
3276
3277 while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
3278 {
3279 AuthRecord *rr = m->CurrentRecord;
3280 m->CurrentRecord = rr->next;
3281 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
3282 {
3283 AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
3284 if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
3285 }
3286 }
3287
3288 m->CurrentQuestion = mDNSNULL;
3289 m->CurrentRecord = mDNSNULL;
3290 }
3291
3292 mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
3293 {
3294 CacheEntity *e = mDNSNULL;
3295
3296 if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
3297 m->lock_rrcache = 1;
3298
3299 // If we have no free records, ask the client layer to give us some more memory
3300 if (!m->rrcache_free && m->MainCallback)
3301 {
3302 if (m->rrcache_totalused != m->rrcache_size)
3303 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
3304 m->rrcache_totalused, m->rrcache_size);
3305
3306 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
3307 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
3308 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
3309 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
3310 // and recycle them, instead of allocating more memory.
3311 if (m->rrcache_size > 3000 && m->rrcache_size / 32 > m->rrcache_active)
3312 LogOperation("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
3313 m->rrcache_size, m->rrcache_active);
3314 else
3315 {
3316 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3317 m->MainCallback(m, mStatus_GrowCache);
3318 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3319 }
3320 }
3321
3322 // If we still have no free records, recycle all the records we can.
3323 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
3324 if (!m->rrcache_free)
3325 {
3326 #if LogAllOperations || MDNS_DEBUGMSGS
3327 mDNSu32 oldtotalused = m->rrcache_totalused;
3328 #endif
3329 mDNSu32 slot;
3330 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
3331 {
3332 CacheGroup **cp = &m->rrcache_hash[slot];
3333 while (*cp)
3334 {
3335 CacheRecord **rp = &(*cp)->members;
3336 while (*rp)
3337 {
3338 // Records that answer still-active questions are not candidates for recycling
3339 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
3340 if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
3341 rp=&(*rp)->next;
3342 else
3343 {
3344 CacheRecord *rr = *rp;
3345 *rp = (*rp)->next; // Cut record from list
3346 ReleaseCacheRecord(m, rr);
3347 }
3348 }
3349 if ((*cp)->rrcache_tail != rp)
3350 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
3351 (*cp)->rrcache_tail = rp;
3352 if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
3353 else ReleaseCacheGroup(m, cp);
3354 }
3355 }
3356 LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d",
3357 oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
3358 }
3359
3360 if (m->rrcache_free) // If there are records in the free list, take one
3361 {
3362 e = m->rrcache_free;
3363 m->rrcache_free = e->next;
3364 if (++m->rrcache_totalused >= m->rrcache_report)
3365 {
3366 LogOperation("RR Cache now using %ld objects", m->rrcache_totalused);
3367 if (m->rrcache_report < 100) m->rrcache_report += 10;
3368 else m->rrcache_report += 100;
3369 }
3370 mDNSPlatformMemZero(e, sizeof(*e));
3371 }
3372
3373 m->lock_rrcache = 0;
3374
3375 return(e);
3376 }
3377
3378 mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
3379 {
3380 CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
3381 if (r)
3382 {
3383 r->resrec.rdata = (RData*)&r->rdatastorage; // By default, assume we're usually going to be using local storage
3384 if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage
3385 {
3386 r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
3387 if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
3388 else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
3389 }
3390 }
3391 return(r);
3392 }
3393
3394 mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
3395 {
3396 mDNSu16 namelen = DomainNameLength(rr->name);
3397 CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
3398 if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
3399 cg->next = m->rrcache_hash[slot];
3400 cg->namehash = rr->namehash;
3401 cg->members = mDNSNULL;
3402 cg->rrcache_tail = &cg->members;
3403 cg->name = (domainname*)cg->namestorage;
3404 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
3405 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
3406 if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
3407 if (!cg->name)
3408 {
3409 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
3410 ReleaseCacheEntity(m, (CacheEntity*)cg);
3411 return(mDNSNULL);
3412 }
3413 AssignDomainName(cg->name, rr->name);
3414
3415 if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
3416 m->rrcache_hash[slot] = cg;
3417 if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
3418
3419 return(cg);
3420 }
3421
3422 mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
3423 {
3424 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
3425 // a positive answer using an expired record (e.g. from an interface that has gone away).
3426 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
3427 // summary deletion without giving the proper callback to any questions that are monitoring it.
3428 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
3429 rr->TimeRcvd = m->timenow - mDNSPlatformOneSecond * 60;
3430 rr->UnansweredQueries = MaxUnansweredQueries;
3431 rr->resrec.rroriginalttl = 0;
3432 SetNextCacheCheckTime(m, rr);
3433 }
3434
3435 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
3436 {
3437 mDNSs32 time;
3438 mDNSPlatformLock(m);
3439 if (m->mDNS_busy)
3440 {
3441 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
3442 if (!m->timenow) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
3443 }
3444
3445 if (m->timenow) time = m->timenow;
3446 else time = mDNS_TimeNow_NoLock(m);
3447 mDNSPlatformUnlock(m);
3448 return(time);
3449 }
3450
3451 mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
3452 {
3453 mDNS_Lock(m); // Must grab lock before trying to read m->timenow
3454
3455 if (m->timenow - m->NextScheduledEvent >= 0)
3456 {
3457 int i;
3458
3459 verbosedebugf("mDNS_Execute");
3460 if (m->CurrentQuestion)
3461 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3462
3463 // 1. If we're past the probe suppression time, we can clear it
3464 if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
3465
3466 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
3467 if (m->NumFailedProbes && m->timenow - m->ProbeFailTime >= mDNSPlatformOneSecond * 10) m->NumFailedProbes = 0;
3468
3469 // 3. Purge our cache of stale old records
3470 if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
3471 {
3472 mDNSu32 slot;
3473 m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
3474 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
3475 {
3476 CacheGroup **cp = &m->rrcache_hash[slot];
3477 while (*cp)
3478 {
3479 CheckCacheExpiration(m, *cp);
3480 if ((*cp)->members) cp=&(*cp)->next;
3481 else ReleaseCacheGroup(m, cp);
3482 }
3483 }
3484 }
3485
3486 // 4. See if we can answer any of our new local questions from the cache
3487 for (i=0; m->NewQuestions && i<1000; i++)
3488 {
3489 if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
3490 AnswerNewQuestion(m);
3491 }
3492 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
3493
3494 for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
3495 if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
3496
3497 for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
3498 {
3499 AuthRecord *rr = m->NewLocalRecords;
3500 m->NewLocalRecords = m->NewLocalRecords->next;
3501 AnswerLocalQuestions(m, rr, mDNStrue);
3502 }
3503 if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
3504
3505 // 5. See what packets we need to send
3506 if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
3507 else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)
3508 {
3509 // If the platform code is ready, and we're not suppressing packet generation right now
3510 // then send our responses, probes, and questions.
3511 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
3512 // We send queries next, because there might be final-stage probes that complete their probing here, causing
3513 // them to advance to announcing state, and we want those to be included in any announcements we send out.
3514 // Finally, we send responses, including the previously mentioned records that just completed probing.
3515 m->SuppressSending = 0;
3516
3517 // 6. Send Query packets. This may cause some probing records to advance to announcing state
3518 if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
3519 if (m->timenow - m->NextScheduledQuery >= 0)
3520 {
3521 DNSQuestion *q;
3522 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
3523 m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
3524 m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
3525 for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
3526 if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
3527 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3528 }
3529 if (m->timenow - m->NextScheduledProbe >= 0)
3530 {
3531 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
3532 m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
3533 m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
3534 }
3535
3536 // 7. Send Response packets, including probing records just advanced to announcing state
3537 if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
3538 if (m->timenow - m->NextScheduledResponse >= 0)
3539 {
3540 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
3541 m->NextScheduledResponse = m->timenow + mDNSPlatformOneSecond;
3542 }
3543 }
3544
3545 // Clear RandomDelay values, ready to pick a new different value next time
3546 m->RandomQueryDelay = 0;
3547 m->RandomReconfirmDelay = 0;
3548 }
3549
3550 // Note about multi-threaded systems:
3551 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
3552 // performing mDNS API operations that change our next scheduled event time.
3553 //
3554 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
3555 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
3556 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
3557 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
3558 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
3559 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
3560 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
3561 // without blocking. This avoids the race condition between the signal from the other thread arriving
3562 // just *before* or just *after* the main thread enters the blocking primitive.
3563 //
3564 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
3565 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
3566 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
3567 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
3568 // by the time it gets to the timer callback function).
3569
3570 #ifndef UNICAST_DISABLED
3571 uDNS_Execute(m);
3572 #endif
3573 mDNS_Unlock(m); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
3574 return(m->NextScheduledEvent);
3575 }
3576
3577 mDNSlocal void SuspendLLQs(mDNS *m)
3578 {
3579 DNSQuestion *q;
3580 for (q = m->Questions; q; q = q->next)
3581 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->state == LLQ_Established)
3582 { q->ReqLease = 0; sendLLQRefresh(m, q); }
3583 }
3584
3585 // ActivateUnicastQuery() is called from three places:
3586 // 1. When a new question is created
3587 // 2. On wake from sleep
3588 // 3. When the DNS configuration changes
3589 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
3590 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
3591 mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
3592 {
3593 // For now this AutoTunnel stuff is specific to Mac OS X.
3594 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
3595 #if APPLE_OSX_mDNSResponder
3596 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
3597 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
3598 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
3599 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
3600 // returns results for both at the same time.
3601 if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
3602 {
3603 question->NoAnswer = NoAnswer_Suspended;
3604 AddNewClientTunnel(m, question);
3605 return;
3606 }
3607 #endif // APPLE_OSX_mDNSResponder
3608
3609 if (!question->DuplicateOf)
3610 {
3611 LogOperation("ActivateUnicastQuery: %##s %s%s%s",
3612 question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
3613 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
3614 if (question->LongLived)
3615 {
3616 question->state = LLQ_InitialRequest;
3617 question->id = zeroOpaque64;
3618 question->servPort = zeroIPPort;
3619 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
3620 }
3621 if (ScheduleImmediately)
3622 {
3623 question->ThisQInterval = InitialQuestionInterval;
3624 question->LastQTime = m->timenow - question->ThisQInterval;
3625 SetNextQueryTime(m, question);
3626 }
3627 }
3628 }
3629
3630 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
3631 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
3632 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
3633 // Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
3634 // mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
3635 // found itself in a new network environment. For example, if the Ethernet hardware indicates that the
3636 // cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
3637 // to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
3638 // While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
3639 // traffic, so it should only be called when there is legitimate reason to believe the machine
3640 // may have become attached to a new network.
3641 mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
3642 {
3643 AuthRecord *rr;
3644
3645 mDNS_Lock(m);
3646
3647 m->SleepState = sleepstate;
3648 LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
3649
3650 if (sleepstate)
3651 {
3652 #ifndef UNICAST_DISABLED
3653 SuspendLLQs(m);
3654 SleepServiceRegistrations(m);
3655 SleepRecordRegistrations(m);
3656 #endif
3657 // Mark all the records we need to deregister and send them
3658 for (rr = m->ResourceRecords; rr; rr=rr->next)
3659 if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
3660 rr->ImmedAnswer = mDNSInterfaceMark;
3661 SendResponses(m);
3662 }
3663 else
3664 {
3665 DNSQuestion *q;
3666 mDNSu32 slot;
3667 CacheGroup *cg;
3668 CacheRecord *cr;
3669
3670 #ifndef UNICAST_DISABLED
3671 // On wake, retrigger all our uDNS questions
3672 if (m->CurrentQuestion)
3673 LogMsg("RestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
3674 m->CurrentQuestion = m->Questions;
3675 while (m->CurrentQuestion)
3676 {
3677 q = m->CurrentQuestion;
3678 m->CurrentQuestion = m->CurrentQuestion->next;
3679 if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
3680 }
3681 // and reactivtate service registrations
3682 m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
3683 LogOperation("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
3684 #endif
3685 // 1. Retrigger all our mDNS questions
3686 for (q = m->Questions; q; q=q->next) // Scan our list of questions
3687 if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
3688 {
3689 q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
3690 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
3691 q->LastQTime = m->timenow - q->ThisQInterval;
3692 q->RecentAnswerPkts = 0;
3693 ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
3694 m->NextScheduledQuery = m->timenow;
3695 }
3696
3697 // 2. Re-validate our cache records
3698 m->NextCacheCheck = m->timenow;
3699 FORALL_CACHERECORDS(slot, cg, cr)
3700 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
3701
3702 // 3. Retrigger probing and announcing for all our authoritative records
3703 for (rr = m->ResourceRecords; rr; rr=rr->next)
3704 if (AuthRecord_uDNS(rr))
3705 {
3706 ActivateUnicastRegistration(m, rr);
3707 }
3708 else
3709 {
3710 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
3711 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
3712 rr->AnnounceCount = InitialAnnounceCount;
3713 InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
3714 }
3715 }
3716
3717 mDNS_Unlock(m);
3718 }
3719
3720 // ***************************************************************************
3721 #if COMPILER_LIKES_PRAGMA_MARK
3722 #pragma mark -
3723 #pragma mark - Packet Reception Functions
3724 #endif
3725
3726 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
3727
3728 mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end,
3729 const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords)
3730 {
3731 mDNSu8 *responseptr = response->data;
3732 const mDNSu8 *const limit = response->data + sizeof(response->data);
3733 const mDNSu8 *ptr = query->data;
3734 AuthRecord *rr;
3735 mDNSu32 maxttl = 0x70000000;
3736 int i;
3737
3738 // Initialize the response fields so we can answer the questions
3739 InitializeDNSMessage(&response->h, query->h.id, ResponseFlags);
3740
3741 // ***
3742 // *** 1. Write out the list of questions we are actually going to answer with this packet
3743 // ***
3744 if (LegacyQuery)
3745 {
3746 maxttl = 10;
3747 for (i=0; i<query->h.numQuestions; i++) // For each question...
3748 {
3749 DNSQuestion q;
3750 ptr = getQuestion(query, ptr, end, InterfaceID, &q); // get the question...
3751 if (!ptr) return(mDNSNULL);
3752
3753 for (rr=ResponseRecords; rr; rr=rr->NextResponse) // and search our list of proposed answers
3754 {
3755 if (rr->NR_AnswerTo == ptr) // If we're going to generate a record answering this question
3756 { // then put the question in the question section
3757 responseptr = putQuestion(response, responseptr, limit, &q.qname, q.qtype, q.qclass);
3758 if (!responseptr) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL); }
3759 break; // break out of the ResponseRecords loop, and go on to the next question
3760 }
3761 }
3762 }
3763
3764 if (response->h.numQuestions == 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL); }
3765 }
3766
3767 // ***
3768 // *** 2. Write Answers
3769 // ***
3770 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
3771 if (rr->NR_AnswerTo)
3772 {
3773 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl);
3774 if (p) responseptr = p;
3775 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; }
3776 }
3777
3778 // ***
3779 // *** 3. Write Additionals
3780 // ***
3781 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
3782 if (rr->NR_AdditionalTo && !rr->NR_AnswerTo)
3783 {
3784 mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl);
3785 if (p) responseptr = p;
3786 else debugf("GenerateUnicastResponse: No more space for additionals");
3787 }
3788
3789 return(responseptr);
3790 }
3791
3792 // AuthRecord *our is our Resource Record
3793 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
3794 // Returns 0 if there is no conflict
3795 // Returns +1 if there was a conflict and we won
3796 // Returns -1 if there was a conflict and we lost and have to rename
3797 mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt)
3798 {
3799 mDNSu8 ourdata[256], *ourptr = ourdata, *ourend;
3800 mDNSu8 pktdata[256], *pktptr = pktdata, *pktend;
3801 if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
3802 if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
3803
3804 ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
3805 pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
3806 while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
3807 if (ourptr >= ourend && pktptr >= pktend) return(0); // If data identical, not a conflict
3808
3809 if (ourptr >= ourend) return(-1); // Our data ran out first; We lost
3810 if (pktptr >= pktend) return(+1); // Packet data ran out first; We won
3811 if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost
3812 if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won
3813
3814 LogMsg("CompareRData ERROR: Invalid state");
3815 return(-1);
3816 }
3817
3818 // See if we have an authoritative record that's identical to this packet record,
3819 // whose canonical DependentOn record is the specified master record.
3820 // The DependentOn pointer is typically used for the TXT record of service registrations
3821 // It indicates that there is no inherent conflict detection for the TXT record
3822 // -- it depends on the SRV record to resolve name conflicts
3823 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
3824 // pointer chain (if any) to make sure we reach the canonical DependentOn record
3825 // If the record has no DependentOn, then just return that record's pointer
3826 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
3827 mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *const pktrr, const AuthRecord *const master)
3828 {
3829 const AuthRecord *r1;
3830 for (r1 = m->ResourceRecords; r1; r1=r1->next)
3831 {
3832 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
3833 {
3834 const AuthRecord *r2 = r1;
3835 while (r2->DependentOn) r2 = r2->DependentOn;
3836 if (r2 == master) return(mDNStrue);
3837 }
3838 }
3839 for (r1 = m->DuplicateRecords; r1; r1=r1->next)
3840 {
3841 if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
3842 {
3843 const AuthRecord *r2 = r1;
3844 while (r2->DependentOn) r2 = r2->DependentOn;
3845 if (r2 == master) return(mDNStrue);
3846 }
3847 }
3848 return(mDNSfalse);
3849 }
3850
3851 // Find the canonical RRSet pointer for this RR received in a packet.
3852 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
3853 // pointers (if any) to make sure we return the canonical member of this name/type/class
3854 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
3855 mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *const pktrr)
3856 {
3857 const AuthRecord *rr;
3858 for (rr = m->ResourceRecords; rr; rr=rr->next)
3859 {
3860 if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
3861 {
3862 while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
3863 return(rr);
3864 }
3865 }
3866 return(mDNSNULL);
3867 }
3868
3869 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
3870 // as one of our records (our) but different rdata.
3871 // 1. If our record is not a type that's supposed to be unique, we don't care.
3872 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
3873 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
3874 // points to our record, ignore this conflict (e.g. the packet record matches one of our
3875 // TXT records, and that record is marked as dependent on 'our', its SRV record).
3876 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
3877 // are members of the same RRSet, then this is not a conflict.
3878 mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr)
3879 {
3880 const AuthRecord *ourset = our->RRSet ? our->RRSet : our;
3881
3882 // If not supposed to be unique, not a conflict
3883 if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse);
3884
3885 // If a dependent record, not a conflict
3886 if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse);
3887
3888 // If the pktrr matches a member of ourset, not a conflict
3889 if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse);
3890
3891 // Okay, this is a conflict
3892 return(mDNStrue);
3893 }
3894
3895 // NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
3896 // the record list and/or question list.
3897 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3898 mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
3899 DNSQuestion *q, AuthRecord *our)
3900 {
3901 int i;
3902 const mDNSu8 *ptr = LocateAuthorities(query, end);
3903 mDNSBool FoundUpdate = mDNSfalse;
3904
3905 for (i = 0; i < query->h.numAuthorities; i++)
3906 {
3907 ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
3908 if (!ptr) break;
3909 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
3910 {
3911 FoundUpdate = mDNStrue;
3912 if (PacketRRConflict(m, our, &m->rec.r))
3913 {
3914 int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
3915 if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype;
3916 if (!result) result = CompareRData(our, &m->rec.r);
3917 if (result > 0)
3918 LogOperation("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
3919 else if (result < 0)
3920 {
3921 LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
3922 mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
3923 goto exit;
3924 }
3925 }
3926 }
3927 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3928 }
3929 if (!FoundUpdate)
3930 LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
3931 exit:
3932 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
3933 }
3934
3935 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr)
3936 {
3937 mDNSu32 slot = HashSlot(pktrr->name);
3938 CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
3939 CacheRecord *rr;
3940 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3941 if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
3942 return(rr);
3943 }
3944
3945 // ProcessQuery examines a received query to see if we have any answers to give
3946 mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
3947 const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
3948 mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
3949 {
3950 mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
3951 AuthRecord *ResponseRecords = mDNSNULL;
3952 AuthRecord **nrp = &ResponseRecords;
3953 CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated
3954 CacheRecord **eap = &ExpectedAnswers;
3955 DNSQuestion *DupQuestions = mDNSNULL; // Our questions that are identical to questions in this packet
3956 DNSQuestion **dqp = &DupQuestions;
3957 mDNSs32 delayresponse = 0;
3958 mDNSBool SendLegacyResponse = mDNSfalse;
3959 const mDNSu8 *ptr = query->data;
3960 mDNSu8 *responseptr = mDNSNULL;
3961 AuthRecord *rr;
3962 int i;
3963
3964 // ***
3965 // *** 1. Parse Question Section and mark potential answers
3966 // ***
3967 for (i=0; i<query->h.numQuestions; i++) // For each question...
3968 {
3969 mDNSBool QuestionNeedsMulticastResponse;
3970 int NumAnswersForThisQuestion = 0;
3971 DNSQuestion pktq, *q;
3972 ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
3973 if (!ptr) goto exit;
3974
3975 // The only queries that *need* a multicast response are:
3976 // * Queries sent via multicast
3977 // * from port 5353
3978 // * that don't have the kDNSQClass_UnicastResponse bit set
3979 // These queries need multicast responses because other clients will:
3980 // * suppress their own identical questions when they see these questions, and
3981 // * expire their cache records if they don't see the expected responses
3982 // For other queries, we may still choose to send the occasional multicast response anyway,
3983 // to keep our neighbours caches warm, and for ongoing conflict detection.
3984 QuestionNeedsMulticastResponse = QueryWasMulticast && !LegacyQuery && !(pktq.qclass & kDNSQClass_UnicastResponse);
3985 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
3986 pktq.qclass &= ~kDNSQClass_UnicastResponse;
3987
3988 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
3989 // can result in user callbacks which may change the record list and/or question list.
3990 // Also note: we just mark potential answer records here, without trying to build the
3991 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
3992 // from that list while we're in the middle of trying to build it.
3993 if (m->CurrentRecord)
3994 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
3995 m->CurrentRecord = m->ResourceRecords;
3996 while (m->CurrentRecord)
3997 {
3998 rr = m->CurrentRecord;
3999 m->CurrentRecord = rr->next;
4000 if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
4001 {
4002 if (rr->resrec.RecordType == kDNSRecordTypeUnique)
4003 ResolveSimultaneousProbe(m, query, end, &pktq, rr);
4004 else if (ResourceRecordIsValidAnswer(rr))
4005 {
4006 NumAnswersForThisQuestion++;
4007 // Notes:
4008 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
4009 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
4010 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
4011 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
4012 // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
4013 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
4014 if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
4015 {
4016 // We only mark this question for sending if it is at least one second since the last time we multicast it
4017 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
4018 // This is to guard against the case where someone blasts us with queries as fast as they can.
4019 if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
4020 (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
4021 rr->NR_AnswerTo = (mDNSu8*)~0;
4022 }
4023 else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
4024 }
4025 }
4026 }
4027
4028 // If we couldn't answer this question, someone else might be able to,
4029 // so use random delay on response to reduce collisions
4030 if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
4031
4032 // We only do the following accelerated cache expiration processing and duplicate question suppression processing
4033 // for multicast queries with multicast responses.
4034 // For any query generating a unicast response we don't do this because we can't assume we will see the response
4035 if (QuestionNeedsMulticastResponse)
4036 {
4037 const mDNSu32 slot = HashSlot(&pktq.qname);
4038 CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
4039 CacheRecord *cr;
4040
4041 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
4042 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
4043 for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
4044 if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
4045 if (!cr->NextInKAList && eap != &cr->NextInKAList)
4046 {
4047 *eap = cr;
4048 eap = &cr->NextInKAList;
4049 if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
4050 {
4051 // Although MPUnansweredQ is only really used for multi-packet query processing,
4052 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
4053 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
4054 cr->MPUnansweredQ++;
4055 cr->MPLastUnansweredQT = m->timenow;
4056 cr->MPExpectingKA = mDNStrue;
4057 }
4058 }
4059
4060 // Check if this question is the same as any of mine.
4061 // We only do this for non-truncated queries. Right now it would be too complicated to try
4062 // to keep track of duplicate suppression state between multiple packets, especially when we
4063 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
4064 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
4065 for (q = m->Questions; q; q=q->next)
4066 if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
4067 if (!q->InterfaceID || q->InterfaceID == InterfaceID)
4068 if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
4069 if (q->qtype == pktq.qtype &&
4070 q->qclass == pktq.qclass &&
4071 q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
4072 { *dqp = q; dqp = &q->NextInDQList; }
4073 }
4074 }
4075
4076 // ***
4077 // *** 2. Now we can safely build the list of marked answers
4078 // ***
4079 for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers
4080 if (rr->NR_AnswerTo) // If we marked the record...
4081 AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list
4082
4083 // ***
4084 // *** 3. Add additional records
4085 // ***
4086 AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID);
4087
4088 // ***
4089 // *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
4090 // ***
4091 for (i=0; i<query->h.numAnswers; i++) // For each record in the query's answer section...
4092 {
4093 // Get the record...
4094 CacheRecord *ourcacherr;
4095 ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
4096 if (!ptr) goto exit;
4097
4098 // See if this Known-Answer suppresses any of our currently planned answers
4099 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4100 if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
4101 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
4102
4103 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
4104 for (rr=m->ResourceRecords; rr; rr=rr->next)
4105 {
4106 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
4107 if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
4108 {
4109 if (srcaddr->type == mDNSAddrType_IPv4)
4110 {
4111 if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
4112 }
4113 else if (srcaddr->type == mDNSAddrType_IPv6)
4114 {
4115 if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
4116 }
4117 if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
4118 {
4119 rr->ImmedAnswer = mDNSNULL;
4120 rr->ImmedUnicast = mDNSfalse;
4121 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4122 LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
4123 #endif
4124 }
4125 }
4126 }
4127
4128 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
4129 // 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).
4130 ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
4131 if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
4132 {
4133 ourcacherr->MPUnansweredKA++;
4134 ourcacherr->MPExpectingKA = mDNSfalse;
4135 }
4136
4137 // Having built our ExpectedAnswers list from the questions in this packet, we can definitively
4138 // remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
4139 // For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
4140 eap = &ExpectedAnswers;
4141 while (*eap)
4142 {
4143 CacheRecord *cr = *eap;
4144 if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
4145 { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
4146 else eap = &cr->NextInKAList;
4147 }
4148
4149 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
4150 if (!ourcacherr)
4151 {
4152 dqp = &DupQuestions;
4153 while (*dqp)
4154 {
4155 DNSQuestion *q = *dqp;
4156 if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
4157 { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
4158 else dqp = &q->NextInDQList;
4159 }
4160 }
4161 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4162 }
4163
4164 // ***
4165 // *** 5. Cancel any additionals that were added because of now-deleted records
4166 // ***
4167 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4168 if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo))
4169 { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
4170
4171 // ***
4172 // *** 6. Mark the send flags on the records we plan to send
4173 // ***
4174 for (rr=ResponseRecords; rr; rr=rr->NextResponse)
4175 {
4176 if (rr->NR_AnswerTo)
4177 {
4178 mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response
4179 mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response)
4180
4181 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
4182 if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
4183 {
4184 SendMulticastResponse = mDNStrue;
4185 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
4186 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
4187 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
4188 if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
4189 }
4190
4191 // If the client insists on a multicast response, then we'd better send one
4192 if (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
4193 else if (rr->NR_AnswerTo == (mDNSu8*)~1) SendUnicastResponse = mDNStrue;
4194 else if (rr->NR_AnswerTo) SendLegacyResponse = mDNStrue;
4195
4196 if (SendMulticastResponse || SendUnicastResponse)
4197 {
4198 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4199 rr->ImmedAnswerMarkTime = m->timenow;
4200 #endif
4201 m->NextScheduledResponse = m->timenow;
4202 // If we're already planning to send this on another interface, just send it on all interfaces
4203 if (rr->ImmedAnswer && rr->ImmedAnswer != InterfaceID)
4204 rr->ImmedAnswer = mDNSInterfaceMark;
4205 else
4206 {
4207 rr->ImmedAnswer = InterfaceID; // Record interface to send it on
4208 if (SendUnicastResponse) rr->ImmedUnicast = mDNStrue;
4209 if (srcaddr->type == mDNSAddrType_IPv4)
4210 {
4211 if (mDNSIPv4AddressIsZero(rr->v4Requester)) rr->v4Requester = srcaddr->ip.v4;
4212 else if (!mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = onesIPv4Addr;
4213 }
4214 else if (srcaddr->type == mDNSAddrType_IPv6)
4215 {
4216 if (mDNSIPv6AddressIsZero(rr->v6Requester)) rr->v6Requester = srcaddr->ip.v6;
4217 else if (!mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = onesIPv6Addr;
4218 }
4219 }
4220 }
4221 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
4222 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
4223 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
4224 // else, for a simple unique record reply, we can reply immediately; no need for delay
4225 if (query->h.flags.b[0] & kDNSFlag0_TC) delayresponse = mDNSPlatformOneSecond * 20; // Divided by 50 = 400ms
4226 else if (rr->resrec.RecordType == kDNSRecordTypeShared) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms
4227 }
4228 else if (rr->NR_AdditionalTo && rr->NR_AdditionalTo->NR_AnswerTo == (mDNSu8*)~0)
4229 {
4230 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
4231 // If two clients on different interfaces do queries that invoke the same optional additional answer,
4232 // then the earlier client is out of luck
4233 rr->ImmedAdditional = InterfaceID;
4234 // No need to set m->NextScheduledResponse here
4235 // We'll send these additional records when we send them, or not, as the case may be
4236 }
4237 }
4238
4239 // ***
4240 // *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
4241 // ***
4242 if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50))
4243 {
4244 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4245 mDNSs32 oldss = m->SuppressSending;
4246 if (oldss && delayresponse)
4247 LogMsg("Current SuppressSending delay%5ld; require%5ld", m->SuppressSending - m->timenow, (delayresponse + 49) / 50);
4248 #endif
4249 // Pick a random delay:
4250 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
4251 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
4252 // This is an integer value, with resolution determined by the platform clock rate.
4253 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
4254 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
4255 // The +49 before dividing is to ensure we round up, not down, to ensure that even
4256 // on platforms where the native clock rate is less than fifty ticks per second,
4257 // we still guarantee that the final calculated delay is at least one platform tick.
4258 // We want to make sure we don't ever allow the delay to be zero ticks,
4259 // because if that happens we'll fail the Bonjour Conformance Test.
4260 // Our final computed delay is 20-120ms for normal delayed replies,
4261 // or 400-500ms in the case of multi-packet known-answer lists.
4262 m->SuppressSending = m->timenow + (delayresponse + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*5) + 49) / 50;
4263 if (m->SuppressSending == 0) m->SuppressSending = 1;
4264 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4265 if (oldss && delayresponse)
4266 LogMsg("Set SuppressSending to %5ld", m->SuppressSending - m->timenow);
4267 #endif
4268 }
4269
4270 // ***
4271 // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
4272 // ***
4273 if (SendLegacyResponse)
4274 responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords);
4275
4276 exit:
4277 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4278
4279 // ***
4280 // *** 9. Finally, clear our link chains ready for use next time
4281 // ***
4282 while (ResponseRecords)
4283 {
4284 rr = ResponseRecords;
4285 ResponseRecords = rr->NextResponse;
4286 rr->NextResponse = mDNSNULL;
4287 rr->NR_AnswerTo = mDNSNULL;
4288 rr->NR_AdditionalTo = mDNSNULL;
4289 }
4290
4291 while (ExpectedAnswers)
4292 {
4293 CacheRecord *cr = ExpectedAnswers;
4294 ExpectedAnswers = cr->NextInKAList;
4295 cr->NextInKAList = mDNSNULL;
4296
4297 // For non-truncated queries, we can definitively say that we should expect
4298 // to be seeing a response for any records still left in the ExpectedAnswers list
4299 if (!(query->h.flags.b[0] & kDNSFlag0_TC))
4300 if (cr->UnansweredQueries == 0 || m->timenow - cr->LastUnansweredTime >= mDNSPlatformOneSecond)
4301 {
4302 cr->UnansweredQueries++;
4303 cr->LastUnansweredTime = m->timenow;
4304 if (cr->UnansweredQueries > 1)
4305 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
4306 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
4307 SetNextCacheCheckTime(m, cr);
4308 }
4309
4310 // If we've seen multiple unanswered queries for this record,
4311 // then mark it to expire in five seconds if we don't get a response by then.
4312 if (cr->UnansweredQueries >= MaxUnansweredQueries)
4313 {
4314 // Only show debugging message if this record was not about to expire anyway
4315 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
4316 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
4317 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
4318 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
4319 }
4320 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
4321 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
4322 // possible packet loss of up to 20% of the additional KA packets.)
4323 else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8)
4324 {
4325 // We want to do this conservatively.
4326 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
4327 // then we don't want them to all hit the network simultaneously with their final expiration queries.
4328 // By setting the record to expire in four minutes, we achieve two things:
4329 // (a) the 90-95% final expiration queries will be less bunched together
4330 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
4331 mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4;
4332 if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
4333 remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
4334
4335 // Only show debugging message if this record was not about to expire anyway
4336 if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
4337 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
4338 cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
4339
4340 if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
4341 cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query
4342 cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics
4343 cr->MPUnansweredKA = 0;
4344 cr->MPExpectingKA = mDNSfalse;
4345
4346 if (remain < kDefaultReconfirmTimeForNoAnswer)
4347 remain = kDefaultReconfirmTimeForNoAnswer;
4348 mDNS_Reconfirm_internal(m, cr, remain);
4349 }
4350 }
4351
4352 while (DupQuestions)
4353 {
4354 DNSQuestion *q = DupQuestions;
4355 DupQuestions = q->NextInDQList;
4356 q->NextInDQList = mDNSNULL;
4357 i = RecordDupSuppressInfo(q->DupSuppress, m->timenow, InterfaceID, srcaddr->type);
4358 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
4359 srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6", i);
4360 }
4361
4362 return(responseptr);
4363 }
4364
4365 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
4366 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
4367 const mDNSInterfaceID InterfaceID)
4368 {
4369 mDNSu8 *responseend = mDNSNULL;
4370 mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr &&
4371 !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
4372
4373 if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
4374 {
4375 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
4376 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
4377 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
4378 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
4379 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
4380 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
4381 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
4382 return;
4383 }
4384
4385 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
4386 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
4387 srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
4388 msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
4389 msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
4390 msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
4391 msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
4392
4393 responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
4394 !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
4395
4396 if (responseend) // If responseend is non-null, that means we built a unicast response packet
4397 {
4398 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
4399 m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
4400 m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
4401 m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
4402 srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
4403 mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, mDNSNULL, mDNSNULL);
4404 }
4405 }
4406
4407 mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
4408 {
4409 DNSServer *s;
4410 (void)m; // Unused
4411 (void)srcaddr; // Unused
4412 for (s = m->DNSServers; s; s = s->next)
4413 if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
4414 return(mDNSfalse);
4415 }
4416
4417 mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSOpaque16 id, const DNSQuestion *const question)
4418 {
4419 DNSQuestion *q;
4420 for (q = m->Questions; q; q=q->next)
4421 if (mDNSSameOpaque16(q->TargetQID, id) &&
4422 q->qtype == question->qtype &&
4423 q->qclass == question->qclass &&
4424 q->qnamehash == question->qnamehash &&
4425 SameDomainName(&q->qname, &question->qname))
4426 return(q);
4427 return(mDNSNULL);
4428 }
4429
4430 mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSOpaque16 id, const CacheRecord *const rr)
4431 {
4432 DNSQuestion *q;
4433 (void)id;
4434 for (q = m->Questions; q; q=q->next)
4435 if (ResourceRecordAnswersQuestion(&rr->resrec, q))
4436 {
4437 if (!mDNSOpaque16IsZero(q->TargetQID))
4438 {
4439 // For now we don't do this check -- for LLQ updates, the ID doesn't seem to match the ID in the question
4440 // if (mDNSSameOpaque16(q->TargetQID, id)
4441 {
4442 if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
4443 if (mDNSSameOpaque16(q->TargetQID, id)) return(mDNStrue);
4444 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
4445 if (TrustedSource(m, srcaddr)) return(mDNStrue);
4446 LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s",
4447 q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
4448 return(mDNSfalse);
4449 }
4450 }
4451 else
4452 {
4453 if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
4454 return(mDNStrue);
4455 }
4456 }
4457 return(mDNSfalse);
4458 }
4459
4460 mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
4461 {
4462 CacheRecord *rr = mDNSNULL;
4463
4464 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
4465 // Currently this applies only to rdata types containing more than one domainname,
4466 // or types where the domainname is not the last item in the structure
4467 mDNSu16 RDLength;
4468 switch (m->rec.r.resrec.rrtype)
4469 {
4470 case kDNSType_SOA: RDLength = sizeof(rdataSOA); break;
4471 case kDNSType_RP: RDLength = sizeof(rdataRP); break;
4472 case kDNSType_PX: RDLength = sizeof(rdataPX); break;
4473 default: RDLength = m->rec.r.resrec.rdlength; break;
4474 }
4475
4476 if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r));
4477
4478 //if (RDLength > InlineCacheRDSize)
4479 // LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
4480
4481 if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now
4482 if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg
4483 if (!rr) NoCacheAnswer(m, &m->rec.r);
4484 else
4485 {
4486 RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
4487 *rr = m->rec.r; // Block copy the CacheRecord object
4488 rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
4489 rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
4490
4491 // If this is an oversized record with external storage allocated, copy rdata to external storage
4492 if (rr->resrec.rdata == (RData*)&rr->rdatastorage && RDLength > InlineCacheRDSize)
4493 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
4494 else if (rr->resrec.rdata != (RData*)&rr->rdatastorage && RDLength <= InlineCacheRDSize)
4495 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
4496 if (RDLength > InlineCacheRDSize)
4497 mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
4498
4499 rr->next = mDNSNULL; // Clear 'next' pointer
4500 *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
4501 cg->rrcache_tail = &(rr->next); // Advance tail pointer
4502 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
4503 rr->DelayDelivery = NonZeroTime(m->timenow);
4504 else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique,
4505 rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have
4506 rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event
4507 else
4508 rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
4509
4510 CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
4511 }
4512 return(rr);
4513 }
4514
4515 mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
4516 {
4517 rr->TimeRcvd = m->timenow;
4518 rr->resrec.rroriginalttl = ttl;
4519 rr->UnansweredQueries = 0;
4520 rr->MPUnansweredQ = 0;
4521 rr->MPUnansweredKA = 0;
4522 rr->MPExpectingKA = mDNSfalse;
4523 SetNextCacheCheckTime(m, rr);
4524 }
4525
4526 mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
4527 {
4528 CacheRecord *rr;
4529 const mDNSu32 slot = HashSlot(&q->qname);
4530 CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
4531 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4532 if (rr->CRActiveQuestion == q)
4533 {
4534 //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
4535 RefreshCacheRecord(m, rr, lease);
4536 }
4537 }
4538
4539 mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds
4540 {
4541 if (LLQType == uDNS_LLQ_Entire) ttl = kLLQ_DefLease;
4542 else if (LLQType == uDNS_LLQ_Events)
4543 {
4544 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
4545 if (ttl == 0xFFFFFFFF) ttl = 0;
4546 else ttl = kLLQ_DefLease;
4547 }
4548 else // else not LLQ (standard uDNS response)
4549 {
4550 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
4551 // also do this check here to make sure we can't get integer overflow below
4552 if (ttl > 0x8000000UL) ttl = 0x8000000UL;
4553
4554 // Adjustment factor to avoid race condition:
4555 // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
4556 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
4557 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
4558 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
4559 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
4560 // the cached copy at our local caching server will already have expired, so the server will be forced
4561 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
4562 ttl += ttl/4 + 2;
4563
4564 // For mDNS, TTL zero means "delete this record"
4565 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
4566 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
4567 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
4568 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
4569 if (ttl < 15) ttl = 15;
4570 }
4571
4572 return ttl;
4573 }
4574
4575 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
4576 // the record list and/or question list.
4577 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4578 mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
4579 const DNSMessage *const response, const mDNSu8 *end,
4580 const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
4581 const mDNSInterfaceID InterfaceID)
4582 {
4583 int i;
4584 mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
4585 mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
4586 uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
4587
4588 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
4589 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
4590 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
4591 CacheRecord *CacheFlushRecords = (CacheRecord*)1;
4592 CacheRecord **cfp = &CacheFlushRecords;
4593
4594 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
4595 // to guard against spoof responses, then the only credible protection against that is cryptographic
4596 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
4597 int firstauthority = response->h.numAnswers;
4598 int firstadditional = firstauthority + response->h.numAuthorities;
4599 int totalrecords = firstadditional + response->h.numAdditionals;
4600 const mDNSu8 *ptr = response->data;
4601
4602 // Currently used only for display in debugging message
4603 (void)srcport;
4604 (void)dstport;
4605
4606 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
4607 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
4608 srcaddr, dstaddr, InterfaceID,
4609 response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
4610 response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
4611 response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
4612 response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
4613
4614 if (LLQType == uDNS_LLQ_Ignore) return;
4615
4616 // 1. We ignore questions (if any) in mDNS response packets
4617 // 2. If this is an LLQ response, we handle it much the same
4618 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
4619 // answer as being the authoritative complete RRSet, and respond by deleting all other
4620 // matching cache records that don't appear in this packet.
4621 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
4622 if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC))
4623 ptr = LocateAnswers(response, end);
4624 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
4625 // in this response packet are immediately deemed to be invalid.
4626 else
4627 {
4628 // We could possibly combine this with the similar loop at the end of this function --
4629 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
4630 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
4631 // which it was received (or refreshed), and then at the end if we find any cache records which
4632 // answer questions in this packet's question section, but which aren't tagged with this packet's
4633 // packet number, then we deduce they are old and delete them
4634 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
4635 {
4636 DNSQuestion q;
4637 ptr = getQuestion(response, ptr, end, InterfaceID, &q);
4638 if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
4639 {
4640 CacheRecord *rr;
4641 const mDNSu32 slot = HashSlot(&q.qname);
4642 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
4643 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4644 if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
4645 {
4646 //LogMsg("uDNS marking %s", CRDisplayString(m, rr));
4647 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
4648 rr->TimeRcvd = m->timenow - TicksTTL(rr) - 1;
4649 rr->UnansweredQueries = MaxUnansweredQueries;
4650 }
4651 }
4652 }
4653 }
4654
4655 for (i = 0; i < totalrecords && ptr && ptr < end; i++)
4656 {
4657 // All responses sent via LL multicast are acceptable for caching
4658 // All responses received over our outbound TCP connections are acceptable for caching
4659 mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
4660 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
4661 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
4662
4663 const mDNSu8 RecordType =
4664 (i < firstauthority ) ? (mDNSu8)kDNSRecordTypePacketAns :
4665 (i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd;
4666 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
4667 if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting
4668
4669 // Don't want to cache OPT or TSIG pseudo-RRs
4670 if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
4671 { m->rec.r.resrec.RecordType = 0; continue; }
4672
4673 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
4674 // In the case of active LLQs, we'll get remove events when the records actually do go away
4675 // In the case of polling LLQs, we assume the record remains valid until the next poll
4676 if (!mDNSOpaque16IsZero(response->h.id))
4677 m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
4678
4679 // If response was not sent via LL multicast,
4680 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
4681 if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, response->h.id, &m->rec.r);
4682
4683 // 1. Check that this packet resource record does not conflict with any of ours
4684 if (mDNSOpaque16IsZero(response->h.id))
4685 {
4686 if (m->CurrentRecord)
4687 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
4688 m->CurrentRecord = m->ResourceRecords;
4689 while (m->CurrentRecord)
4690 {
4691 AuthRecord *rr = m->CurrentRecord;
4692 m->CurrentRecord = rr->next;
4693 // We accept all multicast responses, and unicast responses resulting from queries we issued
4694 // For other unicast responses, this code accepts them only for responses with an
4695 // (apparently) local source address that pertain to a record of our own that's in probing state
4696 if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue;
4697 if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match...
4698 {
4699 // ... check to see if type and rdata are identical
4700 if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
4701 {
4702 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
4703 if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
4704 {
4705 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
4706 if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
4707 }
4708 else
4709 {
4710 if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; }
4711 else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
4712 }
4713 }
4714 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
4715 else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
4716 {
4717 debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
4718 debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
4719
4720 // If this record is marked DependentOn another record for conflict detection purposes,
4721 // then *that* record has to be bumped back to probing state to resolve the conflict
4722 while (rr->DependentOn) rr = rr->DependentOn;
4723
4724 // If we've just whacked this record's ProbeCount, don't need to do it again
4725 if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
4726 {
4727 // If we'd previously verified this record, put it back to probing state and try again
4728 if (rr->resrec.RecordType == kDNSRecordTypeVerified)
4729 {
4730 debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4731 rr->resrec.RecordType = kDNSRecordTypeUnique;
4732 rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
4733 InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique));
4734 RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
4735 }
4736 // If we're probing for this record, we just failed
4737 else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
4738 {
4739 debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4740 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
4741 }
4742 // We assumed this record must be unique, but we were wrong.
4743 // (e.g. There are two mDNSResponders on the same machine giving
4744 // different answers for the reverse mapping record.)
4745 // This is simply a misconfiguration, and we don't try to recover from it.
4746 else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
4747 {
4748 debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
4749 rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4750 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
4751 }
4752 else
4753 debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
4754 rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
4755 }
4756 }
4757 // Else, matching signature, different type or rdata, but not a considered a conflict.
4758 // If the packet record has the cache-flush bit set, then we check to see if we
4759 // have any record(s) of the same type that we should re-assert to rescue them
4760 // (see note about "multi-homing and bridged networks" at the end of this function).
4761 else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
4762 if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
4763 { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
4764 }
4765 }
4766 }
4767
4768 if (!AcceptableResponse)
4769 {
4770 CacheRecord *cr;
4771 for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
4772 {
4773 domainname *target = GetRRDomainNameTarget(&cr->resrec);
4774 if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name))
4775 { AcceptableResponse = mDNStrue; break; }
4776 }
4777 }
4778
4779 // 2. See if we want to add this packet resource record to our cache
4780 // We only try to cache answers if we have a cache to put them in
4781 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
4782 if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
4783 if (m->rrcache_size && AcceptableResponse)
4784 {
4785 const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
4786 CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
4787 CacheRecord *rr;
4788 // 2a. Check if this packet resource record is already in our cache
4789 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4790 {
4791 // If we found this exact resource record, refresh its TTL
4792 if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
4793 {
4794 if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
4795 verbosedebugf("Found record size %5d interface %p already in cache: %s",
4796 m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
4797 rr->TimeRcvd = m->timenow;
4798
4799 if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
4800 {
4801 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
4802 if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
4803 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
4804
4805 // If this packet record is marked unique, and our previous cached copy was not, then fix it
4806 if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
4807 {
4808 DNSQuestion *q;
4809 for (q = m->Questions; q; q=q->next) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) q->UniqueAnswers++;
4810 rr->resrec.RecordType = m->rec.r.resrec.RecordType;
4811 }
4812 }
4813
4814 if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
4815 {
4816 // If the rdata of the packet record differs in name capitalization from the record in our cache
4817 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
4818 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
4819 rr->resrec.rroriginalttl = 0;
4820 rr->UnansweredQueries = MaxUnansweredQueries;
4821 SetNextCacheCheckTime(m, rr);
4822 // DO NOT break out here -- we want to continue as if we never found it
4823 }
4824 else if (m->rec.r.resrec.rroriginalttl > 0)
4825 {
4826 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
4827 RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
4828 break;
4829 }
4830 else
4831 {
4832 // If the packet TTL is zero, that means we're deleting this record.
4833 // To give other hosts on the network a chance to protest, we push the deletion
4834 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
4835 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
4836 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
4837 debugf("DE for %s", CRDisplayString(m, rr));
4838 rr->resrec.rroriginalttl = 1;
4839 rr->UnansweredQueries = MaxUnansweredQueries;
4840 SetNextCacheCheckTime(m, rr);
4841 break;
4842 }
4843 }
4844 }
4845
4846 // If packet resource record not in our cache, add it now
4847 // (unless it is just a deletion of a record we never had, in which case we don't care)
4848 if (!rr && m->rec.r.resrec.rroriginalttl > 0)
4849 {
4850 rr = CreateNewCacheEntry(m, slot, cg);
4851 if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
4852 { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
4853 }
4854 }
4855 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4856 }
4857
4858 exit:
4859 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
4860
4861 // If we've just received one or more records with their cache flush bits set,
4862 // then scan that cache slot to see if there are any old stale records we need to flush
4863 while (CacheFlushRecords != (CacheRecord*)1)
4864 {
4865 CacheRecord *r1 = CacheFlushRecords, *r2;
4866 const mDNSu32 slot = HashSlot(r1->resrec.name);
4867 const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
4868 CacheFlushRecords = CacheFlushRecords->NextInCFList;
4869 r1->NextInCFList = mDNSNULL;
4870
4871 // Look for records in the cache with the same signature as this new one with the cache flush
4872 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
4873 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
4874 // We make these TTL adjustments *only* for records that still have *more* than one second
4875 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
4876 // (and now has half a second remaining) could inadvertently get its life extended, by either
4877 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
4878 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
4879 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
4880 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
4881 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
4882 // To avoid this, we need to ensure that the cache flushing operation will only act to
4883 // *decrease* a record's remaining lifetime, never *increase* it.
4884 for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
4885 if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
4886 r1->resrec.rrtype == r2->resrec.rrtype &&
4887 r1->resrec.rrclass == r2->resrec.rrclass)
4888 {
4889 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
4890 // else, if record is old, mark it to be flushed
4891 if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
4892 {
4893 // If we find mismatched TTLs in an RRSet, correct them.
4894 // We only do this for records with a TTL of 2 or higher. It's possible to have a
4895 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
4896 // which we treat as a goodbye followed by an addition) and in that case it would be
4897 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
4898 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
4899 // because certain early Bonjour devices are known to have this specific mismatch, and
4900 // there's no point filling syslog with messages about something we already know about.
4901 // We also don't log this for uDNS responses, since a caching name server is obliged
4902 // to give us an aged TTL to correct for how long it has held the record,
4903 // so our received TTLs are expected to vary in that case
4904 if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
4905 {
4906 if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
4907 mDNSOpaque16IsZero(response->h.id))
4908 LogOperation("Correcting TTL from %4d to %4d for %s",
4909 r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
4910 r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
4911 }
4912 r2->TimeRcvd = m->timenow;
4913 }
4914 else // else, if record is old, mark it to be flushed
4915 {
4916 verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
4917 // We set stale records to expire in one second.
4918 // This gives the owner a chance to rescue it if necessary.
4919 // This is important in the case of multi-homing and bridged networks:
4920 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
4921 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
4922 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
4923 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
4924 // By delaying the deletion by one second, we give X a change to notice that this bridging has
4925 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
4926
4927 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
4928 // final expiration queries for this record.
4929
4930 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
4931 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
4932 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
4933 if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
4934 {
4935 debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
4936 r2->resrec.rroriginalttl = 0;
4937 m->NextCacheCheck = m->timenow;
4938 m->NextScheduledEvent = m->timenow;
4939 }
4940 else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
4941 {
4942 // We only set a record to expire in one second if it currently has *more* than a second to live
4943 // If it's already due to expire in a second or less, we just leave it alone
4944 r2->resrec.rroriginalttl = 1;
4945 r2->UnansweredQueries = MaxUnansweredQueries;
4946 r2->TimeRcvd = m->timenow - 1;
4947 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
4948 // that we marked for deletion via an explicit DE record
4949 }
4950 }
4951 SetNextCacheCheckTime(m, r2);
4952 }
4953 if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
4954 {
4955 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
4956 r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
4957 if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
4958 }
4959 }
4960
4961 // See if we need to generate negative cache entries for unanswered unicast questions
4962 ptr = response->data;
4963 for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
4964 {
4965 DNSQuestion q;
4966 ptr = getQuestion(response, ptr, end, InterfaceID, &q);
4967 if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
4968 {
4969 CacheRecord *rr, *neg = mDNSNULL;
4970 mDNSu32 slot = HashSlot(&q.qname);
4971 CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
4972 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
4973 if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
4974 {
4975 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
4976 if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break;
4977 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
4978 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
4979 }
4980
4981 if (!rr)
4982 {
4983 // We start off assuming a negative caching TTL of 60 seconds
4984 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
4985 mDNSu32 negttl = 60;
4986 int repeat = 0;
4987 const domainname *name = &q.qname;
4988 mDNSu32 hash = q.qnamehash;
4989
4990 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
4991 if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
4992 {
4993 ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
4994 if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
4995 {
4996 mDNSu32 ttl_s = m->rec.r.resrec.rroriginalttl < m->rec.r.resrec.rdata->u.soa.min ?
4997 m->rec.r.resrec.rroriginalttl : m->rec.r.resrec.rdata->u.soa.min;
4998 if (negttl < ttl_s) negttl = ttl_s;
4999
5000 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
5001 // with an Authority Section SOA record for d.com, then this is a hint that the authority
5002 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
5003 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
5004 if (q.qtype == kDNSType_SOA)
5005 {
5006 int qcount = CountLabels(&q.qname);
5007 int scount = CountLabels(m->rec.r.resrec.name);
5008 if (qcount - 1 > scount)
5009 if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
5010 repeat = qcount - 1 - scount;
5011 }
5012 }
5013 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5014 }
5015
5016 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
5017 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
5018 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
5019 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
5020 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
5021 // so that we back off our polling rate and don't keep hitting the server continually.
5022 if (neg)
5023 {
5024 if (negttl < neg->resrec.rroriginalttl * 2)
5025 negttl = neg->resrec.rroriginalttl * 2;
5026 if (negttl > 3600)
5027 negttl = 3600;
5028 }
5029
5030 negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary
5031
5032 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
5033 if (neg)
5034 {
5035 LogOperation("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
5036 RefreshCacheRecord(m, neg, negttl);
5037 }
5038 else while (1)
5039 {
5040 LogOperation("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
5041 MakeNegativeCacheRecord(m, name, hash, q.qtype, q.qclass, negttl);
5042 CreateNewCacheEntry(m, slot, cg);
5043 m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
5044 if (!repeat) break;
5045 repeat--;
5046 name = (const domainname *)(name->c + 1 + name->c[0]);
5047 hash = DomainNameHashValue(name);
5048 slot = HashSlot(name);
5049 cg = CacheGroupForName(m, slot, hash, name);
5050 }
5051 }
5052 }
5053 }
5054 }
5055
5056 mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds)
5057 {
5058 // Create empty resource record
5059 m->rec.r.resrec.RecordType = kDNSRecordTypePacketNegative;
5060 m->rec.r.resrec.InterfaceID = mDNSInterface_Any;
5061 m->rec.r.resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry
5062 m->rec.r.resrec.rrtype = rrtype;
5063 m->rec.r.resrec.rrclass = rrclass;
5064 m->rec.r.resrec.rroriginalttl = ttl_seconds;
5065 m->rec.r.resrec.rdlength = 0;
5066 m->rec.r.resrec.rdestimate = 0;
5067 m->rec.r.resrec.namehash = namehash;
5068 m->rec.r.resrec.rdatahash = 0;
5069 m->rec.r.resrec.rdata = (RData*)&m->rec.r.rdatastorage;
5070 m->rec.r.resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
5071
5072 m->rec.r.NextInKAList = mDNSNULL;
5073 m->rec.r.TimeRcvd = m->timenow;
5074 m->rec.r.DelayDelivery = 0;
5075 m->rec.r.NextRequiredQuery = m->timenow;
5076 m->rec.r.LastUsed = m->timenow;
5077 m->rec.r.CRActiveQuestion = mDNSNULL;
5078 m->rec.r.UnansweredQueries = 0;
5079 m->rec.r.LastUnansweredTime = 0;
5080 m->rec.r.MPUnansweredQ = 0;
5081 m->rec.r.MPLastUnansweredQT = 0;
5082 m->rec.r.MPUnansweredKA = 0;
5083 m->rec.r.MPExpectingKA = mDNSfalse;
5084 m->rec.r.NextInCFList = mDNSNULL;
5085 }
5086
5087 struct UDPSocket_struct
5088 {
5089 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
5090 };
5091
5092 mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
5093 const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
5094 const mDNSInterfaceID InterfaceID)
5095 {
5096 mDNSInterfaceID ifid = InterfaceID;
5097 DNSMessage *msg = (DNSMessage *)pkt;
5098 const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery;
5099 const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
5100 const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
5101 mDNSu8 QR_OP;
5102 mDNSu8 *ptr = mDNSNULL;
5103 mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
5104 if (TLS) dstaddr = mDNSNULL;
5105
5106 #ifndef UNICAST_DISABLED
5107 if (mDNSSameAddress(srcaddr, &m->Router))
5108 {
5109 #ifdef _LEGACY_NAT_TRAVERSAL_
5110 if (mDNSSameIPPort(srcport, SSDPPort) || (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)))
5111 {
5112 mDNS_Lock(m);
5113 LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
5114 mDNS_Unlock(m);
5115 return;
5116 }
5117 #endif
5118 if (mDNSSameIPPort(srcport, NATPMPPort))
5119 {
5120 mDNS_Lock(m);
5121 uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
5122 mDNS_Unlock(m);
5123 return;
5124 }
5125 }
5126 #endif
5127 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
5128 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
5129 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
5130 ptr = (mDNSu8 *)&msg->h.numQuestions;
5131 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
5132 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
5133 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
5134 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
5135
5136 if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
5137
5138 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
5139 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
5140 if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
5141
5142 mDNS_Lock(m);
5143 m->PktNum++;
5144 #ifndef UNICAST_DISABLED
5145 if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR)))
5146 if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
5147 {
5148 ifid = mDNSInterface_Any;
5149 if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG)
5150 DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, msg, end);
5151 uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
5152 // Note: mDNSCore also needs to get access to received unicast responses
5153 }
5154 #endif
5155 if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
5156 else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
5157 else if (QR_OP != UpdR)
5158 {
5159 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
5160 msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
5161 }
5162 // Packet reception often causes a change to the task list:
5163 // 1. Inbound queries can cause us to need to send responses
5164 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
5165 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
5166 // 4. Response packets that answer questions may cause our client to issue new questions
5167 mDNS_Unlock(m);
5168 }
5169
5170 // ***************************************************************************
5171 #if COMPILER_LIKES_PRAGMA_MARK
5172 #pragma mark -
5173 #pragma mark - Searcher Functions
5174 #endif
5175
5176 // Targets are considered the same if both queries are untargeted, or
5177 // if both are targeted to the same address+port
5178 // (If Target address is zero, TargetPort is undefined)
5179 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
5180 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
5181
5182 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
5183 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
5184 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
5185 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
5186 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
5187
5188 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
5189 {
5190 DNSQuestion *q;
5191 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
5192 // This prevents circular references, where two questions are each marked as a duplicate of the other.
5193 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
5194 // further in the list.
5195 for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question
5196 if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID,
5197 SameQTarget(q, question) && // and same unicast/multicast target settings
5198 q->qtype == question->qtype && // type,
5199 q->qclass == question->qclass && // class,
5200 q->LongLived == question->LongLived && // and long-lived status matches
5201 (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one
5202 q->qnamehash == question->qnamehash &&
5203 SameDomainName(&q->qname, &question->qname)) // and name
5204 return(q);
5205 return(mDNSNULL);
5206 }
5207
5208 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
5209 mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
5210 {
5211 DNSQuestion *q;
5212 for (q = m->Questions; q; q=q->next) // Scan our list of questions
5213 if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate
5214 if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL)
5215 {
5216 // If q used to be a duplicate, but now is not,
5217 // then inherit the state from the question that's going away
5218 q->LastQTime = question->LastQTime;
5219 q->ThisQInterval = question->ThisQInterval;
5220 q->ExpectUnicastResp = question->ExpectUnicastResp;
5221 q->LastAnswerPktNum = question->LastAnswerPktNum;
5222 q->RecentAnswerPkts = question->RecentAnswerPkts;
5223 q->RequestUnicast = question->RequestUnicast;
5224 q->LastQTxTime = question->LastQTxTime;
5225 q->CNAMEReferrals = question->CNAMEReferrals;
5226 q->nta = question->nta;
5227 q->servAddr = question->servAddr;
5228 q->servPort = question->servPort;
5229
5230 q->state = question->state;
5231 // q->tcp = question->tcp;
5232 q->ReqLease = question->ReqLease;
5233 q->expire = question->expire;
5234 q->ntries = question->ntries;
5235 q->id = question->id;
5236
5237 question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question
5238 // question->tcp = mDNSNULL;
5239 if (q->nta)
5240 {
5241 LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5242 q->nta->ZoneDataContext = q;
5243 }
5244
5245 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
5246 if (question->tcp) LogOperation("UpdateQuestionDuplicates did not transfer tcp pointer");
5247
5248 if (question->state == LLQ_Established)
5249 {
5250 LogOperation("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
5251 question->state = 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
5252 }
5253
5254 SetNextQueryTime(m,q);
5255 }
5256 }
5257
5258 // Look up a DNS Server, matching by name in split-dns configurations.
5259 mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
5260 {
5261 DNSServer *curmatch = mDNSNULL, *p;
5262 int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
5263
5264 for (p = m->DNSServers; p; p = p->next)
5265 {
5266 int scount = CountLabels(&p->domain);
5267 if (!(p->flags & DNSServer_FlagDelete) && ncount >= scount && scount > curmatchlen)
5268 if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
5269 { curmatch = p; curmatchlen = scount; }
5270 }
5271 return(curmatch);
5272 }
5273
5274 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
5275 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
5276
5277 // Called in normal client context (lock not held)
5278 mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
5279 {
5280 DNSQuestion *q;
5281 (void)n; // Unused
5282 mDNS_Lock(m);
5283 LogOperation("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
5284 for (q = m->Questions; q; q=q->next)
5285 if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
5286 startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead
5287 #if APPLE_OSX_mDNSResponder
5288 UpdateAutoTunnelDomainStatuses(m);
5289 #endif
5290 mDNS_Unlock(m);
5291 }
5292
5293 mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
5294 {
5295 if (question->Target.type && !ValidQuestionTarget(question))
5296 {
5297 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
5298 question->Target.type, mDNSVal16(question->TargetPort));
5299 question->Target.type = mDNSAddrType_None;
5300 }
5301
5302 if (!question->Target.type) // No question->Target specified, so clear TargetPort and TargetQID
5303 {
5304 question->TargetPort = zeroIPPort;
5305 question->TargetQID = zeroID;
5306 }
5307
5308 question->TargetQID =
5309 #ifndef UNICAST_DISABLED
5310 (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)) ? mDNS_NewMessageID(m) :
5311 #endif // UNICAST_DISABLED
5312 zeroID;
5313
5314 debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5315
5316 if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated
5317 return(mStatus_NoCache);
5318 else
5319 {
5320 int i;
5321 DNSQuestion **q;
5322
5323 if (!ValidateDomainName(&question->qname))
5324 {
5325 LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5326 return(mStatus_Invalid);
5327 }
5328
5329 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
5330 q = &m->Questions;
5331 if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
5332 while (*q && *q != question) q=&(*q)->next;
5333
5334 if (*q)
5335 {
5336 LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
5337 question->qname.c, DNSTypeName(question->qtype));
5338 return(mStatus_AlreadyRegistered);
5339 }
5340
5341 *q = question;
5342
5343 // If this question is referencing a specific interface, verify it exists
5344 if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
5345 {
5346 NetworkInterfaceInfo *intf;
5347 for (intf = m->HostInterfaces; intf; intf = intf->next)
5348 if (intf->InterfaceID == question->InterfaceID) break;
5349 if (!intf)
5350 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
5351 question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
5352 }
5353
5354 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
5355 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
5356 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
5357 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
5358 // that to go out immediately.
5359 question->next = mDNSNULL;
5360 question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion()
5361 question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
5362 question->LastQTime = m->timenow;
5363 question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
5364 question->ExpectUnicastResp = 0;
5365 question->LastAnswerPktNum = m->PktNum;
5366 question->RecentAnswerPkts = 0;
5367 question->CurrentAnswers = 0;
5368 question->LargeAnswers = 0;
5369 question->UniqueAnswers = 0;
5370 question->FlappingInterface1 = mDNSNULL;
5371 question->FlappingInterface2 = mDNSNULL;
5372 question->AuthInfo = GetAuthInfoForQuestion(m, question); // Must do this before calling FindDuplicateQuestion()
5373 question->DuplicateOf = FindDuplicateQuestion(m, question);
5374 question->NextInDQList = mDNSNULL;
5375 question->SendQNow = mDNSNULL;
5376 question->SendOnAll = mDNSfalse;
5377 question->RequestUnicast = 0;
5378 question->LastQTxTime = m->timenow;
5379 question->CNAMEReferrals = 0;
5380
5381 question->qDNSServer = mDNSNULL;
5382 question->nta = mDNSNULL;
5383 question->servAddr = zeroAddr;
5384 question->servPort = zeroIPPort;
5385 question->tcp = mDNSNULL;
5386 question->NoAnswer = NoAnswer_Normal;
5387
5388 question->state = LLQ_InitialRequest;
5389 question->ReqLease = 0;
5390 question->expire = 0;
5391 question->ntries = 0;
5392 question->id = zeroOpaque64;
5393
5394 if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
5395
5396 for (i=0; i<DupSuppressInfoSize; i++)
5397 question->DupSuppress[i].InterfaceID = mDNSNULL;
5398
5399 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
5400 question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
5401 question->LastQTime + question->ThisQInterval - m->timenow,
5402 question->DelayAnswering ? question->DelayAnswering - m->timenow : 0,
5403 question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf);
5404
5405 if (question->InterfaceID == mDNSInterface_LocalOnly)
5406 {
5407 if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
5408 }
5409 else
5410 {
5411 if (!m->NewQuestions) m->NewQuestions = question;
5412
5413 // If the question's id is non-zero, then it's Wide Area
5414 // MUST NOT do this Wide Area setup until near the end of
5415 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
5416 // NS, etc.) and if we haven't finished setting up our own question and setting
5417 // m->NewQuestions if necessary then we could end up recursively re-entering
5418 // this routine with the question list data structures in an inconsistent state.
5419 if (!mDNSOpaque16IsZero(question->TargetQID))
5420 {
5421 question->qDNSServer = GetServerForName(m, &question->qname);
5422 ActivateUnicastQuery(m, question, mDNSfalse);
5423
5424 // If long-lived query, and we don't have our NAT mapping active, start it now
5425 if (question->LongLived && !m->LLQNAT.clientContext)
5426 {
5427 m->LLQNAT.Protocol = NATOp_MapUDP;
5428 m->LLQNAT.IntPort = m->UnicastPort4;
5429 m->LLQNAT.RequestedPort = m->UnicastPort4;
5430 m->LLQNAT.clientCallback = LLQNATCallback;
5431 m->LLQNAT.clientContext = (void*)1; // Means LLQ NAT Traversal is active
5432 mDNS_StartNATOperation_internal(m, &m->LLQNAT);
5433 }
5434
5435 #if APPLE_OSX_mDNSResponder
5436 if (question->LongLived)
5437 UpdateAutoTunnelDomainStatuses(m);
5438 #endif
5439
5440 }
5441 SetNextQueryTime(m,question);
5442 }
5443
5444 return(mStatus_NoError);
5445 }
5446 }
5447
5448 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
5449 mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
5450 {
5451 LogOperation("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
5452 mDNS_StopQuery_internal(m, &nta->question);
5453 mDNSPlatformMemFree(nta);
5454 }
5455
5456 mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
5457 {
5458 const mDNSu32 slot = HashSlot(&question->qname);
5459 CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
5460 CacheRecord *rr;
5461 DNSQuestion **qp = &m->Questions;
5462
5463 //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5464
5465 if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
5466 while (*qp && *qp != question) qp=&(*qp)->next;
5467 if (*qp) *qp = (*qp)->next;
5468 else
5469 {
5470 #if !ForceAlerts
5471 if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active
5472 #endif
5473 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
5474 question->qname.c, DNSTypeName(question->qtype));
5475 #if ForceAlerts
5476 *(long*)0 = 0;
5477 #endif
5478 return(mStatus_BadReferenceErr);
5479 }
5480
5481 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
5482 UpdateQuestionDuplicates(m, question);
5483 // But don't trash ThisQInterval until afterwards.
5484 question->ThisQInterval = -1;
5485
5486 // If there are any cache records referencing this as their active question, then see if there is any
5487 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
5488 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5489 {
5490 if (rr->CRActiveQuestion == question)
5491 {
5492 DNSQuestion *q;
5493 for (q = m->Questions; q; q=q->next) // Scan our list of questions
5494 if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
5495 break;
5496 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
5497 rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
5498 if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
5499 }
5500 }
5501
5502 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
5503 // bump its pointer forward one question.
5504 if (m->CurrentQuestion == question)
5505 {
5506 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
5507 question->qname.c, DNSTypeName(question->qtype));
5508 m->CurrentQuestion = question->next;
5509 }
5510
5511 if (m->NewQuestions == question)
5512 {
5513 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
5514 question->qname.c, DNSTypeName(question->qtype));
5515 m->NewQuestions = question->next;
5516 }
5517
5518 if (m->NewLocalOnlyQuestions == question) m->NewLocalOnlyQuestions = question->next;
5519
5520 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
5521 question->next = mDNSNULL;
5522
5523 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
5524
5525 // And finally, cancel any associated GetZoneData operation that's still running.
5526 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
5527 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
5528 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
5529 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
5530 if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
5531 if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
5532 if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
5533 {
5534 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
5535 DNSQuestion *q;
5536 for (q = m->Questions; q; q=q->next)
5537 if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) break;
5538 if (!q)
5539 {
5540 if (!m->LLQNAT.clientContext) // Should never happen, but just in case...
5541 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
5542 else
5543 {
5544 LogOperation("Stopping LLQNAT");
5545 mDNS_StopNATOperation_internal(m, &m->LLQNAT);
5546 m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running
5547 }
5548 }
5549
5550 // If necessary, tell server it can delete this LLQ state
5551 if (question->state == LLQ_Established)
5552 {
5553 question->ReqLease = 0;
5554 sendLLQRefresh(m, question);
5555 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
5556 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
5557 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
5558 // we let that run out its natural course and complete asynchronously.
5559 if (question->tcp)
5560 {
5561 question->tcp->question = mDNSNULL;
5562 question->tcp = mDNSNULL;
5563 }
5564 }
5565 #if APPLE_OSX_mDNSResponder
5566 UpdateAutoTunnelDomainStatuses(m);
5567 #endif
5568 }
5569
5570 return(mStatus_NoError);
5571 }
5572
5573 mDNSexport mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
5574 {
5575 mStatus status;
5576 mDNS_Lock(m);
5577 status = mDNS_StartQuery_internal(m, question);
5578 mDNS_Unlock(m);
5579 return(status);
5580 }
5581
5582 mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
5583 {
5584 mStatus status;
5585 mDNS_Lock(m);
5586 status = mDNS_StopQuery_internal(m, question);
5587 mDNS_Unlock(m);
5588 return(status);
5589 }
5590
5591 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
5592 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
5593 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
5594 // specifically to catch and report if the client callback does try to make API calls
5595 mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question)
5596 {
5597 mStatus status;
5598 DNSQuestion *qq;
5599 mDNS_Lock(m);
5600
5601 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
5602 for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break;
5603
5604 status = mDNS_StopQuery_internal(m, question);
5605 if (status == mStatus_NoError && !qq)
5606 {
5607 CacheRecord *rr;
5608 const mDNSu32 slot = HashSlot(&question->qname);
5609 CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
5610 LogOperation("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5611 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
5612 if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
5613 {
5614 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
5615 if (question->QuestionCallback)
5616 question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
5617 }
5618 }
5619 mDNS_Unlock(m);
5620 return(status);
5621 }
5622
5623 mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr)
5624 {
5625 mStatus status;
5626 mDNS_Lock(m);
5627 status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5628 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
5629 mDNS_Unlock(m);
5630 return(status);
5631 }
5632
5633 mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr)
5634 {
5635 mStatus status = mStatus_BadReferenceErr;
5636 CacheRecord *cr;
5637 mDNS_Lock(m);
5638 cr = FindIdenticalRecordInCache(m, rr);
5639 debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr));
5640 if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
5641 if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
5642 mDNS_Unlock(m);
5643 return(status);
5644 }
5645
5646 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
5647 const domainname *const srv, const domainname *const domain,
5648 const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context)
5649 {
5650 question->InterfaceID = InterfaceID;
5651 question->Target = zeroAddr;
5652 question->qtype = kDNSType_PTR;
5653 question->qclass = kDNSClass_IN;
5654 question->LongLived = mDNSfalse;
5655 question->ExpectUnique = mDNSfalse;
5656 question->ForceMCast = ForceMCast;
5657 question->ReturnIntermed = mDNSfalse;
5658 question->QuestionCallback = Callback;
5659 question->QuestionContext = Context;
5660 if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
5661
5662 #ifndef UNICAST_DISABLED
5663 if (Question_uDNS(question))
5664 {
5665 question->LongLived = mDNStrue;
5666 question->ThisQInterval = InitialQuestionInterval;
5667 question->LastQTime = m->timenow - question->ThisQInterval;
5668 }
5669 #endif // UNICAST_DISABLED
5670 return(mDNS_StartQuery(m, question));
5671 }
5672
5673 mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
5674 {
5675 NetworkInterfaceInfo *intf;
5676 for (intf = m->HostInterfaces; intf; intf = intf->next)
5677 if (intf->ip.type == mDNSAddrType_IPv6) return(mDNStrue);
5678 return(mDNSfalse);
5679 }
5680
5681 mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5682 {
5683 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
5684 mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
5685 if (!AddRecord) return;
5686 if (answer->rrtype != kDNSType_SRV) return;
5687
5688 query->info->port = answer->rdata->u.srv.port;
5689
5690 // If this is our first answer, then set the GotSRV flag and start the address query
5691 if (!query->GotSRV)
5692 {
5693 query->GotSRV = mDNStrue;
5694 query->qAv4.InterfaceID = answer->InterfaceID;
5695 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
5696 query->qAv6.InterfaceID = answer->InterfaceID;
5697 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
5698 mDNS_StartQuery(m, &query->qAv4);
5699 // Only do the AAAA query if this machine actually has IPv6 active
5700 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
5701 }
5702 // If this is not our first answer, only re-issue the address query if the target host name has changed
5703 else if ((query->qAv4.InterfaceID != query->qSRV.InterfaceID && query->qAv4.InterfaceID != answer->InterfaceID) ||
5704 !SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target))
5705 {
5706 mDNS_StopQuery(m, &query->qAv4);
5707 if (query->qAv6.ThisQInterval >= 0) mDNS_StopQuery(m, &query->qAv6);
5708 if (SameDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target) && !PortChanged)
5709 {
5710 // If we get here, it means:
5711 // 1. This is not our first SRV answer
5712 // 2. The interface ID is different, but the target host and port are the same
5713 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
5714 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
5715 query->qAv4.InterfaceID = query->qSRV.InterfaceID; // Will be mDNSInterface_Any, or a specific interface
5716 query->qAv6.InterfaceID = query->qSRV.InterfaceID;
5717 }
5718 else
5719 {
5720 query->qAv4.InterfaceID = answer->InterfaceID;
5721 AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
5722 query->qAv6.InterfaceID = answer->InterfaceID;
5723 AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
5724 }
5725 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
5726 mDNS_StartQuery(m, &query->qAv4);
5727 // Only do the AAAA query if this machine actually has IPv6 active
5728 if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
5729 }
5730 else if (query->ServiceInfoQueryCallback && query->GotADD && query->GotTXT && PortChanged)
5731 {
5732 if (++query->Answers >= 100)
5733 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
5734 query->Answers, query->qSRV.qname.c, answer->rdata->u.srv.target.c,
5735 mDNSVal16(answer->rdata->u.srv.port));
5736 query->ServiceInfoQueryCallback(m, query);
5737 }
5738 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5739 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5740 }
5741
5742 mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5743 {
5744 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
5745 if (!AddRecord) return;
5746 if (answer->rrtype != kDNSType_TXT) return;
5747 if (answer->rdlength > sizeof(query->info->TXTinfo)) return;
5748
5749 query->GotTXT = mDNStrue;
5750 query->info->TXTlen = answer->rdlength;
5751 query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero
5752 mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
5753
5754 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
5755
5756 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5757 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5758 if (query->ServiceInfoQueryCallback && query->GotADD)
5759 {
5760 if (++query->Answers >= 100)
5761 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
5762 query->Answers, query->qSRV.qname.c, answer->rdata->u.txt.c);
5763 query->ServiceInfoQueryCallback(m, query);
5764 }
5765 }
5766
5767 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
5768 {
5769 ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
5770 //LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
5771 if (!AddRecord) return;
5772
5773 if (answer->rrtype == kDNSType_A)
5774 {
5775 query->info->ip.type = mDNSAddrType_IPv4;
5776 query->info->ip.ip.v4 = answer->rdata->u.ipv4;
5777 }
5778 else if (answer->rrtype == kDNSType_AAAA)
5779 {
5780 query->info->ip.type = mDNSAddrType_IPv6;
5781 query->info->ip.ip.v6 = answer->rdata->u.ipv6;
5782 }
5783 else
5784 {
5785 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
5786 return;
5787 }
5788
5789 query->GotADD = mDNStrue;
5790 query->info->InterfaceID = answer->InterfaceID;
5791
5792 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query->info->ip.type, query->info->name.c, query->GotTXT);
5793
5794 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5795 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5796 if (query->ServiceInfoQueryCallback && query->GotTXT)
5797 {
5798 if (++query->Answers >= 100)
5799 debugf(answer->rrtype == kDNSType_A ?
5800 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
5801 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
5802 query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
5803 query->ServiceInfoQueryCallback(m, query);
5804 }
5805 }
5806
5807 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
5808 // If the query is not interface-specific, then InterfaceID may be zero
5809 // Each time the Callback is invoked, the remainder of the fields will have been filled in
5810 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
5811 mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
5812 ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context)
5813 {
5814 mStatus status;
5815 mDNS_Lock(m);
5816
5817 query->qSRV.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5818 query->qSRV.InterfaceID = info->InterfaceID;
5819 query->qSRV.Target = zeroAddr;
5820 AssignDomainName(&query->qSRV.qname, &info->name);
5821 query->qSRV.qtype = kDNSType_SRV;
5822 query->qSRV.qclass = kDNSClass_IN;
5823 query->qSRV.LongLived = mDNSfalse;
5824 query->qSRV.ExpectUnique = mDNStrue;
5825 query->qSRV.ForceMCast = mDNSfalse;
5826 query->qSRV.ReturnIntermed = mDNSfalse;
5827 query->qSRV.QuestionCallback = FoundServiceInfoSRV;
5828 query->qSRV.QuestionContext = query;
5829
5830 query->qTXT.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5831 query->qTXT.InterfaceID = info->InterfaceID;
5832 query->qTXT.Target = zeroAddr;
5833 AssignDomainName(&query->qTXT.qname, &info->name);
5834 query->qTXT.qtype = kDNSType_TXT;
5835 query->qTXT.qclass = kDNSClass_IN;
5836 query->qTXT.LongLived = mDNSfalse;
5837 query->qTXT.ExpectUnique = mDNStrue;
5838 query->qTXT.ForceMCast = mDNSfalse;
5839 query->qTXT.ReturnIntermed = mDNSfalse;
5840 query->qTXT.QuestionCallback = FoundServiceInfoTXT;
5841 query->qTXT.QuestionContext = query;
5842
5843 query->qAv4.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5844 query->qAv4.InterfaceID = info->InterfaceID;
5845 query->qAv4.Target = zeroAddr;
5846 query->qAv4.qname.c[0] = 0;
5847 query->qAv4.qtype = kDNSType_A;
5848 query->qAv4.qclass = kDNSClass_IN;
5849 query->qAv4.LongLived = mDNSfalse;
5850 query->qAv4.ExpectUnique = mDNStrue;
5851 query->qAv4.ForceMCast = mDNSfalse;
5852 query->qAv4.ReturnIntermed = mDNSfalse;
5853 query->qAv4.QuestionCallback = FoundServiceInfo;
5854 query->qAv4.QuestionContext = query;
5855
5856 query->qAv6.ThisQInterval = -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5857 query->qAv6.InterfaceID = info->InterfaceID;
5858 query->qAv6.Target = zeroAddr;
5859 query->qAv6.qname.c[0] = 0;
5860 query->qAv6.qtype = kDNSType_AAAA;
5861 query->qAv6.qclass = kDNSClass_IN;
5862 query->qAv6.LongLived = mDNSfalse;
5863 query->qAv6.ExpectUnique = mDNStrue;
5864 query->qAv6.ForceMCast = mDNSfalse;
5865 query->qAv6.ReturnIntermed = mDNSfalse;
5866 query->qAv6.QuestionCallback = FoundServiceInfo;
5867 query->qAv6.QuestionContext = query;
5868
5869 query->GotSRV = mDNSfalse;
5870 query->GotTXT = mDNSfalse;
5871 query->GotADD = mDNSfalse;
5872 query->Answers = 0;
5873
5874 query->info = info;
5875 query->ServiceInfoQueryCallback = Callback;
5876 query->ServiceInfoQueryContext = Context;
5877
5878 // info->name = Must already be set up by client
5879 // info->interface = Must already be set up by client
5880 info->ip = zeroAddr;
5881 info->port = zeroIPPort;
5882 info->TXTlen = 0;
5883
5884 // We use mDNS_StartQuery_internal here because we're already holding the lock
5885 status = mDNS_StartQuery_internal(m, &query->qSRV);
5886 if (status == mStatus_NoError) status = mDNS_StartQuery_internal(m, &query->qTXT);
5887 if (status != mStatus_NoError) mDNS_StopResolveService(m, query);
5888
5889 mDNS_Unlock(m);
5890 return(status);
5891 }
5892
5893 mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
5894 {
5895 mDNS_Lock(m);
5896 // We use mDNS_StopQuery_internal here because we're already holding the lock
5897 if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
5898 if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
5899 if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
5900 if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
5901 mDNS_Unlock(m);
5902 }
5903
5904 mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
5905 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
5906 {
5907 question->InterfaceID = InterfaceID;
5908 question->Target = zeroAddr;
5909 question->qtype = kDNSType_PTR;
5910 question->qclass = kDNSClass_IN;
5911 question->LongLived = mDNSfalse;
5912 question->ExpectUnique = mDNSfalse;
5913 question->ForceMCast = mDNSfalse;
5914 question->ReturnIntermed = mDNSfalse;
5915 question->QuestionCallback = Callback;
5916 question->QuestionContext = Context;
5917 if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
5918 if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
5919 if (!dom) dom = &localdomain;
5920 if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
5921 return(mDNS_StartQuery(m, question));
5922 }
5923
5924 // ***************************************************************************
5925 #if COMPILER_LIKES_PRAGMA_MARK
5926 #pragma mark -
5927 #pragma mark - Responder Functions
5928 #endif
5929
5930 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
5931 {
5932 mStatus status;
5933 mDNS_Lock(m);
5934 status = mDNS_Register_internal(m, rr);
5935 mDNS_Unlock(m);
5936 return(status);
5937 }
5938
5939 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
5940 const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
5941 {
5942 #ifndef UNICAST_DISABLED
5943 mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
5944 #else
5945 mDNSBool unicast = mDNSfalse;
5946 #endif
5947
5948 if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
5949 {
5950 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
5951 return(mStatus_Invalid);
5952 }
5953
5954 mDNS_Lock(m);
5955
5956 // If TTL is unspecified, leave TTL unchanged
5957 if (newttl == 0) newttl = rr->resrec.rroriginalttl;
5958
5959 // If we already have an update queued up which has not gone through yet,
5960 // give the client a chance to free that memory
5961 if (!unicast && rr->NewRData)
5962 {
5963 RData *n = rr->NewRData;
5964 rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
5965 if (rr->UpdateCallback)
5966 rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary
5967 }
5968
5969 rr->NewRData = newrdata;
5970 rr->newrdlength = newrdlength;
5971 rr->UpdateCallback = Callback;
5972
5973 if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
5974
5975 if (rr->resrec.rroriginalttl == newttl &&
5976 rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
5977 CompleteRDataUpdate(m, rr);
5978 else
5979 {
5980 domainlabel name;
5981 domainname type, domain;
5982 DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
5983 rr->AnnounceCount = InitialAnnounceCount;
5984 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
5985 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
5986 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
5987 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
5988 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
5989 if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
5990 InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
5991 while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
5992 if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
5993 if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval);
5994 if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
5995 if (rr->UpdateCredits <= 5)
5996 {
5997 mDNSu32 delay = 6 - rr->UpdateCredits; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
5998 if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
5999 rr->ThisAPInterval *= 4;
6000 rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
6001 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
6002 rr->resrec.name->c, delay, delay > 1 ? "s" : "");
6003 }
6004 rr->resrec.rroriginalttl = newttl;
6005 }
6006
6007 mDNS_Unlock(m);
6008 return(mStatus_NoError);
6009 }
6010
6011 // NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
6012 // the record list and/or question list.
6013 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6014 mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
6015 {
6016 mStatus status;
6017 mDNS_Lock(m);
6018 status = mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
6019 mDNS_Unlock(m);
6020 return(status);
6021 }
6022
6023 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
6024 mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
6025
6026 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
6027 {
6028 NetworkInterfaceInfo *intf;
6029 for (intf = m->HostInterfaces; intf; intf = intf->next)
6030 if (intf->Advertise) break;
6031 return(intf);
6032 }
6033
6034 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6035 {
6036 char buffer[MAX_REVERSE_MAPPING_NAME];
6037 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6038 if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
6039
6040 // Send dynamic update for non-linklocal IPv4 Addresses
6041 mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, mDNS_HostNameCallback, set);
6042 mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
6043 mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
6044
6045 #if ANSWER_REMOTE_HOSTNAME_QUERIES
6046 set->RR_A .AllowRemoteQuery = mDNStrue;
6047 set->RR_PTR .AllowRemoteQuery = mDNStrue;
6048 set->RR_HINFO.AllowRemoteQuery = mDNStrue;
6049 #endif
6050 // 1. Set up Address record to map from host name ("foo.local.") to IP address
6051 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
6052 AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
6053 if (set->ip.type == mDNSAddrType_IPv4)
6054 {
6055 set->RR_A.resrec.rrtype = kDNSType_A;
6056 set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
6057 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6058 mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
6059 set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
6060 }
6061 else if (set->ip.type == mDNSAddrType_IPv6)
6062 {
6063 int i;
6064 set->RR_A.resrec.rrtype = kDNSType_AAAA;
6065 set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
6066 for (i = 0; i < 16; i++)
6067 {
6068 static const char hexValues[] = "0123456789ABCDEF";
6069 buffer[i * 4 ] = hexValues[set->ip.ip.v6.b[15 - i] & 0x0F];
6070 buffer[i * 4 + 1] = '.';
6071 buffer[i * 4 + 2] = hexValues[set->ip.ip.v6.b[15 - i] >> 4];
6072 buffer[i * 4 + 3] = '.';
6073 }
6074 mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
6075 }
6076
6077 MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
6078 set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
6079 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
6080
6081 set->RR_A.RRSet = &primary->RR_A; // May refer to self
6082
6083 mDNS_Register_internal(m, &set->RR_A);
6084 mDNS_Register_internal(m, &set->RR_PTR);
6085
6086 if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
6087 {
6088 mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
6089 AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
6090 set->RR_HINFO.DependentOn = &set->RR_A;
6091 mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
6092 p += 1 + (int)p[0];
6093 mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
6094 mDNS_Register_internal(m, &set->RR_HINFO);
6095 }
6096 else
6097 {
6098 debugf("Not creating HINFO record: platform support layer provided no information");
6099 set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
6100 }
6101 }
6102
6103 mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
6104 {
6105 NetworkInterfaceInfo *intf;
6106
6107 // If we still have address records referring to this one, update them
6108 NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
6109 AuthRecord *A = primary ? &primary->RR_A : mDNSNULL;
6110 for (intf = m->HostInterfaces; intf; intf = intf->next)
6111 if (intf->RR_A.RRSet == &set->RR_A)
6112 intf->RR_A.RRSet = A;
6113
6114 // Unregister these records.
6115 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
6116 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
6117 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
6118 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
6119 if (set->RR_A. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
6120 if (set->RR_PTR. resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
6121 if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
6122 }
6123
6124 mDNSexport void mDNS_SetFQDN(mDNS *const m)
6125 {
6126 domainname newmname;
6127 NetworkInterfaceInfo *intf;
6128 AuthRecord *rr;
6129 newmname.c[0] = 0;
6130
6131 if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6132 if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6133 if (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
6134
6135 mDNS_Lock(m);
6136
6137 AssignDomainName(&m->MulticastHostname, &newmname);
6138 // 1. Stop advertising our address records on all interfaces
6139 for (intf = m->HostInterfaces; intf; intf = intf->next)
6140 if (intf->Advertise) DeadvertiseInterface(m, intf);
6141
6142 // 2. Start advertising our address records using the new name
6143 for (intf = m->HostInterfaces; intf; intf = intf->next)
6144 if (intf->Advertise) AdvertiseInterface(m, intf);
6145
6146 // 3. Make sure that any SRV records (and the like) that reference our
6147 // host name in their rdata get updated to reference this new host name
6148 for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
6149 for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
6150
6151 mDNS_Unlock(m);
6152 }
6153
6154 mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6155 {
6156 (void)rr; // Unused parameter
6157
6158 #if MDNS_DEBUGMSGS
6159 {
6160 char *msg = "Unknown result";
6161 if (result == mStatus_NoError) msg = "Name registered";
6162 else if (result == mStatus_NameConflict) msg = "Name conflict";
6163 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6164 }
6165 #endif
6166
6167 if (result == mStatus_NoError)
6168 {
6169 // Notify the client that the host name is successfully registered
6170 if (m->MainCallback)
6171 m->MainCallback(m, mStatus_NoError);
6172 }
6173 else if (result == mStatus_NameConflict)
6174 {
6175 domainlabel oldlabel = m->hostlabel;
6176
6177 // 1. First give the client callback a chance to pick a new name
6178 if (m->MainCallback)
6179 m->MainCallback(m, mStatus_NameConflict);
6180
6181 // 2. If the client callback didn't do it, add (or increment) an index ourselves
6182 // This needs to be case-insensitive compare, because we need to know that the name has been changed so as to
6183 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
6184 if (SameDomainLabelCS(m->hostlabel.c, oldlabel.c))
6185 IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
6186
6187 // 3. Generate the FQDNs from the hostlabel,
6188 // and make sure all SRV records, etc., are updated to reference our new hostname
6189 mDNS_SetFQDN(m);
6190 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel.c, m->hostlabel.c);
6191 }
6192 else if (result == mStatus_MemFree)
6193 {
6194 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
6195 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
6196 debugf("mDNS_HostNameCallback: MemFree (ignored)");
6197 }
6198 else
6199 LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result, rr->resrec.name->c);
6200 }
6201
6202 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
6203 {
6204 NetworkInterfaceInfo *intf;
6205 active->IPv4Available = mDNSfalse;
6206 active->IPv6Available = mDNSfalse;
6207 for (intf = m->HostInterfaces; intf; intf = intf->next)
6208 if (intf->InterfaceID == active->InterfaceID)
6209 {
6210 if (intf->ip.type == mDNSAddrType_IPv4 && intf->McastTxRx) active->IPv4Available = mDNStrue;
6211 if (intf->ip.type == mDNSAddrType_IPv6 && intf->McastTxRx) active->IPv6Available = mDNStrue;
6212 }
6213 }
6214
6215 mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6216 {
6217 AuthRecord *rr;
6218 ServiceRecordSet *s;
6219 mDNSBool FirstOfType = mDNStrue;
6220 NetworkInterfaceInfo **p = &m->HostInterfaces;
6221
6222 if (!set->InterfaceID)
6223 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
6224
6225 if (!mDNSAddressIsValidNonZero(&set->mask))
6226 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
6227
6228 mDNS_Lock(m);
6229
6230 // Assume this interface will be active now, unless we find a duplicate already in the list
6231 set->InterfaceActive = mDNStrue;
6232 set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
6233 set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
6234
6235 // Scan list to see if this InterfaceID is already represented
6236 while (*p)
6237 {
6238 if (*p == set)
6239 {
6240 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
6241 mDNS_Unlock(m);
6242 return(mStatus_AlreadyRegistered);
6243 }
6244
6245 if ((*p)->InterfaceID == set->InterfaceID)
6246 {
6247 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
6248 set->InterfaceActive = mDNSfalse;
6249 if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
6250 if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
6251 if (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx) (*p)->IPv6Available = mDNStrue;
6252 }
6253
6254 p=&(*p)->next;
6255 }
6256
6257 set->next = mDNSNULL;
6258 *p = set;
6259
6260 if (set->Advertise)
6261 AdvertiseInterface(m, set);
6262
6263 LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
6264 set->InterfaceActive ?
6265 "not represented in list; marking active and retriggering queries" :
6266 "already represented in list; marking inactive for now");
6267
6268 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6269 // giving the false impression that there's an active representative of this interface when there really isn't.
6270 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
6271 // even if we believe that we previously had an active representative of this interface.
6272 if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
6273 {
6274 DNSQuestion *q;
6275 // If flapping, delay between first and second queries is eight seconds instead of one
6276 mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0;
6277 mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
6278
6279 // Use a small amount of randomness:
6280 // In the case of a network administrator turning on an Ethernet hub so that all the
6281 // connected machines establish link at exactly the same time, we don't want them all
6282 // to go and hit the network with identical queries at exactly the same moment.
6283 if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
6284
6285 if (flapping)
6286 {
6287 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
6288 if (!m->SuppressProbes ||
6289 m->SuppressProbes - (m->timenow + delay) < 0)
6290 m->SuppressProbes = (m->timenow + delay);
6291 }
6292
6293 for (q = m->Questions; q; q=q->next) // Scan our list of questions
6294 if (mDNSOpaque16IsZero(q->TargetQID))
6295 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
6296 { // then reactivate this question
6297 mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
6298 mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
6299 mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0;
6300 if (dodelay) LogOperation("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
6301
6302 if (!q->ThisQInterval || q->ThisQInterval > initial)
6303 {
6304 q->ThisQInterval = initial;
6305 q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
6306 }
6307 q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
6308 q->RecentAnswerPkts = 0;
6309 SetNextQueryTime(m,q);
6310 }
6311
6312 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
6313 // we now need them to re-probe if necessary, and then re-announce.
6314 for (rr = m->ResourceRecords; rr; rr=rr->next)
6315 if (!AuthRecord_uDNS(rr))
6316 if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
6317 {
6318 if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
6319 rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
6320 if (rr->AnnounceCount < announce) rr->AnnounceCount = announce;
6321 InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType));
6322 }
6323 }
6324
6325 for (rr = m->ResourceRecords; rr; rr=rr->next)
6326 if (AuthRecord_uDNS(rr))
6327 {
6328 LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", rr->resrec.name->c);
6329 if (rr->nta) CancelGetZoneData(m, rr->nta);
6330 rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
6331 }
6332
6333 for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
6334 {
6335 LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
6336 if (s->nta) CancelGetZoneData(m, s->nta);
6337 s->nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
6338 }
6339
6340 mDNS_Unlock(m);
6341 return(mStatus_NoError);
6342 }
6343
6344 // NOTE: mDNS_DeregisterInterface 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.
6347 mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
6348 {
6349 NetworkInterfaceInfo **p = &m->HostInterfaces;
6350
6351 mDNSBool revalidate = mDNSfalse;
6352 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
6353 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
6354 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
6355 if (m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) revalidate = mDNStrue;
6356
6357 mDNS_Lock(m);
6358
6359 // Find this record in our list
6360 while (*p && *p != set) p=&(*p)->next;
6361 if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
6362
6363 // Unlink this record from our list
6364 *p = (*p)->next;
6365 set->next = mDNSNULL;
6366
6367 if (!set->InterfaceActive)
6368 {
6369 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
6370 NetworkInterfaceInfo *intf;
6371 for (intf = m->HostInterfaces; intf; intf = intf->next)
6372 if (intf->InterfaceActive && intf->InterfaceID == set->InterfaceID)
6373 UpdateInterfaceProtocols(m, intf);
6374 }
6375 else
6376 {
6377 NetworkInterfaceInfo *intf;
6378 for (intf = m->HostInterfaces; intf; intf = intf->next)
6379 if (intf->InterfaceID == set->InterfaceID)
6380 break;
6381 if (intf)
6382 {
6383 LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
6384 " making it active", set->InterfaceID, set->ifname, &set->ip);
6385 intf->InterfaceActive = mDNStrue;
6386 UpdateInterfaceProtocols(m, intf);
6387
6388 // See if another representative *of the same type* exists. If not, we mave have gone from
6389 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
6390 for (intf = m->HostInterfaces; intf; intf = intf->next)
6391 if (intf->InterfaceID == set->InterfaceID && intf->ip.type == set->ip.type)
6392 break;
6393 if (!intf) revalidate = mDNStrue;
6394 }
6395 else
6396 {
6397 mDNSu32 slot;
6398 CacheGroup *cg;
6399 CacheRecord *rr;
6400 DNSQuestion *q;
6401 DNSServer *s;
6402
6403 LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
6404 " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
6405
6406 if (flapping)
6407 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
6408 set->ifname, &set->ip);
6409
6410 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
6411 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
6412 for (q = m->Questions; q; q=q->next)
6413 {
6414 if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
6415 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
6416 {
6417 q->FlappingInterface2 = q->FlappingInterface1;
6418 q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away
6419 }
6420 }
6421
6422 // 2. Flush any cache records received on this interface
6423 revalidate = mDNSfalse; // Don't revalidate if we're flushing the records
6424 FORALL_CACHERECORDS(slot, cg, rr)
6425 if (rr->resrec.InterfaceID == set->InterfaceID)
6426 {
6427 // If this interface is deemed flapping,
6428 // postpone deleting the cache records in case the interface comes back again
6429 if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
6430 else
6431 {
6432 // We want these record to go away in 30 seconds
6433 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
6434 // if the interface does come back, any relevant questions will be reactivated anyway
6435 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6436 rr->UnansweredQueries = MaxUnansweredQueries;
6437 }
6438 }
6439
6440 // 3. Any DNS servers specific to this interface are now unusable
6441 for (s = m->DNSServers; s; s = s->next)
6442 if (s->interface == set->InterfaceID)
6443 {
6444 s->interface = mDNSInterface_Any;
6445 s->teststate = DNSServer_Disabled;
6446 }
6447 }
6448 }
6449
6450 // If we were advertising on this interface, deregister those address and reverse-lookup records now
6451 if (set->Advertise) DeadvertiseInterface(m, set);
6452
6453 // If we have any cache records received on this interface that went away, then re-verify them.
6454 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6455 // giving the false impression that there's an active representative of this interface when there really isn't.
6456 // Don't need to do this when shutting down, because *all* interfaces are about to go away
6457 if (revalidate && !m->ShutdownTime)
6458 {
6459 mDNSu32 slot;
6460 CacheGroup *cg;
6461 CacheRecord *rr;
6462 m->NextCacheCheck = m->timenow;
6463 FORALL_CACHERECORDS(slot, cg, rr)
6464 if (rr->resrec.InterfaceID == set->InterfaceID)
6465 mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
6466 }
6467
6468 mDNS_Unlock(m);
6469 }
6470
6471 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6472 {
6473 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6474 (void)m; // Unused parameter
6475
6476 #if MDNS_DEBUGMSGS
6477 {
6478 char *msg = "Unknown result";
6479 if (result == mStatus_NoError) msg = "Name Registered";
6480 else if (result == mStatus_NameConflict) msg = "Name Conflict";
6481 else if (result == mStatus_MemFree) msg = "Memory Free";
6482 debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
6483 }
6484 #endif
6485
6486 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
6487 if (result == mStatus_NoError && rr != &sr->RR_SRV) return;
6488
6489 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
6490 if (result == mStatus_NameConflict)
6491 {
6492 sr->Conflict = mDNStrue; // Record that this service set had a conflict
6493 mDNS_DeregisterService(m, sr); // Unlink the records from our list
6494 return;
6495 }
6496
6497 if (result == mStatus_MemFree)
6498 {
6499 // If the PTR record or any of the subtype PTR records are still in the process of deregistering,
6500 // don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
6501 mDNSu32 i;
6502 if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
6503 for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
6504
6505 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
6506 // then we can now report the NameConflict to the client
6507 if (sr->Conflict) result = mStatus_NameConflict;
6508 }
6509
6510 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
6511 // function is allowed to do anything, including deregistering this service and freeing its memory.
6512 if (sr->ServiceCallback)
6513 sr->ServiceCallback(m, sr, result);
6514 }
6515
6516 mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
6517 {
6518 ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
6519 if (sr->ServiceCallback)
6520 sr->ServiceCallback(m, sr, result);
6521 }
6522
6523 mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
6524 {
6525 mDNSu32 i;
6526 ServiceRecordSet **p = &m->ServiceRegistrations;
6527 while (*p && *p != srs) p=&(*p)->uDNS_next;
6528 if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
6529
6530 srs->uDNS_next = mDNSNULL;
6531 *p = srs;
6532
6533 srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
6534 srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
6535 srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
6536 for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
6537
6538 srs->srs_uselease = mDNStrue;
6539
6540 if (srs->RR_SRV.AutoTarget)
6541 {
6542 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
6543 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
6544 // with the port number in our advertised SRV record automatically tracking the external mapped port.
6545 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
6546 if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
6547 }
6548
6549 if (!GetServiceTarget(m, srs))
6550 {
6551 // defer registration until we've got a target
6552 LogOperation("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
6553 srs->state = regState_NoTarget;
6554 srs->nta = mDNSNULL;
6555 return mStatus_NoError;
6556 }
6557
6558 ActivateUnicastRegistration(m, &srs->RR_SRV);
6559 srs->state = regState_FetchingZoneData;
6560 srs->nta = mDNSNULL;
6561 return mStatus_NoError;
6562 }
6563
6564 // Note:
6565 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
6566 // Type is service type (e.g. "_ipp._tcp.")
6567 // Domain is fully qualified domain name (i.e. ending with a null label)
6568 // We always register a TXT, even if it is empty (so that clients are not
6569 // left waiting forever looking for a nonexistent record.)
6570 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
6571 // then the default host name (m->MulticastHostname) is automatically used
6572 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
6573 mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
6574 const domainlabel *const name, const domainname *const type, const domainname *const domain,
6575 const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
6576 AuthRecord *SubTypes, mDNSu32 NumSubTypes,
6577 const mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context)
6578 {
6579 mStatus err;
6580 mDNSu32 i;
6581
6582 sr->state = regState_Zero;
6583 sr->srs_uselease = 0;
6584 sr->TestForSelfConflict = 0;
6585 sr->Private = 0;
6586 sr->id = zeroID;
6587 sr->zone.c[0] = 0;
6588 sr->SRSUpdateServer = zeroAddr;
6589 sr->SRSUpdatePort = zeroIPPort;
6590 mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
6591 sr->ClientCallbackDeferred = 0;
6592 sr->DeferredStatus = 0;
6593 sr->SRVUpdateDeferred = 0;
6594 sr->SRVChanged = 0;
6595 sr->tcp = mDNSNULL;
6596
6597 sr->ServiceCallback = Callback;
6598 sr->ServiceContext = Context;
6599 sr->Conflict = mDNSfalse;
6600
6601 sr->Extras = mDNSNULL;
6602 sr->NumSubTypes = NumSubTypes;
6603 sr->SubTypes = SubTypes;
6604
6605 // Initialize the AuthRecord objects to sane values
6606 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
6607 mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
6608 mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6609 mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
6610 mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
6611
6612 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
6613 if (mDNSIPPortIsZero(port))
6614 return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
6615
6616 // If the client is registering an oversized TXT record,
6617 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
6618 if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
6619 sr->RR_TXT.resrec.rdata->MaxRDLength = txtlen;
6620
6621 // Set up the record names
6622 // For now we only create an advisory record for the main type, not for subtypes
6623 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
6624 if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
6625 return(mStatus_BadParamErr);
6626 if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6627 if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6628 AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name);
6629
6630 // 1. Set up the ADV record rdata to advertise our service type
6631 AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
6632
6633 // 2. Set up the PTR record rdata to point to our service name
6634 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
6635 AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
6636 sr->RR_PTR.Additional1 = &sr->RR_SRV;
6637 sr->RR_PTR.Additional2 = &sr->RR_TXT;
6638
6639 // 2a. Set up any subtype PTRs to point to our service name
6640 // If the client is using subtypes, it is the client's responsibility to have
6641 // already set the first label of the record name to the subtype being registered
6642 for (i=0; i<NumSubTypes; i++)
6643 {
6644 domainname st;
6645 AssignDomainName(&st, sr->SubTypes[i].resrec.name);
6646 st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
6647 AppendDomainName(&st, type);
6648 mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
6649 if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
6650 AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage);
6651 sr->SubTypes[i].Additional1 = &sr->RR_SRV;
6652 sr->SubTypes[i].Additional2 = &sr->RR_TXT;
6653 }
6654
6655 // 3. Set up the SRV record rdata.
6656 sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
6657 sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
6658 sr->RR_SRV.resrec.rdata->u.srv.port = port;
6659
6660 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
6661 if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host);
6662 else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
6663
6664 // 4. Set up the TXT record rdata,
6665 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
6666 if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
6667 else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
6668 {
6669 sr->RR_TXT.resrec.rdlength = txtlen;
6670 if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
6671 mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen);
6672 }
6673 sr->RR_TXT.DependentOn = &sr->RR_SRV;
6674
6675 #ifndef UNICAST_DISABLED
6676 // If the client has specified an explicit InterfaceID,
6677 // then we do a multicast registration on that interface, even for unicast domains.
6678 if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
6679 {
6680 mStatus status;
6681 mDNS_Lock(m);
6682 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6683 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6684 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6685 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
6686 if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
6687
6688 status = uDNS_RegisterService(m, sr);
6689 mDNS_Unlock(m);
6690 return(status);
6691 }
6692 #endif
6693 mDNS_Lock(m);
6694 err = mDNS_Register_internal(m, &sr->RR_SRV);
6695 if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
6696 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
6697 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
6698 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
6699 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
6700 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
6701 if (!err) err = mDNS_Register_internal(m, &sr->RR_ADV);
6702 for (i=0; i<NumSubTypes; i++) if (!err) err = mDNS_Register_internal(m, &sr->SubTypes[i]);
6703 if (!err) err = mDNS_Register_internal(m, &sr->RR_PTR);
6704
6705 mDNS_Unlock(m);
6706
6707 if (err) mDNS_DeregisterService(m, sr);
6708 return(err);
6709 }
6710
6711 mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
6712 {
6713 (void)m; // Unused
6714 (void)rr; // Unused
6715 (void)result; // Unused
6716 LogOperation("DummyCallback %d %s", result, ARDisplayString(m, rr));
6717 }
6718
6719 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
6720 ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
6721 {
6722 ExtraResourceRecord **e;
6723 mStatus status;
6724
6725 extra->next = mDNSNULL;
6726 mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
6727 extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
6728 AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
6729
6730 mDNS_Lock(m);
6731 e = &sr->Extras;
6732 while (*e) e = &(*e)->next;
6733
6734 if (ttl == 0) ttl = kStandardTTL;
6735
6736 extra->r.DependentOn = &sr->RR_SRV;
6737
6738 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
6739 extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
6740
6741 status = mDNS_Register_internal(m, &extra->r);
6742 if (status == mStatus_NoError)
6743 {
6744 *e = extra;
6745 #ifndef UNICAST_DISABLED
6746 if (AuthRecord_uDNS(&sr->RR_SRV))
6747 {
6748 extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???)
6749 extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
6750 if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
6751 }
6752 #endif
6753 }
6754
6755 mDNS_Unlock(m);
6756 return(status);
6757 }
6758
6759 mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
6760 mDNSRecordCallback MemFreeCallback, void *Context)
6761 {
6762 ExtraResourceRecord **e;
6763 mStatus status;
6764
6765 mDNS_Lock(m);
6766 e = &sr->Extras;
6767 while (*e && *e != extra) e = &(*e)->next;
6768 if (!*e)
6769 {
6770 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
6771 status = mStatus_BadReferenceErr;
6772 }
6773 else
6774 {
6775 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
6776 extra->r.RecordCallback = MemFreeCallback;
6777 extra->r.RecordContext = Context;
6778 *e = (*e)->next;
6779 status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
6780 }
6781 mDNS_Unlock(m);
6782 return(status);
6783 }
6784
6785 mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
6786 {
6787 // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
6788 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
6789 domainlabel name1, name2;
6790 domainname type, domain;
6791 const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target;
6792 ExtraResourceRecord *extras = sr->Extras;
6793 mStatus err;
6794
6795 DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
6796 if (!newname)
6797 {
6798 name2 = name1;
6799 IncrementLabelSuffix(&name2, mDNStrue);
6800 newname = &name2;
6801 }
6802
6803 if (SameDomainName(&domain, &localdomain))
6804 LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
6805 else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
6806
6807 err = mDNS_RegisterService(m, sr, newname, &type, &domain,
6808 host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
6809 sr->SubTypes, sr->NumSubTypes,
6810 sr->RR_PTR.resrec.InterfaceID, sr->ServiceCallback, sr->ServiceContext);
6811
6812 // mDNS_RegisterService() just reset sr->Extras to NULL.
6813 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
6814 // through the old list of extra records, and re-add them to our freshly created service registration
6815 while (!err && extras)
6816 {
6817 ExtraResourceRecord *e = extras;
6818 extras = extras->next;
6819 err = mDNS_AddRecordToService(m, sr, e, e->r.resrec.rdata, e->r.resrec.rroriginalttl);
6820 }
6821
6822 return(err);
6823 }
6824
6825 // NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
6826 // which may change the record list and/or question list.
6827 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6828 mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
6829 {
6830 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
6831 if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
6832
6833 #ifndef UNICAST_DISABLED
6834 if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
6835 {
6836 mStatus status;
6837 mDNS_Lock(m);
6838 status = uDNS_DeregisterService(m, sr);
6839 mDNS_Unlock(m);
6840 return(status);
6841 }
6842 #endif
6843 if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
6844 {
6845 debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
6846 return(mStatus_BadReferenceErr);
6847 }
6848 else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
6849 {
6850 debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
6851 // Avoid race condition:
6852 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
6853 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
6854 // If the client happens to deregister the service in the middle of that process, then
6855 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
6856 // instead of incorrectly promoting it to mStatus_NameConflict.
6857 // This race condition is exposed particularly when the conformance test generates
6858 // a whole batch of simultaneous conflicts across a range of services all advertised
6859 // using the same system default name, and if we don't take this precaution then
6860 // we end up incrementing m->nicelabel multiple times instead of just once.
6861 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
6862 sr->Conflict = mDNSfalse;
6863 return(mStatus_NoError);
6864 }
6865 else
6866 {
6867 mDNSu32 i;
6868 mStatus status;
6869 ExtraResourceRecord *e;
6870 mDNS_Lock(m);
6871 e = sr->Extras;
6872
6873 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
6874 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
6875 mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
6876 mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
6877
6878 mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
6879
6880 // We deregister all of the extra records, but we leave the sr->Extras list intact
6881 // in case the client wants to do a RenameAndReregister and reinstate the registration
6882 while (e)
6883 {
6884 mDNS_Deregister_internal(m, &e->r, mDNS_Dereg_repeat);
6885 e = e->next;
6886 }
6887
6888 for (i=0; i<sr->NumSubTypes; i++)
6889 mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
6890
6891 // Be sure to deregister the PTR last!
6892 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
6893 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
6894 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
6895 // we've deregistered all our records and done any other necessary cleanup before that happens.
6896 status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
6897 mDNS_Unlock(m);
6898 return(status);
6899 }
6900 }
6901
6902 // Create a registration that asserts that no such service exists with this name.
6903 // This can be useful where there is a given function is available through several protocols.
6904 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
6905 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
6906 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
6907 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
6908 mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
6909 const domainlabel *const name, const domainname *const type, const domainname *const domain,
6910 const domainname *const host,
6911 const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
6912 {
6913 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
6914 if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
6915 rr->resrec.rdata->u.srv.priority = 0;
6916 rr->resrec.rdata->u.srv.weight = 0;
6917 rr->resrec.rdata->u.srv.port = zeroIPPort;
6918 if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
6919 else rr->AutoTarget = Target_AutoHost;
6920 return(mDNS_Register(m, rr));
6921 }
6922
6923 mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
6924 mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
6925 {
6926 mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
6927 if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
6928 if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr);
6929 return(mDNS_Register(m, rr));
6930 }
6931
6932 mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
6933 {
6934 static mDNSBool randomized = mDNSfalse;
6935
6936 if (!randomized) { m->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
6937 if (m->NextMessageID == 0) m->NextMessageID++;
6938 return mDNSOpaque16fromIntVal(m->NextMessageID++);
6939 }
6940
6941 // ***************************************************************************
6942 #if COMPILER_LIKES_PRAGMA_MARK
6943 #pragma mark -
6944 #pragma mark - Startup and Shutdown
6945 #endif
6946
6947 mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
6948 {
6949 if (storage && numrecords)
6950 {
6951 mDNSu32 i;
6952 debugf("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
6953 for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
6954 storage[numrecords-1].next = m->rrcache_free;
6955 m->rrcache_free = storage;
6956 m->rrcache_size += numrecords;
6957 }
6958 }
6959
6960 mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
6961 {
6962 mDNS_Lock(m);
6963 mDNS_GrowCache_internal(m, storage, numrecords);
6964 mDNS_Unlock(m);
6965 }
6966
6967 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
6968 CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
6969 mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
6970 {
6971 mDNSu32 slot;
6972 mDNSs32 timenow;
6973 mStatus result;
6974
6975 if (!rrcachestorage) rrcachesize = 0;
6976
6977 m->p = p;
6978 m->KnownBugs = 0;
6979 m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
6980 m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
6981 m->mDNSPlatformStatus = mStatus_Waiting;
6982 m->UnicastPort4 = zeroIPPort;
6983 m->UnicastPort6 = zeroIPPort;
6984 m->MainCallback = Callback;
6985 m->MainContext = Context;
6986 m->rec.r.resrec.RecordType = 0;
6987
6988 // For debugging: To catch and report locking failures
6989 m->mDNS_busy = 0;
6990 m->mDNS_reentrancy = 0;
6991 m->ShutdownTime = 0;
6992 m->lock_rrcache = 0;
6993 m->lock_Questions = 0;
6994 m->lock_Records = 0;
6995
6996 // Task Scheduling variables
6997 result = mDNSPlatformTimeInit();
6998 if (result != mStatus_NoError) return(result);
6999 m->timenow_adjust = (mDNSs32)mDNSRandom(0xFFFFFFFF);
7000 timenow = mDNS_TimeNow_NoLock(m);
7001
7002 m->timenow = 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
7003 m->timenow_last = timenow;
7004 m->NextScheduledEvent = timenow;
7005 m->SuppressSending = timenow;
7006 m->NextCacheCheck = timenow + 0x78000000;
7007 m->NextScheduledQuery = timenow + 0x78000000;
7008 m->NextScheduledProbe = timenow + 0x78000000;
7009 m->NextScheduledResponse = timenow + 0x78000000;
7010 m->NextScheduledNATOp = timenow + 0x78000000;
7011 m->RandomQueryDelay = 0;
7012 m->RandomReconfirmDelay = 0;
7013 m->PktNum = 0;
7014 m->SendDeregistrations = mDNSfalse;
7015 m->SendImmediateAnswers = mDNSfalse;
7016 m->SleepState = mDNSfalse;
7017
7018 // These fields only required for mDNS Searcher...
7019 m->Questions = mDNSNULL;
7020 m->NewQuestions = mDNSNULL;
7021 m->CurrentQuestion = mDNSNULL;
7022 m->LocalOnlyQuestions = mDNSNULL;
7023 m->NewLocalOnlyQuestions = mDNSNULL;
7024 m->rrcache_size = 0;
7025 m->rrcache_totalused = 0;
7026 m->rrcache_active = 0;
7027 m->rrcache_report = 10;
7028 m->rrcache_free = mDNSNULL;
7029
7030 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
7031
7032 mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
7033
7034 // Fields below only required for mDNS Responder...
7035 m->hostlabel.c[0] = 0;
7036 m->nicelabel.c[0] = 0;
7037 m->MulticastHostname.c[0] = 0;
7038 m->HIHardware.c[0] = 0;
7039 m->HISoftware.c[0] = 0;
7040 m->ResourceRecords = mDNSNULL;
7041 m->DuplicateRecords = mDNSNULL;
7042 m->NewLocalRecords = mDNSNULL;
7043 m->CurrentRecord = mDNSNULL;
7044 m->HostInterfaces = mDNSNULL;
7045 m->ProbeFailTime = 0;
7046 m->NumFailedProbes = 0;
7047 m->SuppressProbes = 0;
7048
7049 #ifndef UNICAST_DISABLED
7050 m->NextuDNSEvent = timenow + 0x78000000;
7051 m->NextSRVUpdate = timenow + 0x78000000;
7052 m->SuppressStdPort53Queries = 0;
7053
7054 m->ServiceRegistrations = mDNSNULL;
7055 m->NextMessageID = 0;
7056 m->DNSServers = mDNSNULL;
7057
7058 m->Router = zeroAddr;
7059 m->AdvertisedV4 = zeroAddr;
7060 m->AdvertisedV6 = zeroAddr;
7061
7062 m->AuthInfoList = mDNSNULL;
7063
7064 m->ReverseMap.ThisQInterval = -1;
7065 m->StaticHostname.c[0] = 0;
7066 m->FQDN.c[0] = 0;
7067 m->Hostnames = mDNSNULL;
7068 m->AutoTunnelHostAddr.b[0] = 0;
7069 m->AutoTunnelHostAddrActive = mDNSfalse;
7070 m->AutoTunnelLabel.c[0] = 0;
7071
7072 m->RegisterSearchDomains = mDNSfalse;
7073
7074 // NAT traversal fields
7075 m->NATTraversals = mDNSNULL;
7076 m->CurrentNATTraversal = mDNSNULL;
7077 m->retryIntervalGetAddr = 0; // delta between time sent and retry
7078 m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry
7079 m->ExternalAddress = zerov4Addr;
7080
7081 m->NATMcastRecvskt = mDNSNULL;
7082 m->NATMcastRecvsk2 = mDNSNULL;
7083 m->LastNATupseconds = 0;
7084 m->LastNATReplyLocalTime = timenow;
7085
7086 m->UPnPInterfaceID = 0;
7087 m->SSDPSocket = mDNSNULL;
7088 m->UPnPRouterPort = zeroIPPort;
7089 m->UPnPSOAPPort = zeroIPPort;
7090 m->UPnPRouterURL = mDNSNULL;
7091 m->UPnPSOAPURL = mDNSNULL;
7092 m->UPnPRouterAddressString = mDNSNULL;
7093 m->UPnPSOAPAddressString = mDNSNULL;
7094 #endif
7095
7096 #if APPLE_OSX_mDNSResponder
7097 m->TunnelClients = mDNSNULL;
7098 #endif
7099
7100 result = mDNSPlatformInit(m);
7101
7102 #ifndef UNICAST_DISABLED
7103 // It's better to do this *after* the platform layer has set up the
7104 // interface list and security credentials
7105 uDNS_SetupDNSConfig(m); // Get initial DNS configuration
7106 #endif
7107
7108 return(result);
7109 }
7110
7111 mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
7112 {
7113 (void)m; // unused
7114 debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
7115 mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
7116 }
7117
7118 mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
7119 {
7120 mDNSu32 slot;
7121 CacheGroup *cg;
7122 CacheRecord *cr;
7123
7124 mDNSAddr v4, v6, r;
7125 domainname fqdn;
7126 DNSServer *ptr, **p = &m->DNSServers;
7127 const DNSServer *oldServers = m->DNSServers;
7128 DNSQuestion *q;
7129
7130 if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
7131
7132 mDNS_Lock(m);
7133
7134 // Let the platform layer get the current DNS information
7135 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
7136 // (no need to hit the network with domain enumeration queries until we actually need that information).
7137 for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->flags |= DNSServer_FlagDelete;
7138
7139 mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
7140
7141 // Update our qDNSServer pointers before we go and free the DNSServer object memory
7142 for (q = m->Questions; q; q=q->next)
7143 if (!mDNSOpaque16IsZero(q->TargetQID))
7144 {
7145 DNSServer *s = GetServerForName(m, &q->qname);
7146 DNSServer *t = q->qDNSServer;
7147 if (t != s)
7148 {
7149 // If DNS Server for this question has changed, reactivate it
7150 LogOperation("Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
7151 t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
7152 s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
7153 q->qname.c, DNSTypeName(q->qtype));
7154 q->qDNSServer = s;
7155 ActivateUnicastQuery(m, q, mDNStrue);
7156 }
7157 }
7158
7159 // Flush all records that match a new resolver
7160 FORALL_CACHERECORDS(slot, cg, cr)
7161 {
7162 ptr = GetServerForName(m, cr->resrec.name);
7163 if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID)
7164 {
7165 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
7166 mDNS_PurgeCacheResourceRecord(m, cr);
7167 else
7168 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7169 }
7170 }
7171
7172 while (*p)
7173 {
7174 if (((*p)->flags & DNSServer_FlagDelete) != 0)
7175 {
7176 // Scan our cache, looking for uDNS records that we would have queried this server for.
7177 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
7178 // different DNS servers can give different answers to the same question.
7179 ptr = *p;
7180 ptr->flags &= ~DNSServer_FlagDelete; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
7181 FORALL_CACHERECORDS(slot, cg, cr)
7182 if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
7183 mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
7184 *p = (*p)->next;
7185 mDNSPlatformMemFree(ptr);
7186 }
7187 else
7188 {
7189 (*p)->flags &= ~DNSServer_FlagNew;
7190 p = &(*p)->next;
7191 }
7192 }
7193
7194 // If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
7195 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
7196 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
7197 // Similarly, if we now have some DNS servers and we used to have none, we want to purge any fake negative results we may have generated.
7198 if ((m->DNSServers != mDNSNULL) != (oldServers != mDNSNULL))
7199 {
7200 int count = 0;
7201 FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; }
7202 LogOperation("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
7203 m->DNSServers ? "DNS server became" : "No DNS servers", count);
7204 }
7205
7206 // Did our FQDN change?
7207 if (!SameDomainName(&fqdn, &m->FQDN))
7208 {
7209 if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
7210
7211 AssignDomainName(&m->FQDN, &fqdn);
7212
7213 if (m->FQDN.c[0])
7214 {
7215 mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
7216 mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
7217 }
7218 }
7219
7220 mDNS_Unlock(m);
7221
7222 // handle router and primary interface changes
7223 v4 = v6 = r = zeroAddr;
7224 v4.type = r.type = mDNSAddrType_IPv4;
7225
7226 if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
7227 {
7228 mDNS_SetPrimaryInterfaceInfo(m,
7229 !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
7230 !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL,
7231 !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL);
7232 }
7233 else
7234 {
7235 mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL);
7236 if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
7237 }
7238
7239 return mStatus_NoError;
7240 }
7241
7242 mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
7243 {
7244 m->mDNSPlatformStatus = result;
7245 if (m->MainCallback)
7246 {
7247 mDNS_Lock(m);
7248 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
7249 m->MainCallback(m, mStatus_NoError);
7250 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
7251 mDNS_Unlock(m);
7252 }
7253 }
7254
7255 extern ServiceRecordSet *CurrentServiceRecordSet;
7256
7257 mDNSexport void mDNS_StartExit(mDNS *const m)
7258 {
7259 NetworkInterfaceInfo *intf;
7260 AuthRecord *rr;
7261
7262 mDNS_Lock(m);
7263
7264 m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
7265
7266 #ifndef UNICAST_DISABLED
7267 SuspendLLQs(m);
7268 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
7269 // because we deregister all records and services later in this routine
7270 while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
7271 #endif
7272
7273 for (intf = m->HostInterfaces; intf; intf = intf->next)
7274 if (intf->Advertise)
7275 DeadvertiseInterface(m, intf);
7276
7277 // Shut down all our active NAT Traversals
7278 while (m->NATTraversals)
7279 {
7280 NATTraversalInfo *t = m->NATTraversals;
7281 mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
7282
7283 // After stopping the NAT Traversal, we zero out the fields.
7284 // This has particularly important implications for our AutoTunnel records --
7285 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
7286 // handlers to just turn around and attempt to re-register those same records.
7287 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
7288 t->ExternalAddress = zerov4Addr;
7289 t->ExternalPort = zeroIPPort;
7290 t->Lifetime = 0;
7291 t->Result = mStatus_NoError;
7292 }
7293
7294 // Make sure there are nothing but deregistering records remaining in the list
7295 if (m->CurrentRecord)
7296 LogMsg("mDNS_StartExit ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
7297
7298 // First we deregister any non-shared records. In particular, we want to make sure we deregister
7299 // any extra records added to a Service Record Set first, before we deregister its PTR record,
7300 // because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record.
7301 m->CurrentRecord = m->ResourceRecords;
7302 while (m->CurrentRecord)
7303 {
7304 rr = m->CurrentRecord;
7305 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
7306 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7307 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
7308 // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
7309 // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
7310 if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now
7311 m->CurrentRecord = rr->next;
7312 }
7313
7314 // Now deregister any remaining records we didn't get the first time through
7315 m->CurrentRecord = m->ResourceRecords;
7316 while (m->CurrentRecord)
7317 {
7318 rr = m->CurrentRecord;
7319 if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
7320 {
7321 //LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr));
7322 mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
7323 }
7324 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
7325 // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
7326 // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
7327 if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now
7328 m->CurrentRecord = rr->next;
7329 }
7330
7331 CurrentServiceRecordSet = m->ServiceRegistrations;
7332 while (CurrentServiceRecordSet)
7333 {
7334 ServiceRecordSet *srs = CurrentServiceRecordSet;
7335 LogOperation("mDNS_StartExit: Deregistering %##s", srs->RR_SRV.resrec.name->c);
7336 uDNS_DeregisterService(m, srs);
7337 if (CurrentServiceRecordSet == srs)
7338 CurrentServiceRecordSet = srs->uDNS_next;
7339 }
7340
7341 if (m->ResourceRecords) LogOperation("mDNS_StartExit: Sending final record deregistrations");
7342 else LogOperation("mDNS_StartExit: No deregistering records remain");
7343
7344 if (m->ServiceRegistrations) LogOperation("mDNS_StartExit: Sending final service deregistrations");
7345 else LogOperation("mDNS_StartExit: No deregistering services remain");
7346
7347 // If any deregistering records remain, send their deregistration announcements before we exit
7348 if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
7349
7350 mDNS_Unlock(m);
7351
7352 LogOperation("mDNS_StartExit: done");
7353 }
7354
7355 mDNSexport void mDNS_FinalExit(mDNS *const m)
7356 {
7357 mDNSu32 rrcache_active = 0;
7358 mDNSu32 rrcache_totalused = 0;
7359 mDNSu32 slot;
7360 AuthRecord *rr;
7361 ServiceRecordSet *srs;
7362
7363 LogOperation("mDNS_FinalExit: mDNSPlatformClose");
7364 mDNSPlatformClose(m);
7365
7366 rrcache_totalused = m->rrcache_totalused;
7367 for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
7368 {
7369 while (m->rrcache_hash[slot])
7370 {
7371 CacheGroup *cg = m->rrcache_hash[slot];
7372 while (cg->members)
7373 {
7374 CacheRecord *cr = cg->members;
7375 cg->members = cg->members->next;
7376 if (cr->CRActiveQuestion) rrcache_active++;
7377 ReleaseCacheRecord(m, cr);
7378 }
7379 cg->rrcache_tail = &cg->members;
7380 ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
7381 }
7382 }
7383 debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
7384 if (rrcache_active != m->rrcache_active)
7385 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
7386
7387 for (rr = m->ResourceRecords; rr; rr = rr->next)
7388 LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
7389
7390 for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
7391 LogMsg("mDNS_FinalExit failed to deregister service: %##s", srs->RR_SRV.resrec.name->c);
7392
7393 LogOperation("mDNS_FinalExit: done");
7394 }