1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * This code is completely 100% portable C. It does not depend on any external header files
18 * from outside the mDNS project -- all the types it expects to find are defined right here.
20 * The previous point is very important: This file does not depend on any external
21 * header files. It should compile on *any* platform that has a C compiler, without
22 * making *any* assumptions about availability of so-called "standard" C functions,
23 * routines, or types (which may or may not be present on any given platform).
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
38 Change History (most recent first):
41 Revision 1.777.4.4 2008/08/14 20:43:59 cheshire
42 <rdar://problem/6143846> Back to My Mac not working with Time Capsule shared volume
44 Revision 1.777.4.3 2008/07/29 20:46:05 mcguire
45 <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
46 merge r1.782 & r1.783 from <rdar://problem/3988320>
48 Revision 1.777.4.2 2008/07/29 20:13:52 mcguire
49 <rdar://problem/6090024> BTMM: alternate SSDP queries between multicast & unicast
50 merged r1.781 for <rdar://problem/5736845>
52 Revision 1.777.4.1 2008/07/29 19:17:55 mcguire
53 <rdar://problem/6090046> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
54 merge r1.779, r.1780 from <rdar://problem/6041178>
56 Revision 1.777 2008/06/19 01:20:48 mcguire
57 <rdar://problem/4206534> Use all configured DNS servers
59 Revision 1.776 2008/04/17 20:14:14 cheshire
60 <rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
62 Revision 1.775 2008/03/26 01:53:34 mcguire
63 <rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
65 Revision 1.774 2008/03/17 17:46:08 mcguire
66 When activating an LLQ, reset all the important state and destroy any tcp connection,
67 so that everything will be restarted as if the question had just been asked.
68 Also reset servPort, so that the SOA query will be re-issued.
70 Revision 1.773 2008/03/14 22:52:36 mcguire
71 <rdar://problem/5321824> write status to the DS
72 Update status when any unicast LLQ is started
74 Revision 1.772 2008/03/06 02:48:34 mcguire
75 <rdar://problem/5321824> write status to the DS
77 Revision 1.771 2008/02/26 22:04:44 cheshire
78 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
79 Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
80 question while it's still in our 'm->NewQuestions' section of the list
82 Revision 1.770 2008/02/22 23:09:02 cheshire
83 <rdar://problem/5338420> BTMM: Not processing additional records
85 1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
86 2. Once we decide a record is acceptable, we can break out of the loop
88 Revision 1.769 2008/02/22 00:00:19 cheshire
89 <rdar://problem/5338420> BTMM: Not processing additional records
91 Revision 1.768 2008/02/19 23:26:50 cheshire
92 <rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
94 Revision 1.767 2007/12/22 02:25:29 cheshire
95 <rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
97 Revision 1.766 2007/12/15 01:12:27 cheshire
98 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
100 Revision 1.765 2007/12/15 00:18:51 cheshire
101 Renamed question->origLease to question->ReqLease
103 Revision 1.764 2007/12/14 00:49:53 cheshire
104 Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
105 the CurrentServiceRecordSet mechanism to guard against services being deleted,
106 just like the record deregistration loop uses m->CurrentRecord.
108 Revision 1.763 2007/12/13 20:20:17 cheshire
109 Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
110 SameRData from functions to macros, which allows the code to be inlined (the compiler can't
111 inline a function defined in a different compilation unit) and therefore optimized better.
113 Revision 1.762 2007/12/13 00:13:03 cheshire
114 Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
116 Revision 1.761 2007/12/13 00:03:31 cheshire
117 Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
119 Revision 1.760 2007/12/08 00:36:19 cheshire
120 <rdar://problem/5636422> Updating TXT records is too slow
121 Remove unnecessary delays on announcing record updates, and on processing them on reception
123 Revision 1.759 2007/12/07 22:41:29 cheshire
124 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
125 Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
127 Revision 1.758 2007/12/07 00:45:57 cheshire
128 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
130 Revision 1.757 2007/12/06 00:22:27 mcguire
131 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
133 Revision 1.756 2007/12/05 01:52:30 cheshire
134 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
135 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
137 Revision 1.755 2007/12/03 23:36:45 cheshire
138 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
139 Need to check GetServerForName() result is non-null before dereferencing pointer
141 Revision 1.754 2007/12/01 01:21:27 jgraessley
142 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
144 Revision 1.753 2007/12/01 00:44:15 cheshire
145 Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
147 Revision 1.752 2007/11/14 01:10:51 cheshire
148 Fixed LogOperation() message wording
150 Revision 1.751 2007/10/30 23:49:41 cheshire
151 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
152 LLQ state was not being transferred properly between duplicate questions
154 Revision 1.750 2007/10/29 23:58:52 cheshire
155 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
156 Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
158 Revision 1.749 2007/10/29 21:28:36 cheshire
159 Change "Correcting TTL" log message to LogOperation to suppress it in customer build
161 Revision 1.748 2007/10/29 20:02:50 cheshire
162 <rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
164 Revision 1.747 2007/10/26 22:53:50 cheshire
165 Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
166 instead of replicating the logic in both places
168 Revision 1.746 2007/10/25 22:48:50 cheshire
169 Added LogOperation message saying when we restart GetZoneData for record and service registrations
171 Revision 1.745 2007/10/25 20:48:47 cheshire
172 For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
174 Revision 1.744 2007/10/25 20:06:14 cheshire
175 Don't try to do SOA queries using private DNS (TLS over TCP) queries
177 Revision 1.743 2007/10/25 00:12:46 cheshire
178 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
179 Retrigger service registrations whenever a new network interface is added
181 Revision 1.742 2007/10/24 22:40:06 cheshire
182 Renamed: RecordRegistrationCallback -> RecordRegistrationGotZoneData
183 Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
185 Revision 1.741 2007/10/24 00:50:29 cheshire
186 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
187 Retrigger record registrations whenever a new network interface is added
189 Revision 1.740 2007/10/23 00:38:03 cheshire
190 When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
191 or code will spin sending the same cache expiration query repeatedly
193 Revision 1.739 2007/10/22 23:46:41 cheshire
194 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
195 Need to clear question->nta pointer after calling CancelGetZoneData()
197 Revision 1.738 2007/10/19 22:08:49 cheshire
198 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
199 Additional fixes and refinements
201 Revision 1.737 2007/10/18 23:06:42 cheshire
202 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
203 Additional fixes and refinements
205 Revision 1.736 2007/10/18 20:23:17 cheshire
206 Moved SuspendLLQs into mDNS.c, since it's only called from one place
208 Revision 1.735 2007/10/18 00:12:34 cheshire
209 Fixed "unused variable" compiler warning
211 Revision 1.734 2007/10/17 22:49:54 cheshire
212 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
214 Revision 1.733 2007/10/17 22:37:23 cheshire
215 <rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
217 Revision 1.732 2007/10/17 21:53:51 cheshire
218 Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
220 Revision 1.731 2007/10/17 18:37:50 cheshire
221 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
222 Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
224 Revision 1.730 2007/10/16 21:16:07 cheshire
225 <rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
227 Revision 1.729 2007/10/05 17:56:10 cheshire
228 Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
230 Revision 1.728 2007/10/04 23:18:14 cheshire
231 <rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
233 Revision 1.727 2007/10/04 22:51:57 cheshire
234 Added debugging LogOperation message to show when we're sending cache expiration queries
236 Revision 1.726 2007/10/03 00:14:24 cheshire
237 Removed write to null to generate stack trace for SetNextQueryTime locking failure
239 Revision 1.725 2007/10/02 21:11:08 cheshire
240 <rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
242 Revision 1.724 2007/10/02 20:10:23 cheshire
243 Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
245 Revision 1.723 2007/10/02 19:56:54 cheshire
246 <rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
248 Revision 1.722 2007/10/01 22:59:46 cheshire
249 <rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
250 Need to shut down NATTraversals on exit
252 Revision 1.721 2007/10/01 18:42:07 cheshire
253 To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
255 Revision 1.720 2007/09/29 20:40:19 cheshire
256 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
258 Revision 1.719 2007/09/27 22:23:56 cheshire
259 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
260 Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
262 Revision 1.718 2007/09/27 22:02:33 cheshire
263 <rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
265 Revision 1.717 2007/09/27 21:21:39 cheshire
266 Export CompleteDeregistration so it's callable from other files
268 Revision 1.716 2007/09/27 02:12:21 cheshire
269 Updated GrantCacheExtensions degugging message to show new record lifetime
271 Revision 1.715 2007/09/27 01:20:06 cheshire
272 <rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
274 Revision 1.714 2007/09/27 00:37:01 cheshire
275 <rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
277 Revision 1.713 2007/09/27 00:25:39 cheshire
278 Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
279 <rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
281 Revision 1.712 2007/09/26 23:16:58 cheshire
282 <rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
284 Revision 1.711 2007/09/26 22:06:02 cheshire
285 <rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
287 Revision 1.710 2007/09/26 00:49:46 cheshire
288 Improve packet logging to show sent and received packets,
289 transport protocol (UDP/TCP/TLS) and source/destination address:port
291 Revision 1.709 2007/09/21 21:12:36 cheshire
292 <rdar://problem/5498009> BTMM: Need to log updates and query packet contents
294 Revision 1.708 2007/09/20 23:13:37 cheshire
295 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
296 Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
298 Revision 1.707 2007/09/20 02:29:37 cheshire
299 <rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
301 Revision 1.706 2007/09/20 01:13:19 cheshire
302 Export CacheGroupForName so it's callable from other files
304 Revision 1.705 2007/09/20 01:12:06 cheshire
305 Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
307 Revision 1.704 2007/09/19 22:47:25 cheshire
308 <rdar://problem/5490182> Memory corruption freeing a "no such service" service record
310 Revision 1.703 2007/09/14 01:46:59 cheshire
311 Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
313 Revision 1.702 2007/09/13 22:06:46 cheshire
314 <rdar://problem/5480643> Tully's Free WiFi: DNS fails
315 Need to accept DNS responses where the query ID field matches, even if the source address does not
317 Revision 1.701 2007/09/12 23:22:32 cheshire
318 <rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
320 Revision 1.700 2007/09/12 23:03:08 cheshire
321 <rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
323 Revision 1.699 2007/09/12 22:19:28 cheshire
324 <rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
326 Revision 1.698 2007/09/12 22:13:27 cheshire
327 Remove DynDNSHostNames cleanly on shutdown
329 Revision 1.697 2007/09/12 01:44:47 cheshire
330 <rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
332 Revision 1.696 2007/09/12 01:26:08 cheshire
333 Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
335 Revision 1.695 2007/09/11 19:19:16 cheshire
336 Correct capitalization of "uPNP" to "UPnP"
338 Revision 1.694 2007/09/10 22:06:51 cheshire
339 Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
341 Revision 1.693 2007/09/07 22:24:36 vazquez
342 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
344 Revision 1.692 2007/09/07 00:12:09 cheshire
345 <rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
347 Revision 1.691 2007/09/05 22:25:01 vazquez
348 <rdar://problem/5400521> update_record mDNSResponder leak
350 Revision 1.690 2007/09/05 21:48:01 cheshire
351 <rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
352 Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
353 to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
354 otherwise those records will expire and vanish from the cache.
356 Revision 1.689 2007/09/05 02:29:06 cheshire
357 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
358 Additional fixes to code implementing "NoAnswer" logic
360 Revision 1.688 2007/08/31 22:56:39 cheshire
361 <rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
363 Revision 1.687 2007/08/31 19:53:14 cheshire
364 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
365 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
367 Revision 1.686 2007/08/30 00:01:56 cheshire
368 Added comment about SetTargetToHostName()
370 Revision 1.685 2007/08/29 01:19:24 cheshire
371 <rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
372 Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
374 Revision 1.684 2007/08/28 23:58:42 cheshire
375 Rename HostTarget -> AutoTarget
377 Revision 1.683 2007/08/28 23:53:21 cheshire
378 Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
380 Revision 1.682 2007/08/27 20:28:19 cheshire
381 Improve "suspect uDNS response" log message
383 Revision 1.681 2007/08/24 23:37:23 cheshire
384 Added debugging message to show when ExtraResourceRecord callback gets invoked
386 Revision 1.680 2007/08/24 00:15:19 cheshire
387 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
389 Revision 1.679 2007/08/23 21:47:09 vazquez
390 <rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
391 make sure we clean up port mappings on base stations by sending a lease value of 0,
392 and only send NAT-PMP packets on private networks; also save some memory by
393 not using packet structs in NATTraversals.
395 Revision 1.678 2007/08/01 16:09:13 cheshire
396 Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
398 Revision 1.677 2007/08/01 01:58:24 cheshire
399 Added RecordType sanity check in mDNS_Register_internal
401 Revision 1.676 2007/08/01 00:04:13 cheshire
402 <rdar://problem/5261696> Crash in tcpKQSocketCallback
403 Half-open TCP connections were not being cancelled properly
405 Revision 1.675 2007/07/31 02:28:35 vazquez
406 <rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
408 Revision 1.674 2007/07/31 01:57:23 cheshire
409 Adding code to respect TTL received in uDNS responses turned out to
410 expose other problems; backing out change for now.
412 Revision 1.673 2007/07/30 23:31:26 cheshire
413 Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
415 Revision 1.672 2007/07/28 01:25:56 cheshire
416 <rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
418 Revision 1.671 2007/07/27 22:32:54 cheshire
419 When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
420 of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
422 Revision 1.670 2007/07/27 20:54:43 cheshire
423 Fixed code to respect real record TTL received in uDNS responses
425 Revision 1.669 2007/07/27 20:09:32 cheshire
426 Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
428 Revision 1.668 2007/07/27 19:58:47 cheshire
429 Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
431 Revision 1.667 2007/07/27 19:52:10 cheshire
432 Don't increment m->rrcache_active for no-cache add events
434 Revision 1.666 2007/07/27 19:30:39 cheshire
435 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
436 to properly reflect tri-state nature of the possible responses
438 Revision 1.665 2007/07/27 18:44:01 cheshire
439 Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
441 Revision 1.664 2007/07/27 18:38:56 cheshire
442 Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
444 Revision 1.663 2007/07/25 03:05:02 vazquez
446 <rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
447 <rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
448 and a myriad of other security problems
450 Revision 1.662 2007/07/24 20:22:46 cheshire
451 Make sure all fields of main mDNS object are initialized correctly
453 Revision 1.661 2007/07/21 00:54:45 cheshire
454 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
456 Revision 1.660 2007/07/20 20:00:45 cheshire
457 "Legacy Browse" is better called "Automatic Browse"
459 Revision 1.659 2007/07/20 00:54:18 cheshire
460 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
462 Revision 1.658 2007/07/18 02:28:57 cheshire
463 Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
465 Revision 1.657 2007/07/18 00:57:10 cheshire
466 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
467 Only need to call AddNewClientTunnel() for IPv6 addresses
469 Revision 1.656 2007/07/16 23:54:48 cheshire
470 <rdar://problem/5338850> Crash when removing or changing DNS keys
472 Revision 1.655 2007/07/16 20:11:37 vazquez
473 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
474 Init LNT stuff and handle SSDP packets
476 Revision 1.654 2007/07/12 23:30:23 cheshire
477 Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
479 Revision 1.653 2007/07/12 02:51:27 cheshire
480 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
482 Revision 1.652 2007/07/11 23:43:42 cheshire
483 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
485 Revision 1.651 2007/07/11 22:44:40 cheshire
486 <rdar://problem/5328801> SIGHUP should purge the cache
488 Revision 1.650 2007/07/11 21:34:09 cheshire
489 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
490 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
492 Revision 1.649 2007/07/11 02:52:52 cheshire
493 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
494 In uDNS_RegisterService, set HostTarget for AutoTunnel services
496 Revision 1.648 2007/07/09 23:48:12 cheshire
497 Add parentheses around bitwise operation for clarity
499 Revision 1.647 2007/07/06 21:17:55 cheshire
500 Initialize m->retryGetAddr to timenow + 0x78000000;
502 Revision 1.646 2007/07/06 18:55:49 cheshire
503 Initialize m->NextScheduledNATOp
505 Revision 1.645 2007/06/29 22:55:54 cheshire
506 Move declaration of DNSServer *s; Fixed incomplete comment.
508 Revision 1.644 2007/06/29 00:07:29 vazquez
509 <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
511 Revision 1.643 2007/06/20 01:10:12 cheshire
512 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
514 Revision 1.642 2007/06/15 21:54:50 cheshire
515 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
517 Revision 1.641 2007/05/25 00:30:24 cheshire
518 When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
519 status matches. This is particularly important when doing a private query for an SOA record,
520 which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
521 If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
523 Revision 1.640 2007/05/25 00:25:44 cheshire
524 <rdar://problem/5227737> Need to enhance putRData to output all current known types
526 Revision 1.639 2007/05/23 00:51:33 cheshire
527 Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
528 each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
529 days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
531 Revision 1.638 2007/05/23 00:43:16 cheshire
532 If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
534 Revision 1.637 2007/05/14 23:53:00 cheshire
535 Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
537 Revision 1.636 2007/05/10 23:27:15 cheshire
538 Update mDNS_Deregister_internal debugging messages
540 Revision 1.635 2007/05/07 20:43:45 cheshire
541 <rdar://problem/4241419> Reduce the number of queries and announcements
543 Revision 1.634 2007/05/04 22:09:08 cheshire
544 Only do "restarting exponential backoff sequence" for mDNS questions
545 In mDNS_RegisterInterface, only retrigger mDNS questions
546 In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
548 Revision 1.633 2007/05/04 21:45:12 cheshire
549 Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
551 Revision 1.632 2007/05/04 20:20:50 cheshire
552 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
553 Need to set srs->nta = mDNSNULL; when regState_NoTarget
555 Revision 1.631 2007/05/04 00:39:42 cheshire
556 <rdar://problem/4410011> Eliminate looping SOA lookups
557 When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
558 each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
560 Revision 1.630 2007/05/03 22:40:38 cheshire
561 <rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
563 Revision 1.629 2007/05/03 00:15:51 cheshire
564 <rdar://problem/4410011> Eliminate looping SOA lookups
566 Revision 1.628 2007/05/02 22:21:33 cheshire
567 <rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
569 Revision 1.627 2007/04/30 19:29:13 cheshire
570 Fix display of port number in "Updating DNS Server" message
572 Revision 1.626 2007/04/30 04:21:13 cheshire
573 Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
575 Revision 1.625 2007/04/28 01:34:21 cheshire
576 Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
577 (Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
579 Revision 1.624 2007/04/27 21:04:30 cheshire
580 On network configuration change, need to call uDNS_RegisterSearchDomains
582 Revision 1.623 2007/04/27 19:28:01 cheshire
583 Any code that calls StartGetZoneData needs to keep a handle to the structure, so
584 it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
585 -- it would start a query and then quickly cancel it, and then when
586 StartGetZoneData completed, it had a dangling pointer and crashed.)
588 Revision 1.622 2007/04/26 16:09:22 cheshire
589 mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
591 Revision 1.621 2007/04/26 15:43:22 cheshire
592 Make sure DNSServer *s is non-null before using value in LogOperation
594 Revision 1.620 2007/04/26 13:11:05 cheshire
595 Fixed crash when logging out of VPN
597 Revision 1.619 2007/04/26 00:35:15 cheshire
598 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
599 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
600 inside the firewall may give answers where a public one gives none, and vice versa.)
602 Revision 1.618 2007/04/25 19:26:01 cheshire
603 m->NextScheduledQuery was getting set too early in SendQueries()
604 Improved "SendQueries didn't send all its queries" debugging message
606 Revision 1.617 2007/04/25 17:48:22 cheshire
607 Update debugging message
609 Revision 1.616 2007/04/25 16:38:32 cheshire
610 If negative cache entry already exists, reactivate it instead of creating a new one
612 Revision 1.615 2007/04/25 02:14:38 cheshire
613 <rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
614 Additional fixes to make LLQs work properly
616 Revision 1.614 2007/04/23 21:52:45 cheshire
617 <rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
619 Revision 1.613 2007/04/23 04:58:20 cheshire
620 <rdar://problem/5072548> Crash when setting extremely large TXT records
622 Revision 1.612 2007/04/22 20:39:38 cheshire
623 <rdar://problem/4633194> Add 20 to 120ms random delay to browses
625 Revision 1.611 2007/04/22 18:16:29 cheshire
626 Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
628 Revision 1.610 2007/04/22 06:02:02 cheshire
629 <rdar://problem/4615977> Query should immediately return failure when no server
631 Revision 1.609 2007/04/20 21:17:24 cheshire
632 For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
634 Revision 1.608 2007/04/20 19:45:31 cheshire
635 In LogAllOperations mode, dump out unknown DNS packets in their entirety
637 Revision 1.607 2007/04/19 23:56:25 cheshire
638 Don't do cache-flush processing for LLQ answers
640 Revision 1.606 2007/04/19 22:50:53 cheshire
641 <rdar://problem/4246187> Identical client queries should reference a single shared core query
643 Revision 1.605 2007/04/19 20:06:41 cheshire
644 Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
646 Revision 1.604 2007/04/19 18:03:04 cheshire
647 Add "const" declaration
649 Revision 1.603 2007/04/06 21:00:25 cheshire
652 Revision 1.602 2007/04/05 22:55:35 cheshire
653 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
655 Revision 1.601 2007/04/04 21:48:52 cheshire
656 <rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
658 Revision 1.600 2007/04/04 01:31:33 cheshire
659 Improve debugging message
661 Revision 1.599 2007/04/04 00:03:26 cheshire
662 <rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
664 Revision 1.598 2007/04/03 19:43:16 cheshire
665 Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
667 Revision 1.597 2007/03/31 00:32:32 cheshire
668 After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
670 Revision 1.596 2007/03/28 20:59:26 cheshire
671 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
673 Revision 1.595 2007/03/26 23:48:16 cheshire
674 <rdar://problem/4848295> Advertise model information via Bonjour
675 Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
677 Revision 1.594 2007/03/26 23:05:05 cheshire
678 <rdar://problem/5089257> Don't cache TSIG records
680 Revision 1.593 2007/03/23 17:40:08 cheshire
681 <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
683 Revision 1.592 2007/03/22 18:31:48 cheshire
684 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
686 Revision 1.591 2007/03/22 00:49:19 cheshire
687 <rdar://problem/4848295> Advertise model information via Bonjour
689 Revision 1.590 2007/03/21 23:05:59 cheshire
690 Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
692 Revision 1.589 2007/03/20 15:37:19 cheshire
693 Delete unnecessary log message
695 Revision 1.588 2007/03/20 00:24:44 cheshire
696 <rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
698 Revision 1.587 2007/03/16 22:10:56 cheshire
699 <rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
701 Revision 1.586 2007/03/10 03:26:44 cheshire
702 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
704 Revision 1.585 2007/03/10 02:02:58 cheshire
705 <rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
706 Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
708 Revision 1.584 2007/02/28 01:51:27 cheshire
709 Added comment about reverse-order IP address
711 Revision 1.583 2007/01/27 03:19:33 cheshire
712 Need to initialize question->sock
714 Revision 1.582 2007/01/25 00:40:16 cheshire
715 Unified CNAME-following functionality into cache management code (which means CNAME-following
716 should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
718 Revision 1.581 2007/01/23 02:56:11 cheshire
719 Store negative results in the cache, instead of generating them out of pktResponseHndlr()
721 Revision 1.580 2007/01/19 21:17:33 cheshire
722 StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
724 Revision 1.579 2007/01/19 18:39:10 cheshire
725 Fix a bunch of parameters that should have been declared "const"
727 Revision 1.578 2007/01/10 22:51:57 cheshire
728 <rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
730 Revision 1.577 2007/01/10 02:05:21 cheshire
731 Delay uDNS_SetupDNSConfig() until *after* the platform layer
732 has set up the interface list and security credentials
734 Revision 1.576 2007/01/09 02:40:57 cheshire
735 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
736 moved it to mDNS_Init() in mDNS.c (core code)
738 Revision 1.575 2007/01/09 00:17:25 cheshire
739 Improve "ERROR m->CurrentRecord already set" debugging messages
741 Revision 1.574 2007/01/05 08:30:41 cheshire
742 Trim excessive "$Log" checkin history from before 2006
743 (checkin history still available via "cvs log ..." of course)
745 Revision 1.573 2007/01/05 06:34:03 cheshire
746 Improve "ERROR m->CurrentQuestion already set" debugging messages
748 Revision 1.572 2007/01/04 23:11:11 cheshire
749 <rdar://problem/4720673> uDNS: Need to start caching unicast records
750 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
752 Revision 1.571 2007/01/04 21:45:20 cheshire
753 Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
754 to do additional lock sanity checking around callback invocations
756 Revision 1.570 2007/01/04 20:57:47 cheshire
757 Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
759 Revision 1.569 2007/01/04 20:27:27 cheshire
760 Change a LogMsg() to debugf()
762 Revision 1.568 2007/01/04 02:39:53 cheshire
763 <rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
765 Revision 1.567 2006/12/21 00:01:37 cheshire
766 Tidy up code alignment
768 Revision 1.566 2006/12/20 04:07:34 cheshire
769 Remove uDNS_info substructure from AuthRecord_struct
771 Revision 1.565 2006/12/19 22:49:23 cheshire
772 Remove uDNS_info substructure from ServiceRecordSet_struct
774 Revision 1.564 2006/12/19 02:38:20 cheshire
775 Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
777 Revision 1.563 2006/12/19 02:18:48 cheshire
778 Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
780 Revision 1.562 2006/12/16 01:58:31 cheshire
781 <rdar://problem/4720673> uDNS: Need to start caching unicast records
783 Revision 1.561 2006/12/01 07:38:53 herscher
784 Only perform cache workaround fix if query is wide-area
786 Revision 1.560 2006/11/30 23:07:56 herscher
787 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
789 Revision 1.559 2006/11/27 08:20:57 cheshire
790 Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
792 Revision 1.558 2006/11/10 07:44:03 herscher
793 <rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
795 Revision 1.557 2006/11/10 01:12:51 cheshire
796 <rdar://problem/4829718> Incorrect TTL corrections
798 Revision 1.556 2006/11/10 00:54:14 cheshire
799 <rdar://problem/4816598> Changing case of Computer Name doesn't work
801 Revision 1.555 2006/10/30 20:03:37 cheshire
802 <rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
804 Revision 1.554 2006/10/20 05:35:04 herscher
805 <rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
807 Revision 1.553 2006/10/05 03:42:43 herscher
808 Remove embedded uDNS_info struct in DNSQuestion_struct
810 Revision 1.552 2006/09/15 21:20:15 cheshire
811 Remove uDNS_info substructure from mDNS_struct
813 Revision 1.551 2006/08/14 23:24:22 cheshire
814 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
816 Revision 1.550 2006/07/27 17:58:34 cheshire
817 Improved text of "SendQueries didn't send all its queries; will try again" debugging message
819 Revision 1.549 2006/07/20 22:07:31 mkrochma
820 <rdar://problem/4633196> Wide-area browsing is currently broken in TOT
821 More fixes for uninitialized variables
823 Revision 1.548 2006/07/20 19:30:19 mkrochma
824 <rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
826 Revision 1.547 2006/07/15 02:31:30 cheshire
827 <rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
829 Revision 1.546 2006/07/07 01:09:09 cheshire
830 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
831 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
833 Revision 1.545 2006/07/05 23:10:30 cheshire
834 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
835 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
837 Revision 1.544 2006/06/29 07:42:14 cheshire
838 <rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
840 Revision 1.543 2006/06/29 01:38:43 cheshire
841 <rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
843 Revision 1.542 2006/06/27 23:40:29 cheshire
844 Fix typo in comment: mis-spelled "compile"
846 Revision 1.541 2006/06/27 19:46:24 cheshire
847 Updated comments and debugging messages
849 Revision 1.540 2006/06/15 21:35:16 cheshire
850 Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
851 from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
853 Revision 1.539 2006/06/08 23:45:46 cheshire
854 Change SimultaneousProbe messages from debugf() to LogOperation()
856 Revision 1.538 2006/03/19 17:13:06 cheshire
857 <rdar://problem/4483117> Need faster purging of stale records
858 Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
859 and reconfirm whole chain of antecedents ot once
861 Revision 1.537 2006/03/19 02:00:07 cheshire
862 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
864 Revision 1.536 2006/03/08 23:29:53 cheshire
865 <rdar://problem/4468716> Improve "Service Renamed" log message
867 Revision 1.535 2006/03/02 20:41:17 cheshire
868 <rdar://problem/4111464> After record update, old record sometimes remains in cache
869 Minor code tidying and comments to reduce the risk of similar programming errors in future
871 Revision 1.534 2006/03/02 03:25:46 cheshire
872 <rdar://problem/4111464> After record update, old record sometimes remains in cache
873 Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
875 Revision 1.533 2006/02/26 00:54:41 cheshire
876 Fixes to avoid code generation warning/error on FreeBSD 7
880 #include "DNSCommon.h" // Defines general DNS untility routines
881 #include "uDNS.h" // Defines entry points into unicast-specific routines
883 // Disable certain benign warnings with Microsoft compilers
884 #if(defined(_MSC_VER))
885 // Disable "conditional expression is constant" warning for debug macros.
886 // Otherwise, this generates warnings for the perfectly natural construct "while(1)"
887 // If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
888 #pragma warning(disable:4127)
890 // Disable "assignment within conditional expression".
891 // Other compilers understand the convention that if you place the assignment expression within an extra pair
892 // of parentheses, this signals to the compiler that you really intended an assignment and no warning is necessary.
893 // The Microsoft compiler doesn't understand this convention, so in the absense of any other way to signal
894 // to the compiler that the assignment is intentional, we have to just turn this warning off completely.
895 #pragma warning(disable:4706)
898 // ***************************************************************************
899 #if COMPILER_LIKES_PRAGMA_MARK
900 #pragma mark - Program Constants
905 mDNSlocal
const mDNSInterfaceID mDNSInterfaceMark
= (mDNSInterfaceID
)~0;
907 // Any records bigger than this are considered 'large' records
908 #define SmallRecordLimit 1024
910 #define kMaxUpdateCredits 10
911 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
913 mDNSexport
const char *const mDNS_DomainTypeNames
[] =
915 "b._dns-sd._udp.", // Browse
916 "db._dns-sd._udp.", // Default Browse
917 "lb._dns-sd._udp.", // Automatic Browse
918 "r._dns-sd._udp.", // Registration
919 "dr._dns-sd._udp." // Default Registration
922 #ifdef UNICAST_DISABLED
923 #define uDNS_IsActiveQuery(q, u) mDNSfalse
926 // ***************************************************************************
927 #if COMPILER_LIKES_PRAGMA_MARK
929 #pragma mark - General Utility Functions
932 #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
933 #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
935 mDNSexport
void SetNextQueryTime(mDNS
*const m
, const DNSQuestion
*const q
)
937 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1)
938 LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m
->mDNS_busy
, m
->mDNS_reentrancy
);
941 if (m
->mDNS_busy
!= m
->mDNS_reentrancy
+1) *(long*)0 = 0;
944 if (ActiveQuestion(q
))
946 mDNSs32 sendtime
= q
->LastQTime
+ q
->ThisQInterval
;
948 // Don't allow sendtime to be earlier than SuppressStdPort53Queries
949 if (!mDNSOpaque16IsZero(q
->TargetQID
) && !q
->LongLived
&& m
->SuppressStdPort53Queries
&& (sendtime
- m
->SuppressStdPort53Queries
< 0))
950 sendtime
= m
->SuppressStdPort53Queries
;
952 if (m
->NextScheduledQuery
- sendtime
> 0)
953 m
->NextScheduledQuery
= sendtime
;
957 mDNSexport CacheGroup
*CacheGroupForName(const mDNS
*const m
, const mDNSu32 slot
, const mDNSu32 namehash
, const domainname
*const name
)
960 for (cg
= m
->rrcache_hash
[slot
]; cg
; cg
=cg
->next
)
961 if (cg
->namehash
== namehash
&& SameDomainName(cg
->name
, name
))
966 mDNSlocal CacheGroup
*CacheGroupForRecord(const mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
968 return(CacheGroupForName(m
, slot
, rr
->namehash
, rr
->name
));
971 mDNSlocal mDNSBool
AddressIsLocalSubnet(mDNS
*const m
, const mDNSInterfaceID InterfaceID
, const mDNSAddr
*addr
)
973 NetworkInterfaceInfo
*intf
;
975 if (addr
->type
== mDNSAddrType_IPv4
)
977 // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
978 if (mDNSv4AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
979 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
980 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
981 if (((intf
->ip
.ip
.v4
.NotAnInteger
^ addr
->ip
.v4
.NotAnInteger
) & intf
->mask
.ip
.v4
.NotAnInteger
) == 0)
985 if (addr
->type
== mDNSAddrType_IPv6
)
987 if (mDNSv6AddressIsLinkLocal(&addr
->ip
.v4
)) return(mDNStrue
);
988 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
989 if (intf
->ip
.type
== addr
->type
&& intf
->InterfaceID
== InterfaceID
&& intf
->McastTxRx
)
990 if ((((intf
->ip
.ip
.v6
.l
[0] ^ addr
->ip
.v6
.l
[0]) & intf
->mask
.ip
.v6
.l
[0]) == 0) &&
991 (((intf
->ip
.ip
.v6
.l
[1] ^ addr
->ip
.v6
.l
[1]) & intf
->mask
.ip
.v6
.l
[1]) == 0) &&
992 (((intf
->ip
.ip
.v6
.l
[2] ^ addr
->ip
.v6
.l
[2]) & intf
->mask
.ip
.v6
.l
[2]) == 0) &&
993 (((intf
->ip
.ip
.v6
.l
[3] ^ addr
->ip
.v6
.l
[3]) & intf
->mask
.ip
.v6
.l
[3]) == 0))
1000 // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
1001 // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
1002 mDNSlocal
void AnswerLocalOnlyQuestionWithResourceRecord(mDNS
*const m
, DNSQuestion
*q
, AuthRecord
*rr
, QC_result AddRecord
)
1004 // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
1005 if (AddRecord
) rr
->AnsweredLocalQ
= mDNStrue
;
1006 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1007 if (q
->QuestionCallback
&& !q
->NoAnswer
)
1008 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
1009 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1012 // When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
1013 // to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
1014 // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
1015 // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
1016 mDNSlocal
void AnswerLocalQuestions(mDNS
*const m
, AuthRecord
*rr
, QC_result AddRecord
)
1018 if (m
->CurrentQuestion
)
1019 LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
1021 m
->CurrentQuestion
= m
->LocalOnlyQuestions
;
1022 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewLocalOnlyQuestions
)
1024 DNSQuestion
*q
= m
->CurrentQuestion
;
1025 m
->CurrentQuestion
= q
->next
;
1026 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1027 AnswerLocalOnlyQuestionWithResourceRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1030 // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
1031 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
1033 m
->CurrentQuestion
= m
->Questions
;
1034 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
1036 DNSQuestion
*q
= m
->CurrentQuestion
;
1037 m
->CurrentQuestion
= q
->next
;
1038 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
1039 AnswerLocalOnlyQuestionWithResourceRecord(m
, q
, rr
, AddRecord
); // MUST NOT dereference q again
1043 m
->CurrentQuestion
= mDNSNULL
;
1046 // ***************************************************************************
1047 #if COMPILER_LIKES_PRAGMA_MARK
1049 #pragma mark - Resource Record Utility Functions
1052 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
1054 #define ResourceRecordIsValidAnswer(RR) ( ((RR)-> resrec.RecordType & kDNSRecordTypeActiveMask) && \
1055 ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1056 ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
1057 ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
1059 #define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
1060 (ResourceRecordIsValidAnswer(RR) && \
1061 ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
1063 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
1064 #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
1066 #define InitialAnnounceCount ((mDNSu8)8)
1068 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
1069 // This means that because the announce interval is doubled after sending the first packet, the first
1070 // observed on-the-wire inter-packet interval between announcements is actually one second.
1071 // The half-second value here may be thought of as a conceptual (non-existent) half-second delay *before* the first packet is sent.
1072 #define DefaultProbeIntervalForTypeUnique (mDNSPlatformOneSecond/4)
1073 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
1074 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
1076 #define DefaultAPIntervalForRecordType(X) ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared ) ? DefaultAnnounceIntervalForTypeShared : \
1077 (X) & (kDNSRecordTypeUnique ) ? DefaultProbeIntervalForTypeUnique : \
1078 (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
1080 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
1081 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
1082 #define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
1083 #define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
1085 #define MaxUnansweredQueries 4
1087 // SameResourceRecordSignature returns true if two resources records have the same name, type, and class, and may be sent
1088 // (or were received) on the same interface (i.e. if *both* records specify an interface, then it has to match).
1089 // TTL and rdata may differ.
1090 // This is used for cache flush management:
1091 // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
1092 // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
1094 mDNSlocal mDNSBool
SameResourceRecordSignature(const AuthRecord
*const r1
, const AuthRecord
*const r2
)
1096 if (!r1
) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse
); }
1097 if (!r2
) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse
); }
1098 if (r1
->resrec
.InterfaceID
&&
1099 r2
->resrec
.InterfaceID
&&
1100 r1
->resrec
.InterfaceID
!= r2
->resrec
.InterfaceID
) return(mDNSfalse
);
1102 r1
->resrec
.rrtype
== r2
->resrec
.rrtype
&&
1103 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
&&
1104 r1
->resrec
.namehash
== r2
->resrec
.namehash
&&
1105 SameDomainName(r1
->resrec
.name
, r2
->resrec
.name
));
1108 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
1109 // authoratative record is unique (as opposed to shared). For unique records, we are supposed to have
1110 // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict.
1111 // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY,
1112 // so a response of any type should match, even if it is not actually the type the client plans to use.
1113 mDNSlocal mDNSBool
PacketRRMatchesSignature(const CacheRecord
*const pktrr
, const AuthRecord
*const authrr
)
1115 if (!pktrr
) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse
); }
1116 if (!authrr
) { LogMsg("PacketRRMatchesSignature ERROR: authrr is NULL"); return(mDNSfalse
); }
1117 if (pktrr
->resrec
.InterfaceID
&&
1118 authrr
->resrec
.InterfaceID
&&
1119 pktrr
->resrec
.InterfaceID
!= authrr
->resrec
.InterfaceID
) return(mDNSfalse
);
1120 if (!(authrr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) && pktrr
->resrec
.rrtype
!= authrr
->resrec
.rrtype
) return(mDNSfalse
);
1122 pktrr
->resrec
.rrclass
== authrr
->resrec
.rrclass
&&
1123 pktrr
->resrec
.namehash
== authrr
->resrec
.namehash
&&
1124 SameDomainName(pktrr
->resrec
.name
, authrr
->resrec
.name
));
1127 // CacheRecord *ka is the CacheRecord from the known answer list in the query.
1128 // This is the information that the requester believes to be correct.
1129 // AuthRecord *rr is the answer we are proposing to give, if not suppressed.
1130 // This is the information that we believe to be correct.
1131 // We've already determined that we plan to give this answer on this interface
1132 // (either the record is non-specific, or it is specific to this interface)
1133 // so now we just need to check the name, type, class, rdata and TTL.
1134 mDNSlocal mDNSBool
ShouldSuppressKnownAnswer(const CacheRecord
*const ka
, const AuthRecord
*const rr
)
1136 // If RR signature is different, or data is different, then don't suppress our answer
1137 if (!IdenticalResourceRecord(&ka
->resrec
, &rr
->resrec
)) return(mDNSfalse
);
1139 // If the requester's indicated TTL is less than half the real TTL,
1140 // we need to give our answer before the requester's copy expires.
1141 // If the requester's indicated TTL is at least half the real TTL,
1142 // then we can suppress our answer this time.
1143 // If the requester's indicated TTL is greater than the TTL we believe,
1144 // then that's okay, and we don't need to do anything about it.
1145 // (If two responders on the network are offering the same information,
1146 // that's okay, and if they are offering the information with different TTLs,
1147 // the one offering the lower TTL should defer to the one offering the higher TTL.)
1148 return(mDNSBool
)(ka
->resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/ 2);
1151 mDNSlocal
void SetNextAnnounceProbeTime(mDNS
*const m
, const AuthRecord
*const rr
)
1153 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1155 //LogMsg("ProbeCount %d Next %ld %s",
1156 // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
1157 if (m
->NextScheduledProbe
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1158 m
->NextScheduledProbe
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1160 else if (rr
->AnnounceCount
&& ResourceRecordIsValidAnswer(rr
))
1162 if (m
->NextScheduledResponse
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) >= 0)
1163 m
->NextScheduledResponse
= (rr
->LastAPTime
+ rr
->ThisAPInterval
);
1167 mDNSlocal
void InitializeLastAPTime(mDNS
*const m
, AuthRecord
*const rr
, mDNSs32 interval
)
1169 rr
->ThisAPInterval
= interval
;
1171 // To allow us to aggregate probes when a group of services are registered together,
1172 // the first probe is delayed 1/4 second. This means the common-case behaviour is:
1173 // 1/4 second wait; probe
1174 // 1/4 second wait; probe
1175 // 1/4 second wait; probe
1176 // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
1180 // If we have no probe suppression time set, or it is in the past, set it now
1181 if (m
->SuppressProbes
== 0 || m
->SuppressProbes
- m
->timenow
< 0)
1183 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ DefaultProbeIntervalForTypeUnique
);
1184 // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
1185 if (m
->SuppressProbes
- m
->NextScheduledProbe
>= 0)
1186 m
->SuppressProbes
= m
->NextScheduledProbe
;
1187 // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
1188 if (m
->SuppressProbes
- m
->NextScheduledQuery
>= 0)
1189 m
->SuppressProbes
= m
->NextScheduledQuery
;
1193 rr
->LastAPTime
= m
->SuppressProbes
- interval
;
1194 // Set LastMCTime to now, to inhibit multicast responses
1195 // (no need to send additional multicast responses when we're announcing anyway)
1196 rr
->LastMCTime
= m
->timenow
;
1197 rr
->LastMCInterface
= mDNSInterfaceMark
;
1199 // If this is a record type that's not going to probe, then delay its first announcement so that
1200 // it will go out synchronized with the first announcement for the other records that *are* probing.
1201 // This is a minor performance tweak that helps keep groups of related records synchronized together.
1202 // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
1203 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
1204 // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
1205 // because they will meet the criterion of being at least half-way to their scheduled announcement time.
1206 // The exception is unique records that have already been verified and are just being updated
1207 // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
1208 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
1209 rr
->LastAPTime
= m
->timenow
- interval
;
1210 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
)
1211 rr
->LastAPTime
+= DefaultProbeIntervalForTypeUnique
* DefaultProbeCountForTypeUnique
+ interval
/ 2;
1213 SetNextAnnounceProbeTime(m
, rr
);
1216 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
1217 // Eventually we should unify this with GetServiceTarget() in uDNS.c
1218 mDNSlocal
void SetTargetToHostName(mDNS
*const m
, AuthRecord
*const rr
)
1220 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
1222 if (!target
) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr
->resrec
.rrtype
);
1224 if (target
&& SameDomainName(target
, &m
->MulticastHostname
))
1225 debugf("SetTargetToHostName: Target of %##s is already %##s", rr
->resrec
.name
->c
, target
->c
);
1227 if (target
&& !SameDomainName(target
, &m
->MulticastHostname
))
1229 AssignDomainName(target
, &m
->MulticastHostname
);
1230 SetNewRData(&rr
->resrec
, mDNSNULL
, 0); // Update rdlength, rdestimate, rdatahash
1232 // If we're in the middle of probing this record, we need to start again,
1233 // because changing its rdata may change the outcome of the tie-breaker.
1234 // (If the record type is kDNSRecordTypeUnique (unconfirmed unique) then DefaultProbeCountForRecordType is non-zero.)
1235 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
1237 // If we've announced this record, we really should send a goodbye packet for the old rdata before
1238 // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
1239 // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
1240 if (rr
->RequireGoodbye
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
)
1241 debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
1242 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1244 rr
->AnnounceCount
= InitialAnnounceCount
;
1245 rr
->RequireGoodbye
= mDNSfalse
;
1246 InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
));
1250 mDNSlocal
void AcknowledgeRecord(mDNS
*const m
, AuthRecord
*const rr
)
1252 if (rr
->RecordCallback
)
1254 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1255 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1256 rr
->Acknowledged
= mDNStrue
;
1257 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1258 rr
->RecordCallback(m
, rr
, mStatus_NoError
);
1259 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1263 mDNSlocal
void ActivateUnicastRegistration(mDNS
*const m
, AuthRecord
*const rr
)
1266 rr
->AnnounceCount
= 0;
1267 rr
->ThisAPInterval
= 5 * mDNSPlatformOneSecond
; // After doubling, first retry will happen after ten seconds
1268 rr
->LastAPTime
= m
->timenow
- rr
->ThisAPInterval
;
1269 rr
->state
= regState_FetchingZoneData
;
1270 rr
->uselease
= mDNStrue
;
1273 // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
1274 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
1275 ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
1276 #define RecordIsLocalDuplicate(A,B) \
1277 ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
1279 // Exported so uDNS.c can call this
1280 mDNSexport mStatus
mDNS_Register_internal(mDNS
*const m
, AuthRecord
*const rr
)
1282 domainname
*target
= GetRRDomainNameTarget(&rr
->resrec
);
1284 AuthRecord
**p
= &m
->ResourceRecords
;
1285 AuthRecord
**d
= &m
->DuplicateRecords
;
1287 if ((mDNSs32
)rr
->resrec
.rroriginalttl
<= 0)
1288 { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1290 if (!rr
->resrec
.RecordType
)
1291 { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m
, rr
)); return(mStatus_BadParamErr
); }
1293 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
1294 while (*d
&& *d
!= rr
) d
=&(*d
)->next
;
1297 LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
1298 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1299 return(mStatus_AlreadyRegistered
);
1302 if (rr
->DependentOn
)
1304 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
1305 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
1308 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
1309 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1310 return(mStatus_Invalid
);
1312 if (!(rr
->DependentOn
->resrec
.RecordType
& (kDNSRecordTypeUnique
| kDNSRecordTypeVerified
)))
1314 LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
1315 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->DependentOn
->resrec
.RecordType
);
1316 return(mStatus_Invalid
);
1320 // If this resource record is referencing a specific interface, make sure it exists
1321 if (rr
->resrec
.InterfaceID
&& rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
1323 NetworkInterfaceInfo
*intf
;
1324 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
1325 if (intf
->InterfaceID
== rr
->resrec
.InterfaceID
) break;
1328 debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr
->resrec
.InterfaceID
);
1329 return(mStatus_BadReferenceErr
);
1333 rr
->next
= mDNSNULL
;
1335 // Field Group 1: The actual information pertaining to this resource record
1336 // Set up by client prior to call
1338 // Field Group 2: Persistent metadata for Authoritative Records
1339 // rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1340 // rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1341 // rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1342 // rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
1343 // rr->Callback = already set in mDNS_SetupResourceRecord
1344 // rr->Context = already set in mDNS_SetupResourceRecord
1345 // rr->RecordType = already set in mDNS_SetupResourceRecord
1346 // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1347 // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
1348 // Make sure target is not uninitialized data, or we may crash writing debugging log messages
1349 if (rr
->AutoTarget
&& target
) target
->c
[0] = 0;
1351 // Field Group 3: Transient state for Authoritative Records
1352 rr
->Acknowledged
= mDNSfalse
;
1353 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
1354 rr
->AnnounceCount
= InitialAnnounceCount
;
1355 rr
->RequireGoodbye
= mDNSfalse
;
1356 rr
->AnsweredLocalQ
= mDNSfalse
;
1357 rr
->IncludeInProbe
= mDNSfalse
;
1358 rr
->ImmedAnswer
= mDNSNULL
;
1359 rr
->ImmedUnicast
= mDNSfalse
;
1360 rr
->ImmedAdditional
= mDNSNULL
;
1361 rr
->SendRNow
= mDNSNULL
;
1362 rr
->v4Requester
= zerov4Addr
;
1363 rr
->v6Requester
= zerov6Addr
;
1364 rr
->NextResponse
= mDNSNULL
;
1365 rr
->NR_AnswerTo
= mDNSNULL
;
1366 rr
->NR_AdditionalTo
= mDNSNULL
;
1367 if (!rr
->AutoTarget
) InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
));
1368 // rr->LastAPTime = Set for us in InitializeLastAPTime()
1369 // rr->LastMCTime = Set for us in InitializeLastAPTime()
1370 // rr->LastMCInterface = Set for us in InitializeLastAPTime()
1371 rr
->NewRData
= mDNSNULL
;
1372 rr
->newrdlength
= 0;
1373 rr
->UpdateCallback
= mDNSNULL
;
1374 rr
->UpdateCredits
= kMaxUpdateCredits
;
1375 rr
->NextUpdateCredit
= 0;
1376 rr
->UpdateBlocked
= 0;
1378 // Field Group 4: Transient uDNS state for Authoritative Records
1379 rr
->state
= regState_Zero
;
1385 rr
->UpdateServer
= zeroAddr
;
1386 rr
->UpdatePort
= zeroIPPort
;
1391 rr
->InFlightRData
= 0;
1392 rr
->InFlightRDLen
= 0;
1393 rr
->QueuedRData
= 0;
1394 rr
->QueuedRDLen
= 0;
1396 // rr->resrec.interface = already set in mDNS_SetupResourceRecord
1397 // rr->resrec.name->c = MUST be set by client
1398 // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
1399 // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord
1400 // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
1401 // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
1404 SetTargetToHostName(m
, rr
); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
1407 rr
->resrec
.rdlength
= GetRDLength(&rr
->resrec
, mDNSfalse
);
1408 rr
->resrec
.rdestimate
= GetRDLength(&rr
->resrec
, mDNStrue
);
1411 if (!ValidateDomainName(rr
->resrec
.name
))
1412 { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
1414 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1415 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1416 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1417 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& rr
->resrec
.rdlength
== 0) { rr
->resrec
.rdlength
= 1; rr
->resrec
.rdata
->u
.txt
.c
[0] = 0; }
1419 // Don't do this until *after* we've set rr->resrec.rdlength
1420 if (!ValidateRData(rr
->resrec
.rrtype
, rr
->resrec
.rdlength
, rr
->resrec
.rdata
))
1421 { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m
, rr
)); return(mStatus_Invalid
); }
1423 rr
->resrec
.namehash
= DomainNameHashValue(rr
->resrec
.name
);
1424 rr
->resrec
.rdatahash
= target
? DomainNameHashValue(target
) : RDataHashValue(&rr
->resrec
);
1426 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
1428 // If this is supposed to be unique, make sure we don't have any name conflicts
1429 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
1431 const AuthRecord
*s1
= rr
->RRSet
? rr
->RRSet
: rr
;
1432 for (r
= m
->ResourceRecords
; r
; r
=r
->next
)
1434 const AuthRecord
*s2
= r
->RRSet
? r
->RRSet
: r
;
1435 if (s1
!= s2
&& SameResourceRecordSignature(r
, rr
) && !SameRData(&r
->resrec
, &rr
->resrec
))
1438 if (r
) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
1440 debugf("Name conflict %p %##s (%s)", rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1441 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
1442 rr
->resrec
.rroriginalttl
= 0;
1443 rr
->ImmedAnswer
= mDNSInterfaceMark
;
1444 m
->NextScheduledResponse
= m
->timenow
;
1449 // Now that we've finished building our new record, make sure it's not identical to one we already have
1450 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (RecordIsLocalDuplicate(r
, rr
)) break;
1454 debugf("Adding to duplicate list %p %s", rr
, ARDisplayString(m
,rr
));
1456 // If the previous copy of this record is already verified unique,
1457 // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
1458 // Setting ProbeCount to zero will cause SendQueries() to advance this record to
1459 // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
1460 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& r
->resrec
.RecordType
== kDNSRecordTypeVerified
)
1465 debugf("Adding to active record list %p %s", rr
, ARDisplayString(m
,rr
));
1466 if (!m
->NewLocalRecords
) m
->NewLocalRecords
= rr
;
1470 if (!AuthRecord_uDNS(rr
))
1472 // For records that are not going to probe, acknowledge them right away
1473 if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnique
&& rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
1474 AcknowledgeRecord(m
, rr
);
1476 #ifndef UNICAST_DISABLED
1479 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
1480 ActivateUnicastRegistration(m
, rr
);
1484 return(mStatus_NoError
);
1487 mDNSlocal
void RecordProbeFailure(mDNS
*const m
, const AuthRecord
*const rr
)
1489 m
->ProbeFailTime
= m
->timenow
;
1490 m
->NumFailedProbes
++;
1491 // If we've had fifteen or more probe failures, rate-limit to one every five seconds.
1492 // If a bunch of hosts have all been configured with the same name, then they'll all
1493 // conflict and run through the same series of names: name-2, name-3, name-4, etc.,
1494 // up to name-10. After that they'll start adding random increments in the range 1-100,
1495 // so they're more likely to branch out in the available namespace and settle on a set of
1496 // unique names quickly. If after five more tries the host is still conflicting, then we
1497 // may have a serious problem, so we start rate-limiting so we don't melt down the network.
1498 if (m
->NumFailedProbes
>= 15)
1500 m
->SuppressProbes
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
1501 LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
1502 m
->NumFailedProbes
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1506 mDNSlocal
void CompleteRDataUpdate(mDNS
*const m
, AuthRecord
*const rr
)
1508 RData
*OldRData
= rr
->resrec
.rdata
;
1509 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
); // Update our rdata
1510 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
1511 if (rr
->UpdateCallback
)
1512 rr
->UpdateCallback(m
, rr
, OldRData
); // ... and let the client know
1515 // NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
1516 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1517 // Exported so uDNS.c can call this
1518 mDNSexport mStatus
mDNS_Deregister_internal(mDNS
*const m
, AuthRecord
*const rr
, mDNS_Dereg_type drt
)
1521 mDNSu8 RecordType
= rr
->resrec
.RecordType
;
1522 AuthRecord
**p
= &m
->ResourceRecords
; // Find this record in our list of active records
1524 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
1528 // We found our record on the main list. See if there are any duplicates that need special handling.
1529 if (drt
== mDNS_Dereg_conflict
) // If this was a conflict, see that all duplicates get the same treatment
1531 // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
1532 // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
1533 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
) if (RecordIsLocalDuplicate(r2
, rr
)) r2
->ProbeCount
= 0xFF;
1537 // Before we delete the record (and potentially send a goodbye packet)
1538 // first see if we have a record on the duplicate list ready to take over from it.
1539 AuthRecord
**d
= &m
->DuplicateRecords
;
1540 while (*d
&& !RecordIsLocalDuplicate(*d
, rr
)) d
=&(*d
)->next
;
1543 AuthRecord
*dup
= *d
;
1544 debugf("Duplicate record %p taking over from %p %##s (%s)",
1545 dup
, rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1546 *d
= dup
->next
; // Cut replacement record from DuplicateRecords list
1547 dup
->next
= rr
->next
; // And then...
1548 rr
->next
= dup
; // ... splice it in right after the record we're about to delete
1549 dup
->resrec
.RecordType
= rr
->resrec
.RecordType
;
1550 dup
->ProbeCount
= rr
->ProbeCount
;
1551 dup
->AnnounceCount
= rr
->AnnounceCount
;
1552 dup
->RequireGoodbye
= rr
->RequireGoodbye
;
1553 dup
->ImmedAnswer
= rr
->ImmedAnswer
;
1554 dup
->ImmedUnicast
= rr
->ImmedUnicast
;
1555 dup
->ImmedAdditional
= rr
->ImmedAdditional
;
1556 dup
->v4Requester
= rr
->v4Requester
;
1557 dup
->v6Requester
= rr
->v6Requester
;
1558 dup
->ThisAPInterval
= rr
->ThisAPInterval
;
1559 dup
->LastAPTime
= rr
->LastAPTime
;
1560 dup
->LastMCTime
= rr
->LastMCTime
;
1561 dup
->LastMCInterface
= rr
->LastMCInterface
;
1562 rr
->RequireGoodbye
= mDNSfalse
;
1568 // We didn't find our record on the main list; try the DuplicateRecords list instead.
1569 p
= &m
->DuplicateRecords
;
1570 while (*p
&& *p
!= rr
) p
=&(*p
)->next
;
1571 // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
1572 if (*p
) rr
->RequireGoodbye
= mDNSfalse
;
1573 if (*p
) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
1574 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1579 // No need to log an error message if we already know this is a potentially repeated deregistration
1580 if (drt
!= mDNS_Dereg_repeat
)
1581 LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
1582 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1583 return(mStatus_BadReferenceErr
);
1586 // If this is a shared record and we've announced it at least once,
1587 // we need to retract that announcement before we delete the record
1589 // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local answers then
1590 // it's tempting to just do "AnswerLocalQuestions(m, rr, mDNSfalse)" here, but that would not not be safe.
1591 // The AnswerLocalQuestions routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
1592 // mechanism to cope with the client callback modifying the question list while that's happening.
1593 // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
1594 // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
1595 // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
1596 // records, thereby invoking yet more callbacks, without limit.
1597 // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
1598 // actual goodbye packets.
1600 #ifndef UNICAST_DISABLED
1601 if (AuthRecord_uDNS(rr
) && rr
->RequireGoodbye
)
1603 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
1604 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
1605 uDNS_DeregisterRecord(m
, rr
);
1606 // At this point unconditionally we bail out
1607 // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
1608 // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
1609 // process and will complete asynchronously. Either way we don't need to do anything more here.
1610 return(mStatus_NoError
);
1612 #endif UNICAST_DISABLED
1614 if (RecordType
== kDNSRecordTypeShared
&& (rr
->RequireGoodbye
|| rr
->AnsweredLocalQ
))
1616 verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m
, rr
));
1617 rr
->resrec
.RecordType
= kDNSRecordTypeDeregistering
;
1618 rr
->resrec
.rroriginalttl
= 0;
1619 rr
->ImmedAnswer
= mDNSInterfaceMark
;
1620 if (m
->NextScheduledResponse
- (m
->timenow
+ mDNSPlatformOneSecond
/10) >= 0)
1621 m
->NextScheduledResponse
= (m
->timenow
+ mDNSPlatformOneSecond
/10);
1625 *p
= rr
->next
; // Cut this record from the list
1626 // If someone is about to look at this, bump the pointer forward
1627 if (m
->CurrentRecord
== rr
) m
->CurrentRecord
= rr
->next
;
1628 if (m
->NewLocalRecords
== rr
) m
->NewLocalRecords
= rr
->next
;
1629 rr
->next
= mDNSNULL
;
1631 if (RecordType
== kDNSRecordTypeUnregistered
)
1632 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m
, rr
));
1633 else if (RecordType
== kDNSRecordTypeDeregistering
)
1634 LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m
, rr
));
1637 verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m
, rr
));
1638 rr
->resrec
.RecordType
= kDNSRecordTypeUnregistered
;
1641 if ((drt
== mDNS_Dereg_conflict
|| drt
== mDNS_Dereg_repeat
) && RecordType
== kDNSRecordTypeShared
)
1642 debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
1643 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1645 // If we have an update queued up which never executed, give the client a chance to free that memory
1646 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
1648 if (rr
->nta
) { CancelGetZoneData(m
, rr
->nta
); rr
->nta
= mDNSNULL
; }
1649 if (rr
->tcp
) { DisposeTCPConn(rr
->tcp
); rr
->tcp
= mDNSNULL
; }
1651 // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
1652 // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
1653 // In this case the likely client action to the mStatus_MemFree message is to free the memory,
1654 // so any attempt to touch rr after this is likely to lead to a crash.
1655 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
1656 if (drt
!= mDNS_Dereg_conflict
)
1658 if (rr
->RecordCallback
)
1659 rr
->RecordCallback(m
, rr
, mStatus_MemFree
); // MUST NOT touch rr after this
1663 RecordProbeFailure(m
, rr
);
1664 if (rr
->RecordCallback
)
1665 rr
->RecordCallback(m
, rr
, mStatus_NameConflict
); // MUST NOT touch rr after this
1666 // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
1667 // Note that with all the client callbacks going on, by the time we get here all the
1668 // records we marked may have been explicitly deregistered by the client anyway.
1669 r2
= m
->DuplicateRecords
;
1672 if (r2
->ProbeCount
!= 0xFF) r2
= r2
->next
;
1673 else { mDNS_Deregister_internal(m
, r2
, mDNS_Dereg_conflict
); r2
= m
->DuplicateRecords
; }
1676 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
1678 return(mStatus_NoError
);
1681 // ***************************************************************************
1682 #if COMPILER_LIKES_PRAGMA_MARK
1684 #pragma mark - Packet Sending Functions
1687 mDNSlocal
void AddRecordToResponseList(AuthRecord
***nrpp
, AuthRecord
*rr
, AuthRecord
*add
)
1689 if (rr
->NextResponse
== mDNSNULL
&& *nrpp
!= &rr
->NextResponse
)
1692 // NR_AdditionalTo must point to a record with NR_AnswerTo set (and not NR_AdditionalTo)
1693 // If 'add' does not meet this requirement, then follow its NR_AdditionalTo pointer to a record that does
1694 // The referenced record will definitely be acceptable (by recursive application of this rule)
1695 if (add
&& add
->NR_AdditionalTo
) add
= add
->NR_AdditionalTo
;
1696 rr
->NR_AdditionalTo
= add
;
1697 *nrpp
= &rr
->NextResponse
;
1699 debugf("AddRecordToResponseList: %##s (%s) already in list", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
1702 mDNSlocal
void AddAdditionalsToResponseList(mDNS
*const m
, AuthRecord
*ResponseRecords
, AuthRecord
***nrpp
, const mDNSInterfaceID InterfaceID
)
1704 AuthRecord
*rr
, *rr2
;
1705 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // For each record we plan to put
1707 // (Note: This is an "if", not a "while". If we add a record, we'll find it again
1708 // later in the "for" loop, and we will follow further "additional" links then.)
1709 if (rr
->Additional1
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional1
, InterfaceID
))
1710 AddRecordToResponseList(nrpp
, rr
->Additional1
, rr
);
1712 if (rr
->Additional2
&& ResourceRecordIsValidInterfaceAnswer(rr
->Additional2
, InterfaceID
))
1713 AddRecordToResponseList(nrpp
, rr
->Additional2
, rr
);
1715 // For SRV records, automatically add the Address record(s) for the target host
1716 if (rr
->resrec
.rrtype
== kDNSType_SRV
)
1718 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
1719 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
1720 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
1721 rr
->resrec
.rdatahash
== rr2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
1722 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, rr2
->resrec
.name
))
1723 AddRecordToResponseList(nrpp
, rr2
, rr
);
1725 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
)) // For A or AAAA, put counterpart as additional
1727 for (rr2
=m
->ResourceRecords
; rr2
; rr2
=rr2
->next
) // Scan list of resource records
1728 if (RRTypeIsAddressType(rr2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
1729 ResourceRecordIsValidInterfaceAnswer(rr2
, InterfaceID
) && // ... which are valid for answer ...
1730 rr
->resrec
.namehash
== rr2
->resrec
.namehash
&& // ... and have the same name
1731 SameDomainName(rr
->resrec
.name
, rr2
->resrec
.name
))
1732 AddRecordToResponseList(nrpp
, rr2
, rr
);
1734 else if (rr
->resrec
.rrtype
== kDNSType_PTR
) // For service PTR, see if we want to add DeviceInfo record
1736 if (ResourceRecordIsValidInterfaceAnswer(&m
->DeviceInfo
, InterfaceID
) &&
1737 SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
1738 AddRecordToResponseList(nrpp
, &m
->DeviceInfo
, rr
);
1743 mDNSlocal
void SendDelayedUnicastResponse(mDNS
*const m
, const mDNSAddr
*const dest
, const mDNSInterfaceID InterfaceID
)
1746 AuthRecord
*ResponseRecords
= mDNSNULL
;
1747 AuthRecord
**nrp
= &ResponseRecords
;
1749 // Make a list of all our records that need to be unicast to this destination
1750 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1752 // If we find we can no longer unicast this answer, clear ImmedUnicast
1753 if (rr
->ImmedAnswer
== mDNSInterfaceMark
||
1754 mDNSSameIPv4Address(rr
->v4Requester
, onesIPv4Addr
) ||
1755 mDNSSameIPv6Address(rr
->v6Requester
, onesIPv6Addr
) )
1756 rr
->ImmedUnicast
= mDNSfalse
;
1758 if (rr
->ImmedUnicast
&& rr
->ImmedAnswer
== InterfaceID
)
1759 if ((dest
->type
== mDNSAddrType_IPv4
&& mDNSSameIPv4Address(rr
->v4Requester
, dest
->ip
.v4
)) ||
1760 (dest
->type
== mDNSAddrType_IPv6
&& mDNSSameIPv6Address(rr
->v6Requester
, dest
->ip
.v6
)))
1762 rr
->ImmedAnswer
= mDNSNULL
; // Clear the state fields
1763 rr
->ImmedUnicast
= mDNSfalse
;
1764 rr
->v4Requester
= zerov4Addr
;
1765 rr
->v6Requester
= zerov6Addr
;
1766 if (rr
->NextResponse
== mDNSNULL
&& nrp
!= &rr
->NextResponse
) // rr->NR_AnswerTo
1767 { rr
->NR_AnswerTo
= (mDNSu8
*)~0; *nrp
= rr
; nrp
= &rr
->NextResponse
; }
1771 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
1773 while (ResponseRecords
)
1775 mDNSu8
*responseptr
= m
->omsg
.data
;
1777 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
1779 // Put answers in the packet
1780 while (ResponseRecords
&& ResponseRecords
->NR_AnswerTo
)
1782 rr
= ResponseRecords
;
1783 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
1784 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
1785 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
1786 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
1787 if (!newptr
&& m
->omsg
.h
.numAnswers
) break; // If packet full, send it now
1788 if (newptr
) responseptr
= newptr
;
1789 ResponseRecords
= rr
->NextResponse
;
1790 rr
->NextResponse
= mDNSNULL
;
1791 rr
->NR_AnswerTo
= mDNSNULL
;
1792 rr
->NR_AdditionalTo
= mDNSNULL
;
1793 rr
->RequireGoodbye
= mDNStrue
;
1796 // Add additionals, if there's space
1797 while (ResponseRecords
&& !ResponseRecords
->NR_AnswerTo
)
1799 rr
= ResponseRecords
;
1800 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
1801 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
1802 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
1803 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
1805 if (newptr
) responseptr
= newptr
;
1806 if (newptr
&& m
->omsg
.h
.numAnswers
) rr
->RequireGoodbye
= mDNStrue
;
1807 else if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
) rr
->ImmedAnswer
= mDNSInterfaceMark
;
1808 ResponseRecords
= rr
->NextResponse
;
1809 rr
->NextResponse
= mDNSNULL
;
1810 rr
->NR_AnswerTo
= mDNSNULL
;
1811 rr
->NR_AdditionalTo
= mDNSNULL
;
1814 if (m
->omsg
.h
.numAnswers
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, mDNSInterface_Any
, mDNSNULL
, dest
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
1818 mDNSexport
void CompleteDeregistration(mDNS
*const m
, AuthRecord
*rr
)
1820 // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
1821 // it should go ahead and immediately dispose of this registration
1822 rr
->resrec
.RecordType
= kDNSRecordTypeShared
;
1823 rr
->RequireGoodbye
= mDNSfalse
;
1824 if (rr
->AnsweredLocalQ
) { AnswerLocalQuestions(m
, rr
, mDNSfalse
); rr
->AnsweredLocalQ
= mDNSfalse
; }
1825 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
); // Don't touch rr after this
1828 // NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
1829 // the record list and/or question list.
1830 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1831 mDNSlocal
void DiscardDeregistrations(mDNS
*const m
)
1833 if (m
->CurrentRecord
)
1834 LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
1835 m
->CurrentRecord
= m
->ResourceRecords
;
1837 while (m
->CurrentRecord
)
1839 AuthRecord
*rr
= m
->CurrentRecord
;
1840 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
1841 CompleteDeregistration(m
, rr
); // Don't touch rr after this
1843 m
->CurrentRecord
= rr
->next
;
1847 mDNSlocal
void GrantUpdateCredit(AuthRecord
*rr
)
1849 if (++rr
->UpdateCredits
>= kMaxUpdateCredits
) rr
->NextUpdateCredit
= 0;
1850 else rr
->NextUpdateCredit
= NonZeroTime(rr
->NextUpdateCredit
+ kUpdateCreditRefreshInterval
);
1853 // Note about acceleration of announcements to facilitate automatic coalescing of
1854 // multiple independent threads of announcements into a single synchronized thread:
1855 // The announcements in the packet may be at different stages of maturity;
1856 // One-second interval, two-second interval, four-second interval, and so on.
1857 // After we've put in all the announcements that are due, we then consider
1858 // whether there are other nearly-due announcements that are worth accelerating.
1859 // To be eligible for acceleration, a record MUST NOT be older (further along
1860 // its timeline) than the most mature record we've already put in the packet.
1861 // In other words, younger records can have their timelines accelerated to catch up
1862 // with their elder bretheren; this narrows the age gap and helps them eventually get in sync.
1863 // Older records cannot have their timelines accelerated; this would just widen
1864 // the gap between them and their younger bretheren and get them even more out of sync.
1866 // NOTE: SendResponses calls mDNS_Deregister_internal which can call a user callback, which may change
1867 // the record list and/or question list.
1868 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
1869 mDNSlocal
void SendResponses(mDNS
*const m
)
1872 AuthRecord
*rr
, *r2
;
1873 mDNSs32 maxExistingAnnounceInterval
= 0;
1874 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
1876 m
->NextScheduledResponse
= m
->timenow
+ 0x78000000;
1878 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1879 if (rr
->ImmedUnicast
)
1881 mDNSAddr v4
= { mDNSAddrType_IPv4
, {{{0}}} };
1882 mDNSAddr v6
= { mDNSAddrType_IPv6
, {{{0}}} };
1883 v4
.ip
.v4
= rr
->v4Requester
;
1884 v6
.ip
.v6
= rr
->v6Requester
;
1885 if (!mDNSIPv4AddressIsZero(rr
->v4Requester
)) SendDelayedUnicastResponse(m
, &v4
, rr
->ImmedAnswer
);
1886 if (!mDNSIPv6AddressIsZero(rr
->v6Requester
)) SendDelayedUnicastResponse(m
, &v6
, rr
->ImmedAnswer
);
1887 if (rr
->ImmedUnicast
)
1889 LogMsg("SendResponses: ERROR: rr->ImmedUnicast still set: %s", ARDisplayString(m
, rr
));
1890 rr
->ImmedUnicast
= mDNSfalse
;
1895 // *** 1. Setup: Set the SendRNow and ImmedAnswer fields to indicate which interface(s) the records need to be sent on
1898 // Run through our list of records, and decide which ones we're going to announce on all interfaces
1899 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1901 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
1902 if (TimeToAnnounceThisRecord(rr
, m
->timenow
) && ResourceRecordIsValidAnswer(rr
))
1904 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
1905 if (maxExistingAnnounceInterval
< rr
->ThisAPInterval
)
1906 maxExistingAnnounceInterval
= rr
->ThisAPInterval
;
1907 if (rr
->UpdateBlocked
) rr
->UpdateBlocked
= 0;
1911 // Any interface-specific records we're going to send are marked as being sent on all appropriate interfaces (which is just one)
1912 // Eligible records that are more than half-way to their announcement time are accelerated
1913 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1914 if ((rr
->resrec
.InterfaceID
&& rr
->ImmedAnswer
) ||
1915 (rr
->ThisAPInterval
<= maxExistingAnnounceInterval
&&
1916 TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2) &&
1917 ResourceRecordIsValidAnswer(rr
)))
1918 rr
->ImmedAnswer
= mDNSInterfaceMark
; // Send on all interfaces
1920 // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals
1921 // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID,
1922 // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
1923 // then all that means is that it won't get sent -- which would not be the end of the world.
1924 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1926 if (rr
->ImmedAnswer
&& rr
->resrec
.rrtype
== kDNSType_SRV
)
1927 for (r2
=m
->ResourceRecords
; r2
; r2
=r2
->next
) // Scan list of resource records
1928 if (RRTypeIsAddressType(r2
->resrec
.rrtype
) && // For all address records (A/AAAA) ...
1929 ResourceRecordIsValidAnswer(r2
) && // ... which are valid for answer ...
1930 rr
->LastMCTime
- r2
->LastMCTime
>= 0 && // ... which we have not sent recently ...
1931 rr
->resrec
.rdatahash
== r2
->resrec
.namehash
&& // ... whose name is the name of the SRV target
1932 SameDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, r2
->resrec
.name
) &&
1933 (rr
->ImmedAnswer
== mDNSInterfaceMark
|| rr
->ImmedAnswer
== r2
->resrec
.InterfaceID
))
1934 r2
->ImmedAdditional
= r2
->resrec
.InterfaceID
; // ... then mark this address record for sending too
1935 // We also make sure we send the DeviceInfo TXT record too, if necessary
1936 // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
1937 // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
1938 if (rr
->ImmedAnswer
&& rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->resrec
.rrtype
== kDNSType_PTR
)
1939 if (ResourceRecordIsValidAnswer(&m
->DeviceInfo
) && SameDomainLabel(rr
->resrec
.rdata
->u
.name
.c
, m
->DeviceInfo
.resrec
.name
->c
))
1941 if (!m
->DeviceInfo
.ImmedAnswer
) m
->DeviceInfo
.ImmedAnswer
= rr
->ImmedAnswer
;
1942 else m
->DeviceInfo
.ImmedAnswer
= mDNSInterfaceMark
;
1946 // If there's a record which is supposed to be unique that we're going to send, then make sure that we give
1947 // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
1948 // then we need to mark them for sending too. Otherwise, if we set the kDNSClass_UniqueRRSet bit on a
1949 // record, then other RRSet members that have not been sent recently will get flushed out of client caches.
1950 // -- 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
1951 // -- If any record is marked to be sent on all interfaces, make sure the whole set is marked to be sent on all interfaces
1952 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1953 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
1955 if (rr
->ImmedAnswer
) // If we're sending this as answer, see that its whole RRSet is similarly marked
1957 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
1958 if (ResourceRecordIsValidAnswer(r2
))
1959 if (r2
->ImmedAnswer
!= mDNSInterfaceMark
&&
1960 r2
->ImmedAnswer
!= rr
->ImmedAnswer
&& SameResourceRecordSignature(r2
, rr
))
1961 r2
->ImmedAnswer
= rr
->ImmedAnswer
;
1963 else if (rr
->ImmedAdditional
) // If we're sending this as additional, see that its whole RRSet is similarly marked
1965 for (r2
= m
->ResourceRecords
; r2
; r2
=r2
->next
)
1966 if (ResourceRecordIsValidAnswer(r2
))
1967 if (r2
->ImmedAdditional
!= rr
->ImmedAdditional
&& SameResourceRecordSignature(r2
, rr
))
1968 r2
->ImmedAdditional
= rr
->ImmedAdditional
;
1972 // Now set SendRNow state appropriately
1973 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
1975 if (rr
->ImmedAnswer
== mDNSInterfaceMark
) // Sending this record on all appropriate interfaces
1977 rr
->SendRNow
= !intf
? mDNSNULL
: (rr
->resrec
.InterfaceID
) ? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
1978 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional if sending as answer
1979 rr
->LastMCTime
= m
->timenow
;
1980 rr
->LastMCInterface
= rr
->ImmedAnswer
;
1981 // If we're announcing this record, and it's at least half-way to its ordained time, then consider this announcement done
1982 if (TimeToAnnounceThisRecord(rr
, m
->timenow
+ rr
->ThisAPInterval
/2))
1984 rr
->AnnounceCount
--;
1985 rr
->ThisAPInterval
*= 2;
1986 rr
->LastAPTime
= m
->timenow
;
1987 debugf("Announcing %##s (%s) %d", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->AnnounceCount
);
1990 else if (rr
->ImmedAnswer
) // Else, just respond to a single query on single interface:
1992 rr
->SendRNow
= rr
->ImmedAnswer
; // Just respond on that interface
1993 rr
->ImmedAdditional
= mDNSNULL
; // No need to send as additional too
1994 rr
->LastMCTime
= m
->timenow
;
1995 rr
->LastMCInterface
= rr
->ImmedAnswer
;
1997 SetNextAnnounceProbeTime(m
, rr
);
1998 //if (rr->SendRNow) LogMsg("%-15.4a %s", &rr->v4Requester, ARDisplayString(m, rr));
2002 // *** 2. Loop through interface list, sending records as appropriate
2008 int numAnnounce
= 0;
2010 mDNSu8
*responseptr
= m
->omsg
.data
;
2012 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, ResponseFlags
);
2014 // First Pass. Look for:
2015 // 1. Deregistering records that need to send their goodbye packet
2016 // 2. Updated records that need to retract their old data
2017 // 3. Answers and announcements we need to send
2018 // In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can
2019 // send this packet and then try again.
2020 // If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway,
2021 // because otherwise we'll end up in an infinite loop trying to send a record that will never fit.
2022 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2023 if (rr
->SendRNow
== intf
->InterfaceID
)
2025 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2027 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2028 if (newptr
) { responseptr
= newptr
; numDereg
++; }
2029 else if (m
->omsg
.h
.numAnswers
) break;
2031 else if (rr
->NewRData
&& !m
->SleepState
) // If we have new data for this record
2033 RData
*OldRData
= rr
->resrec
.rdata
;
2034 mDNSu16 oldrdlength
= rr
->resrec
.rdlength
;
2035 // See if we should send a courtesy "goodbye" for the old data before we replace it.
2036 if (ResourceRecordIsValidAnswer(rr
) && rr
->RequireGoodbye
)
2038 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, 0);
2039 if (newptr
) { responseptr
= newptr
; numDereg
++; rr
->RequireGoodbye
= mDNSfalse
; }
2040 else if (m
->omsg
.h
.numAnswers
) break;
2042 // Now try to see if we can fit the update in the same packet (not fatal if we can't)
2043 SetNewRData(&rr
->resrec
, rr
->NewRData
, rr
->newrdlength
);
2044 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2045 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2046 newptr
= PutResourceRecord(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
);
2047 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2048 if (newptr
) { responseptr
= newptr
; rr
->RequireGoodbye
= mDNStrue
; }
2049 SetNewRData(&rr
->resrec
, OldRData
, oldrdlength
);
2053 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2054 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2055 newptr
= PutResourceRecordTTL(&m
->omsg
, responseptr
, &m
->omsg
.h
.numAnswers
, &rr
->resrec
, m
->SleepState
? 0 : rr
->resrec
.rroriginalttl
);
2056 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2059 responseptr
= newptr
;
2060 rr
->RequireGoodbye
= (mDNSu8
) (!m
->SleepState
);
2061 if (rr
->LastAPTime
== m
->timenow
) numAnnounce
++; else numAnswer
++;
2063 else if (m
->omsg
.h
.numAnswers
) break;
2065 // If sending on all interfaces, go to next interface; else we're finished now
2066 if (rr
->ImmedAnswer
== mDNSInterfaceMark
&& rr
->resrec
.InterfaceID
== mDNSInterface_Any
)
2067 rr
->SendRNow
= GetNextActiveInterfaceID(intf
);
2069 rr
->SendRNow
= mDNSNULL
;
2072 // Second Pass. Add additional records, if there's space.
2073 newptr
= responseptr
;
2074 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2075 if (rr
->ImmedAdditional
== intf
->InterfaceID
)
2076 if (ResourceRecordIsValidAnswer(rr
))
2078 // If we have at least one answer already in the packet, then plan to add additionals too
2079 mDNSBool SendAdditional
= (m
->omsg
.h
.numAnswers
> 0);
2081 // If we're not planning to send any additionals, but this record is a unique one, then
2082 // make sure we haven't already sent any other members of its RRSet -- if we have, then they
2083 // will have had the cache flush bit set, so now we need to finish the job and send the rest.
2084 if (!SendAdditional
&& (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
))
2086 const AuthRecord
*a
;
2087 for (a
= m
->ResourceRecords
; a
; a
=a
->next
)
2088 if (a
->LastMCTime
== m
->timenow
&&
2089 a
->LastMCInterface
== intf
->InterfaceID
&&
2090 SameResourceRecordSignature(a
, rr
)) { SendAdditional
= mDNStrue
; break; }
2092 if (!SendAdditional
) // If we don't want to send this after all,
2093 rr
->ImmedAdditional
= mDNSNULL
; // then cancel its ImmedAdditional field
2094 else if (newptr
) // Else, try to add it if we can
2096 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
2097 rr
->resrec
.rrclass
|= kDNSClass_UniqueRRSet
; // Temporarily set the cache flush bit so PutResourceRecord will set it
2098 newptr
= PutResourceRecord(&m
->omsg
, newptr
, &m
->omsg
.h
.numAdditionals
, &rr
->resrec
);
2099 rr
->resrec
.rrclass
&= ~kDNSClass_UniqueRRSet
; // Make sure to clear cache flush bit back to normal state
2102 responseptr
= newptr
;
2103 rr
->ImmedAdditional
= mDNSNULL
;
2104 rr
->RequireGoodbye
= mDNStrue
;
2105 // If we successfully put this additional record in the packet, we record LastMCTime & LastMCInterface.
2106 // This matters particularly in the case where we have more than one IPv6 (or IPv4) address, because otherwise,
2107 // when we see our own multicast with the cache flush bit set, if we haven't set LastMCTime, then we'll get
2108 // all concerned and re-announce our record again to make sure it doesn't get flushed from peer caches.
2109 rr
->LastMCTime
= m
->timenow
;
2110 rr
->LastMCInterface
= intf
->InterfaceID
;
2115 if (m
->omsg
.h
.numAnswers
> 0 || m
->omsg
.h
.numAdditionals
)
2117 debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
2118 numDereg
, numDereg
== 1 ? "" : "s",
2119 numAnnounce
, numAnnounce
== 1 ? "" : "s",
2120 numAnswer
, numAnswer
== 1 ? "" : "s",
2121 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s", intf
->InterfaceID
);
2122 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2123 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, responseptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2124 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
2125 if (++pktcount
>= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount
); break; }
2126 // There might be more things to send on this interface, so go around one more time and try again.
2128 else // Nothing more to send on this interface; go to next
2130 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
2131 #if MDNS_DEBUGMSGS && 0
2132 const char *const msg
= next
? "SendResponses: Nothing more on %p; moving to %p" : "SendResponses: Nothing more on %p";
2133 debugf(msg
, intf
, next
);
2140 // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
2143 if (m
->CurrentRecord
)
2144 LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
2145 m
->CurrentRecord
= m
->ResourceRecords
;
2146 while (m
->CurrentRecord
)
2148 rr
= m
->CurrentRecord
;
2149 m
->CurrentRecord
= rr
->next
;
2153 if (rr
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
2154 LogMsg("SendResponses: No active interface to send: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
2155 rr
->SendRNow
= mDNSNULL
;
2158 if (rr
->ImmedAnswer
)
2160 if (rr
->NewRData
) CompleteRDataUpdate(m
, rr
); // Update our rdata, clear the NewRData pointer, and return memory to the client
2162 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2163 CompleteDeregistration(m
, rr
); // Don't touch rr after this
2166 rr
->ImmedAnswer
= mDNSNULL
;
2167 rr
->ImmedUnicast
= mDNSfalse
;
2168 rr
->v4Requester
= zerov4Addr
;
2169 rr
->v6Requester
= zerov6Addr
;
2173 verbosedebugf("SendResponses: Next in %ld ticks", m
->NextScheduledResponse
- m
->timenow
);
2176 // Calling CheckCacheExpiration() is an expensive operation because it has to look at the entire cache,
2177 // so we want to be lazy about how frequently we do it.
2178 // 1. If a cache record is currently referenced by *no* active questions,
2179 // then we don't mind expiring it up to a minute late (who will know?)
2180 // 2. Else, if a cache record is due for some of its final expiration queries,
2181 // we'll allow them to be late by up to 2% of the TTL
2182 // 3. Else, if a cache record has completed all its final expiration queries without success,
2183 // and is expiring, and had an original TTL more than ten seconds, we'll allow it to be one second late
2184 // 4. Else, it is expiring and had an original TTL of ten seconds or less (includes explicit goodbye packets),
2185 // so allow at most 1/10 second lateness
2186 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
2187 // (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
2188 #define CacheCheckGracePeriod(RR) ( \
2189 ((RR)->DelayDelivery ) ? (mDNSPlatformOneSecond/10) : \
2190 ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
2191 ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
2192 ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
2193 ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
2195 // Note: MUST call SetNextCacheCheckTime any time we change:
2197 // rr->resrec.rroriginalttl
2198 // rr->UnansweredQueries
2199 // rr->CRActiveQuestion
2200 // Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
2201 // Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
2202 mDNSlocal
void SetNextCacheCheckTime(mDNS
*const m
, CacheRecord
*const rr
)
2204 rr
->NextRequiredQuery
= RRExpireTime(rr
);
2206 // If we have an active question, then see if we want to schedule a refresher query for this record.
2207 // Usually we expect to do four queries, at 80-82%, 85-87%, 90-92% and then 95-97% of the TTL.
2208 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
2210 rr
->NextRequiredQuery
-= TicksTTL(rr
)/20 * (MaxUnansweredQueries
- rr
->UnansweredQueries
);
2211 rr
->NextRequiredQuery
+= mDNSRandom((mDNSu32
)TicksTTL(rr
)/50);
2212 verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
2213 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
),
2214 (rr
->NextRequiredQuery
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
));
2217 if (m
->NextCacheCheck
- (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
)) > 0)
2218 m
->NextCacheCheck
= (rr
->NextRequiredQuery
+ CacheCheckGracePeriod(rr
));
2220 if (rr
->DelayDelivery
)
2221 if (m
->NextCacheCheck
- rr
->DelayDelivery
> 0)
2222 m
->NextCacheCheck
= rr
->DelayDelivery
;
2225 #define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
2226 #define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
2227 #define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
2228 #define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
2230 mDNSlocal mStatus
mDNS_Reconfirm_internal(mDNS
*const m
, CacheRecord
*const rr
, mDNSu32 interval
)
2232 if (interval
< kMinimumReconfirmTime
)
2233 interval
= kMinimumReconfirmTime
;
2234 if (interval
> 0x10000000) // Make sure interval doesn't overflow when we multiply by four below
2235 interval
= 0x10000000;
2237 // If the expected expiration time for this record is more than interval+33%, then accelerate its expiration
2238 if (RRExpireTime(rr
) - m
->timenow
> (mDNSs32
)((interval
* 4) / 3))
2240 // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
2241 // For all the reconfirmations in a given batch, we want to use the same random value
2242 // so that the reconfirmation questions can be grouped into a single query packet
2243 if (!m
->RandomReconfirmDelay
) m
->RandomReconfirmDelay
= 1 + mDNSRandom(0x3FFFFFFF);
2244 interval
+= mDNSRandomFromFixedSeed(m
->RandomReconfirmDelay
, interval
/3);
2245 rr
->TimeRcvd
= m
->timenow
- (mDNSs32
)interval
* 3;
2246 rr
->resrec
.rroriginalttl
= (interval
* 4 + mDNSPlatformOneSecond
- 1) / mDNSPlatformOneSecond
;
2247 SetNextCacheCheckTime(m
, rr
);
2249 debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
2250 RRExpireTime(rr
) - m
->timenow
, CRDisplayString(m
, rr
), rr
->CRActiveQuestion
);
2251 return(mStatus_NoError
);
2254 #define MaxQuestionInterval (3600 * mDNSPlatformOneSecond)
2256 // BuildQuestion puts a question into a DNS Query packet and if successful, updates the value of queryptr.
2257 // It also appends to the list of known answer records that need to be included,
2258 // and updates the forcast for the size of the known answer section.
2259 mDNSlocal mDNSBool
BuildQuestion(mDNS
*const m
, DNSMessage
*query
, mDNSu8
**queryptr
, DNSQuestion
*q
,
2260 CacheRecord
***kalistptrptr
, mDNSu32
*answerforecast
)
2262 mDNSBool ucast
= (q
->LargeAnswers
|| q
->RequestUnicast
) && m
->CanReceiveUnicastOn5353
;
2263 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
2264 const mDNSu8
*const limit
= query
->data
+ NormalMaxDNSMessageData
;
2265 mDNSu8
*newptr
= putQuestion(query
, *queryptr
, limit
, &q
->qname
, q
->qtype
, (mDNSu16
)(q
->qclass
| ucbit
));
2268 debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2271 else if (newptr
+ *answerforecast
>= limit
)
2273 verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
2274 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ *answerforecast
- query
->data
);
2275 query
->h
.numQuestions
--;
2280 mDNSu32 forecast
= *answerforecast
;
2281 const mDNSu32 slot
= HashSlot(&q
->qname
);
2282 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
2284 CacheRecord
**ka
= *kalistptrptr
; // Make a working copy of the pointer we're going to update
2286 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
2287 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
2288 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not already in the known answer list
2289 rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
2290 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
2291 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
> // and its half-way-to-expiry time is at least 1 second away
2292 mDNSPlatformOneSecond
) // (also ensures we never include goodbye records with TTL=1)
2294 *ka
= rr
; // Link this record into our known answer chain
2295 ka
= &rr
->NextInKAList
;
2296 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2297 forecast
+= 12 + rr
->resrec
.rdestimate
;
2298 // If we're trying to put more than one question in this packet, and it doesn't fit
2299 // then undo that last question and try again next time
2300 if (query
->h
.numQuestions
> 1 && newptr
+ forecast
>= limit
)
2302 debugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
2303 q
->qname
.c
, DNSTypeName(q
->qtype
), newptr
+ forecast
- query
->data
);
2304 query
->h
.numQuestions
--;
2305 ka
= *kalistptrptr
; // Go back to where we started and retract these answer records
2306 while (*ka
) { CacheRecord
*c
= *ka
; *ka
= mDNSNULL
; ka
= &c
->NextInKAList
; }
2307 return(mDNSfalse
); // Return false, so we'll try again in the next packet
2311 // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
2312 *queryptr
= newptr
; // Update the packet pointer
2313 *answerforecast
= forecast
; // Update the forecast
2314 *kalistptrptr
= ka
; // Update the known answer list pointer
2315 if (ucast
) q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
2317 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // For every resource record in our cache,
2318 if (rr
->resrec
.InterfaceID
== q
->SendQNow
&& // received on this interface
2319 rr
->NextInKAList
== mDNSNULL
&& ka
!= &rr
->NextInKAList
&& // which is not in the known answer list
2320 SameNameRecordAnswersQuestion(&rr
->resrec
, q
)) // which answers our question
2322 rr
->UnansweredQueries
++; // indicate that we're expecting a response
2323 rr
->LastUnansweredTime
= m
->timenow
;
2324 SetNextCacheCheckTime(m
, rr
);
2331 // When we have a query looking for a specified name, but there appear to be no answers with
2332 // that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
2333 // for any records in our cache that reference the given name (e.g. PTR and SRV records).
2334 // For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
2335 // We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
2336 // A typical reconfirmation scenario might go like this:
2337 // Depth 0: Name "myhost.local" has no address records
2338 // Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
2339 // Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
2340 // Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
2341 // Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
2342 // found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
2343 mDNSlocal
void ReconfirmAntecedents(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const int depth
)
2348 debugf("ReconfirmAntecedents (depth=%d) for %##s", depth
, name
->c
);
2349 FORALL_CACHERECORDS(slot
, cg
, cr
)
2351 domainname
*crtarget
= GetRRDomainNameTarget(&cr
->resrec
);
2352 if (crtarget
&& cr
->resrec
.rdatahash
== namehash
&& SameDomainName(crtarget
, name
))
2354 LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth
, CRDisplayString(m
, cr
));
2355 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
2356 if (depth
< 5) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, depth
+1);
2361 // If we get no answer for a AAAA query, then before doing an automatic implicit ReconfirmAntecedents
2362 // we check if we have an address record for the same name. If we do have an IPv4 address for a given
2363 // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure
2364 // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
2365 mDNSlocal CacheRecord
*CacheHasAddressTypeForName(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
)
2367 CacheGroup
*const cg
= CacheGroupForName(m
, HashSlot(name
), namehash
, name
);
2368 CacheRecord
*cr
= cg
? cg
->members
: mDNSNULL
;
2369 while (cr
&& !RRTypeIsAddressType(cr
->resrec
.rrtype
)) cr
=cr
->next
;
2373 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
2374 mDNSlocal
void ExpireDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
)
2377 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
2380 mDNSlocal
void ExpireDupSuppressInfoOnInterface(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 time
, mDNSInterfaceID InterfaceID
)
2383 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Time
- time
< 0) ds
[i
].InterfaceID
= mDNSNULL
;
2386 mDNSlocal mDNSBool
SuppressOnThisInterface(const DupSuppressInfo ds
[DupSuppressInfoSize
], const NetworkInterfaceInfo
* const intf
)
2389 mDNSBool v4
= !intf
->IPv4Available
; // If this interface doesn't do v4, we don't need to find a v4 duplicate of this query
2390 mDNSBool v6
= !intf
->IPv6Available
; // If this interface doesn't do v6, we don't need to find a v6 duplicate of this query
2391 for (i
=0; i
<DupSuppressInfoSize
; i
++)
2392 if (ds
[i
].InterfaceID
== intf
->InterfaceID
)
2394 if (ds
[i
].Type
== mDNSAddrType_IPv4
) v4
= mDNStrue
;
2395 else if (ds
[i
].Type
== mDNSAddrType_IPv6
) v6
= mDNStrue
;
2396 if (v4
&& v6
) return(mDNStrue
);
2401 mDNSlocal
int RecordDupSuppressInfo(DupSuppressInfo ds
[DupSuppressInfoSize
], mDNSs32 Time
, mDNSInterfaceID InterfaceID
, mDNSs32 Type
)
2405 // See if we have this one in our list somewhere already
2406 for (i
=0; i
<DupSuppressInfoSize
; i
++) if (ds
[i
].InterfaceID
== InterfaceID
&& ds
[i
].Type
== Type
) break;
2408 // If not, find a slot we can re-use
2409 if (i
>= DupSuppressInfoSize
)
2412 for (j
=1; j
<DupSuppressInfoSize
&& ds
[i
].InterfaceID
; j
++)
2413 if (!ds
[j
].InterfaceID
|| ds
[j
].Time
- ds
[i
].Time
< 0)
2417 // Record the info about this query we saw
2419 ds
[i
].InterfaceID
= InterfaceID
;
2425 mDNSlocal mDNSBool
AccelerateThisQuery(mDNS
*const m
, DNSQuestion
*q
)
2427 // If more than 90% of the way to the query time, we should unconditionally accelerate it
2428 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/10))
2431 // If half-way to next scheduled query time, only accelerate if it will add less than 512 bytes to the packet
2432 if (TimeToSendThisQuestion(q
, m
->timenow
+ q
->ThisQInterval
/2))
2434 // We forecast: qname (n) type (2) class (2)
2435 mDNSu32 forecast
= (mDNSu32
)DomainNameLength(&q
->qname
) + 4;
2436 const mDNSu32 slot
= HashSlot(&q
->qname
);
2437 const CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
2439 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
) // If we have a resource record in our cache,
2440 if (rr
->resrec
.rdlength
<= SmallRecordLimit
&& // which is small enough to sensibly fit in the packet
2441 SameNameRecordAnswersQuestion(&rr
->resrec
, q
) && // which answers our question
2442 rr
->TimeRcvd
+ TicksTTL(rr
)/2 - m
->timenow
>= 0 && // and it is less than half-way to expiry
2443 rr
->NextRequiredQuery
- (m
->timenow
+ q
->ThisQInterval
) > 0)// and we'll ask at least once again before NextRequiredQuery
2445 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2446 forecast
+= 12 + rr
->resrec
.rdestimate
;
2447 if (forecast
>= 512) return(mDNSfalse
); // If this would add 512 bytes or more to the packet, don't accelerate
2455 // How Standard Queries are generated:
2456 // 1. The Question Section contains the question
2457 // 2. The Additional Section contains answers we already know, to suppress duplicate responses
2459 // How Probe Queries are generated:
2460 // 1. The Question Section contains queries for the name we intend to use, with QType=ANY because
2461 // if some other host is already using *any* records with this name, we want to know about it.
2462 // 2. The Authority Section contains the proposed values we intend to use for one or more
2463 // of our records with that name (analogous to the Update section of DNS Update packets)
2464 // because if some other host is probing at the same time, we each want to know what the other is
2465 // planning, in order to apply the tie-breaking rule to see who gets to use the name and who doesn't.
2467 mDNSlocal
void SendQueries(mDNS
*const m
)
2475 // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
2476 mDNSs32 maxExistingQuestionInterval
= 0;
2477 const NetworkInterfaceInfo
*intf
= GetFirstActiveInterface(m
->HostInterfaces
);
2478 CacheRecord
*KnownAnswerList
= mDNSNULL
;
2480 // 1. If time for a query, work out what we need to do
2481 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2485 // We're expecting to send a query anyway, so see if any expiring cache records are close enough
2486 // to their NextRequiredQuery to be worth batching them together with this one
2487 FORALL_CACHERECORDS(slot
, cg
, rr
)
2488 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
2489 if (m
->timenow
+ TicksTTL(rr
)/50 - rr
->NextRequiredQuery
>= 0)
2491 LogOperation("Sending %d%% cache expiration query for %s", 80 + 5 * rr
->UnansweredQueries
, CRDisplayString(m
, rr
));
2492 q
= rr
->CRActiveQuestion
;
2493 ExpireDupSuppressInfoOnInterface(q
->DupSuppress
, m
->timenow
- TicksTTL(rr
)/20, rr
->resrec
.InterfaceID
);
2494 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
2495 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
2496 if (q
->Target
.type
) q
->SendQNow
= mDNSInterfaceMark
; // If targeted query, mark it
2497 else if (!mDNSOpaque16IsZero(q
->TargetQID
)) { q
->LastQTime
= m
->timenow
- q
->ThisQInterval
; rr
->UnansweredQueries
++; }
2498 else if (q
->SendQNow
== mDNSNULL
) q
->SendQNow
= rr
->resrec
.InterfaceID
;
2499 else if (q
->SendQNow
!= rr
->resrec
.InterfaceID
) q
->SendQNow
= mDNSInterfaceMark
;
2502 if (m
->SuppressStdPort53Queries
&& m
->timenow
- m
->SuppressStdPort53Queries
>= 0)
2503 m
->SuppressStdPort53Queries
= 0; // If suppression time has passed, clear it
2505 // Scan our list of questions to see which:
2506 // *WideArea* queries need to be sent
2507 // *unicast* queries need to be sent
2508 // *multicast* queries we're definitely going to send
2509 if (m
->CurrentQuestion
)
2510 LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
2511 m
->CurrentQuestion
= m
->Questions
;
2512 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
2514 q
= m
->CurrentQuestion
;
2515 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
)) uDNS_CheckCurrentQuestion(m
);
2516 else if (mDNSOpaque16IsZero(q
->TargetQID
) && q
->Target
.type
&& (q
->SendQNow
|| TimeToSendThisQuestion(q
, m
->timenow
)))
2518 mDNSu8
*qptr
= m
->omsg
.data
;
2519 const mDNSu8
*const limit
= m
->omsg
.data
+ sizeof(m
->omsg
.data
);
2520 InitializeDNSMessage(&m
->omsg
.h
, q
->TargetQID
, QueryFlags
);
2521 qptr
= putQuestion(&m
->omsg
, qptr
, limit
, &q
->qname
, q
->qtype
, q
->qclass
);
2522 mDNSSendDNSMessage(m
, &m
->omsg
, qptr
, mDNSInterface_Any
, q
->LocalSocket
, &q
->Target
, q
->TargetPort
, mDNSNULL
, mDNSNULL
);
2523 q
->ThisQInterval
*= QuestionIntervalStep
;
2524 if (q
->ThisQInterval
> MaxQuestionInterval
)
2525 q
->ThisQInterval
= MaxQuestionInterval
;
2526 q
->LastQTime
= m
->timenow
;
2527 q
->LastQTxTime
= m
->timenow
;
2528 q
->RecentAnswerPkts
= 0;
2529 q
->SendQNow
= mDNSNULL
;
2530 q
->ExpectUnicastResp
= NonZeroTime(m
->timenow
);
2532 else if (mDNSOpaque16IsZero(q
->TargetQID
) && !q
->Target
.type
&& TimeToSendThisQuestion(q
, m
->timenow
))
2534 //LogOperation("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
2535 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
2536 if (maxExistingQuestionInterval
< q
->ThisQInterval
)
2537 maxExistingQuestionInterval
= q
->ThisQInterval
;
2539 // If m->CurrentQuestion wasn't modified out from under us, advance it now
2540 // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
2541 // m->CurrentQuestion point to the right question
2542 if (q
== m
->CurrentQuestion
) m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
2544 m
->CurrentQuestion
= mDNSNULL
;
2546 // Scan our list of questions
2547 // (a) to see if there are any more that are worth accelerating, and
2548 // (b) to update the state variables for *all* the questions we're going to send
2549 // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
2550 // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
2551 // 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.
2552 m
->NextScheduledQuery
= m
->timenow
+ 0x78000000;
2553 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
2555 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
||
2556 (!q
->Target
.type
&& ActiveQuestion(q
) && q
->ThisQInterval
<= maxExistingQuestionInterval
&& AccelerateThisQuery(m
,q
))))
2558 // If at least halfway to next query time, advance to next interval
2559 // If less than halfway to next query time, then
2560 // treat this as logically a repeat of the last transmission, without advancing the interval
2561 if (m
->timenow
- (q
->LastQTime
+ q
->ThisQInterval
/2) >= 0)
2563 //LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
2564 q
->SendQNow
= mDNSInterfaceMark
; // Mark this question for sending on all interfaces
2565 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
2566 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->ThisQInterval
/ InitialQuestionInterval
, q
->RequestUnicast
);
2567 q
->ThisQInterval
*= QuestionIntervalStep
;
2568 if (q
->ThisQInterval
> MaxQuestionInterval
)
2569 q
->ThisQInterval
= MaxQuestionInterval
;
2570 else if (q
->CurrentAnswers
== 0 && q
->ThisQInterval
== InitialQuestionInterval
* QuestionIntervalStep3
&& !q
->RequestUnicast
&&
2571 !(RRTypeIsAddressType(q
->qtype
) && CacheHasAddressTypeForName(m
, &q
->qname
, q
->qnamehash
)))
2573 // Generally don't need to log this.
2574 // It's not especially noteworthy if a query finds no results -- this usually happens for domain
2575 // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
2576 // and when there simply happen to be no instances of the service the client is looking
2577 // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
2578 debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
2579 q
->qname
.c
, DNSTypeName(q
->qtype
));
2580 // Sending third query, and no answers yet; time to begin doubting the source
2581 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
2585 // Mark for sending. (If no active interfaces, then don't even try.)
2586 q
->SendOnAll
= (q
->SendQNow
== mDNSInterfaceMark
);
2589 q
->SendQNow
= !intf
? mDNSNULL
: (q
->InterfaceID
) ? q
->InterfaceID
: intf
->InterfaceID
;
2590 q
->LastQTime
= m
->timenow
;
2593 // If we recorded a duplicate suppression for this question less than half an interval ago,
2594 // then we consider it recent enough that we don't need to do an identical query ourselves.
2595 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
- q
->ThisQInterval
/2);
2597 q
->LastQTxTime
= m
->timenow
;
2598 q
->RecentAnswerPkts
= 0;
2599 if (q
->RequestUnicast
) q
->RequestUnicast
--;
2601 // For all questions (not just the ones we're sending) check what the next scheduled event will be
2602 SetNextQueryTime(m
,q
);
2606 // 2. Scan our authoritative RR list to see what probes we might need to send
2607 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2609 m
->NextScheduledProbe
= m
->timenow
+ 0x78000000;
2611 if (m
->CurrentRecord
)
2612 LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
2613 m
->CurrentRecord
= m
->ResourceRecords
;
2614 while (m
->CurrentRecord
)
2616 AuthRecord
*rr
= m
->CurrentRecord
;
2617 m
->CurrentRecord
= rr
->next
;
2618 if (!AuthRecord_uDNS(rr
) && rr
->resrec
.RecordType
== kDNSRecordTypeUnique
) // For all records that are still probing...
2620 // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
2621 if (m
->timenow
- (rr
->LastAPTime
+ rr
->ThisAPInterval
) < 0)
2623 SetNextAnnounceProbeTime(m
, rr
);
2625 // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
2626 else if (rr
->ProbeCount
)
2628 // Mark for sending. (If no active interfaces, then don't even try.)
2629 rr
->SendRNow
= !intf
? mDNSNULL
: (rr
->resrec
.InterfaceID
) ? rr
->resrec
.InterfaceID
: intf
->InterfaceID
;
2630 rr
->LastAPTime
= m
->timenow
;
2632 SetNextAnnounceProbeTime(m
, rr
);
2633 if (rr
->ProbeCount
== 0)
2635 // If this is the last probe for this record, then see if we have any matching records
2636 // on our duplicate list which should similarly have their ProbeCount cleared to zero...
2638 for (r2
= m
->DuplicateRecords
; r2
; r2
=r2
->next
)
2639 if (r2
->resrec
.RecordType
== kDNSRecordTypeUnique
&& RecordIsLocalDuplicate(r2
, rr
))
2641 // ... then acknowledge this record to the client.
2642 // We do this optimistically, just as we're about to send the third probe.
2643 // This helps clients that both advertise and browse, and want to filter themselves
2644 // from the browse results list, because it helps ensure that the registration
2645 // confirmation will be delivered 1/4 second *before* the browse "add" event.
2646 // A potential downside is that we could deliver a registration confirmation and then find out
2647 // moments later that there's a name conflict, but applications have to be prepared to handle
2648 // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
2649 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
);
2652 // else, if it has now finished probing, move it to state Verified,
2653 // and update m->NextScheduledResponse so it will be announced
2656 if (!rr
->Acknowledged
) AcknowledgeRecord(m
, rr
); // Defensive, just in case it got missed somehow
2657 rr
->resrec
.RecordType
= kDNSRecordTypeVerified
;
2658 rr
->ThisAPInterval
= DefaultAnnounceIntervalForTypeUnique
;
2659 rr
->LastAPTime
= m
->timenow
- DefaultAnnounceIntervalForTypeUnique
;
2660 SetNextAnnounceProbeTime(m
, rr
);
2664 m
->CurrentRecord
= m
->DuplicateRecords
;
2665 while (m
->CurrentRecord
)
2667 AuthRecord
*rr
= m
->CurrentRecord
;
2668 m
->CurrentRecord
= rr
->next
;
2669 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
&& rr
->ProbeCount
== 0 && !rr
->Acknowledged
)
2670 AcknowledgeRecord(m
, rr
);
2674 // 3. Now we know which queries and probes we're sending,
2675 // go through our interface list sending the appropriate queries on each interface
2679 mDNSu8
*queryptr
= m
->omsg
.data
;
2680 InitializeDNSMessage(&m
->omsg
.h
, zeroID
, QueryFlags
);
2681 if (KnownAnswerList
) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet");
2682 if (!KnownAnswerList
)
2684 // Start a new known-answer list
2685 CacheRecord
**kalistptr
= &KnownAnswerList
;
2686 mDNSu32 answerforecast
= 0;
2688 // Put query questions in this packet
2689 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
2691 if (mDNSOpaque16IsZero(q
->TargetQID
) && (q
->SendQNow
== intf
->InterfaceID
))
2693 debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
2694 SuppressOnThisInterface(q
->DupSuppress
, intf
) ? "Suppressing" : "Putting ",
2695 q
->qname
.c
, DNSTypeName(q
->qtype
), queryptr
- m
->omsg
.data
, queryptr
+ answerforecast
- m
->omsg
.data
);
2696 // If we're suppressing this question, or we successfully put it, update its SendQNow state
2697 if (SuppressOnThisInterface(q
->DupSuppress
, intf
) ||
2698 BuildQuestion(m
, &m
->omsg
, &queryptr
, q
, &kalistptr
, &answerforecast
))
2699 q
->SendQNow
= (q
->InterfaceID
|| !q
->SendOnAll
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
2703 // Put probe questions in this packet
2704 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2705 if (rr
->SendRNow
== intf
->InterfaceID
)
2707 mDNSBool ucast
= (rr
->ProbeCount
>= DefaultProbeCountForTypeUnique
-1) && m
->CanReceiveUnicastOn5353
;
2708 mDNSu16 ucbit
= (mDNSu16
)(ucast
? kDNSQClass_UnicastResponse
: 0);
2709 const mDNSu8
*const limit
= m
->omsg
.data
+ ((m
->omsg
.h
.numQuestions
) ? NormalMaxDNSMessageData
: AbsoluteMaxDNSMessageData
);
2710 mDNSu8
*newptr
= putQuestion(&m
->omsg
, queryptr
, limit
, rr
->resrec
.name
, kDNSQType_ANY
, (mDNSu16
)(rr
->resrec
.rrclass
| ucbit
));
2711 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
2712 mDNSu32 forecast
= answerforecast
+ 12 + rr
->resrec
.rdestimate
;
2713 if (newptr
&& newptr
+ forecast
< limit
)
2716 answerforecast
= forecast
;
2717 rr
->SendRNow
= (rr
->resrec
.InterfaceID
) ? mDNSNULL
: GetNextActiveInterfaceID(intf
);
2718 rr
->IncludeInProbe
= mDNStrue
;
2719 verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
2720 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->ProbeCount
);
2724 verbosedebugf("SendQueries: Retracting Question %##s (%s)",
2725 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2726 m
->omsg
.h
.numQuestions
--;
2731 // Put our known answer list (either new one from this question or questions, or remainder of old one from last time)
2732 while (KnownAnswerList
)
2734 CacheRecord
*ka
= KnownAnswerList
;
2735 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- ka
->TimeRcvd
)) / mDNSPlatformOneSecond
;
2736 mDNSu8
*newptr
= PutResourceRecordTTL(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAnswers
, &ka
->resrec
, ka
->resrec
.rroriginalttl
- SecsSinceRcvd
);
2739 verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
2740 ka
->resrec
.name
->c
, DNSTypeName(ka
->resrec
.rrtype
), queryptr
- m
->omsg
.data
, newptr
- m
->omsg
.data
);
2742 KnownAnswerList
= ka
->NextInKAList
;
2743 ka
->NextInKAList
= mDNSNULL
;
2747 // If we ran out of space and we have more than one question in the packet, that's an error --
2748 // we shouldn't have put more than one question if there was a risk of us running out of space.
2749 if (m
->omsg
.h
.numQuestions
> 1)
2750 LogMsg("SendQueries: Put %d answers; No more space for known answers", m
->omsg
.h
.numAnswers
);
2751 m
->omsg
.h
.flags
.b
[0] |= kDNSFlag0_TC
;
2756 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
2757 if (rr
->IncludeInProbe
)
2759 mDNSu8
*newptr
= PutResourceRecord(&m
->omsg
, queryptr
, &m
->omsg
.h
.numAuthorities
, &rr
->resrec
);
2760 rr
->IncludeInProbe
= mDNSfalse
;
2761 if (newptr
) queryptr
= newptr
;
2762 else LogMsg("SendQueries: How did we fail to have space for the Update record %##s (%s)?",
2763 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
2766 if (queryptr
> m
->omsg
.data
)
2768 if ((m
->omsg
.h
.flags
.b
[0] & kDNSFlag0_TC
) && m
->omsg
.h
.numQuestions
> 1)
2769 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m
->omsg
.h
.numQuestions
);
2770 debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
2771 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
2772 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
2773 m
->omsg
.h
.numAuthorities
, m
->omsg
.h
.numAuthorities
== 1 ? "" : "s", intf
->InterfaceID
);
2774 if (intf
->IPv4Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v4
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2775 if (intf
->IPv6Available
) mDNSSendDNSMessage(m
, &m
->omsg
, queryptr
, intf
->InterfaceID
, mDNSNULL
, &AllDNSLinkGroup_v6
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
2776 if (!m
->SuppressSending
) m
->SuppressSending
= NonZeroTime(m
->timenow
+ (mDNSPlatformOneSecond
+9)/10);
2777 if (++pktcount
>= 1000)
2778 { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount
); break; }
2779 // There might be more records left in the known answer list, or more questions to send
2780 // on this interface, so go around one more time and try again.
2782 else // Nothing more to send on this interface; go to next
2784 const NetworkInterfaceInfo
*next
= GetFirstActiveInterface(intf
->next
);
2785 #if MDNS_DEBUGMSGS && 0
2786 const char *const msg
= next
? "SendQueries: Nothing more on %p; moving to %p" : "SendQueries: Nothing more on %p";
2787 debugf(msg
, intf
, next
);
2793 // 4. Final housekeeping
2795 // 4a. Debugging check: Make sure we announced all our records
2796 for (ar
= m
->ResourceRecords
; ar
; ar
=ar
->next
)
2799 if (ar
->resrec
.InterfaceID
!= mDNSInterface_LocalOnly
)
2800 LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m
, ar
));
2801 ar
->SendRNow
= mDNSNULL
;
2804 // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
2805 // that their interface which went away might come back again, the logic will want to send queries
2806 // for those records, but we can't because their interface isn't here any more, so to keep the
2807 // state machine ticking over we just pretend we did so.
2808 // If the interface does not come back in time, the cache record will expire naturally
2809 FORALL_CACHERECORDS(slot
, cg
, cr
)
2810 if (cr
->CRActiveQuestion
&& cr
->UnansweredQueries
< MaxUnansweredQueries
&& m
->timenow
- cr
->NextRequiredQuery
>= 0)
2812 cr
->UnansweredQueries
++;
2813 cr
->CRActiveQuestion
->SendQNow
= mDNSNULL
;
2814 SetNextCacheCheckTime(m
, cr
);
2817 // 4c. Debugging check: Make sure we sent all our planned questions
2818 // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
2819 // we legitimately couldn't send because the interface is no longer available
2820 for (q
= m
->Questions
; q
; q
=q
->next
)
2823 LogMsg("SendQueries: No active interface to send: %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2824 q
->SendQNow
= mDNSNULL
;
2828 // ***************************************************************************
2829 #if COMPILER_LIKES_PRAGMA_MARK
2831 #pragma mark - RR List Management & Task Management
2834 // NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
2835 // Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
2836 // In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
2837 // which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
2838 mDNSexport
void AnswerCurrentQuestionWithResourceRecord(mDNS
*const m
, CacheRecord
*const rr
, const QC_result AddRecord
)
2840 DNSQuestion
*const q
= m
->CurrentQuestion
;
2841 mDNSBool followcname
= rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& AddRecord
&&
2842 rr
->resrec
.rrtype
== kDNSType_CNAME
&& q
->qtype
!= kDNSType_CNAME
;
2843 verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q
->CurrentAnswers
, AddRecord
? "Add" : "Rmv", rr
->resrec
.rroriginalttl
, CRDisplayString(m
, rr
));
2845 // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
2846 // may be called twice, once when the record is received, and again when it's time to notify local clients.
2847 // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
2849 rr
->LastUsed
= m
->timenow
;
2850 if (AddRecord
== QC_add
&& !q
->DuplicateOf
&& rr
->CRActiveQuestion
!= q
)
2852 if (!rr
->CRActiveQuestion
) m
->rrcache_active
++; // If not previously active, increment rrcache_active count
2853 debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
2854 rr
->CRActiveQuestion
= q
; // We know q is non-null
2855 SetNextCacheCheckTime(m
, rr
);
2859 // (a) a no-cache add, where we've already done at least one 'QM' query, or
2860 // (b) a normal add, where we have at least one unique-type answer,
2861 // then there's no need to keep polling the network.
2862 // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
2863 // We do this for mDNS questions and uDNS one-shot questions, but not for
2864 // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
2865 if ((AddRecord
== QC_addnocache
&& !q
->RequestUnicast
) ||
2866 (AddRecord
== QC_add
&& (q
->ExpectUnique
|| (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))))
2867 if (ActiveQuestion(q
) && (mDNSOpaque16IsZero(q
->TargetQID
) || !q
->LongLived
))
2869 q
->LastQTime
= m
->timenow
;
2870 q
->LastQTxTime
= m
->timenow
;
2871 q
->RecentAnswerPkts
= 0;
2872 q
->ThisQInterval
= MaxQuestionInterval
;
2873 q
->RequestUnicast
= mDNSfalse
;
2874 debugf("AnswerCurrentQuestionWithResourceRecord: Set MaxQuestionInterval for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2877 if (rr
->DelayDelivery
) return; // We'll come back later when CacheRecordDeferredAdd() calls us
2879 // Only deliver negative answers if client has explicitly requested them
2880 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& (!AddRecord
|| !q
->ReturnIntermed
)) return;
2882 // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
2883 if (q
->QuestionCallback
&& !q
->NoAnswer
&& (!followcname
|| q
->ReturnIntermed
))
2885 mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
2886 q
->QuestionCallback(m
, q
, &rr
->resrec
, AddRecord
);
2887 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
2889 // NOTE: Proceed with caution here because client callback function is allowed to do anything,
2890 // including starting/stopping queries, registering/deregistering records, etc.
2892 if (followcname
&& m
->CurrentQuestion
== q
&& q
->CNAMEReferrals
< 10)
2894 const mDNSu32 c
= q
->CNAMEReferrals
+ 1;
2895 // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
2896 // and track CNAMEs coming and going, we should really create a subbordinate query here,
2897 // which we would subsequently cancel and retract if the CNAME referral record were removed.
2898 // In reality this is such a corner case we'll ignore it until someone actually needs it.
2899 LogOperation("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m
, rr
));
2900 mDNS_StopQuery_internal(m
, q
); // Stop old query
2901 AssignDomainName(&q
->qname
, &rr
->resrec
.rdata
->u
.name
); // Update qname
2902 q
->qnamehash
= DomainNameHashValue(&q
->qname
); // and namehash
2903 mDNS_StartQuery_internal(m
, q
); // start new query
2904 q
->CNAMEReferrals
= c
; // and keep count of how many times we've done this
2908 mDNSlocal
void CacheRecordDeferredAdd(mDNS
*const m
, CacheRecord
*rr
)
2910 rr
->DelayDelivery
= 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
2911 if (m
->CurrentQuestion
)
2912 LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
2913 m
->CurrentQuestion
= m
->Questions
;
2914 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
2916 DNSQuestion
*q
= m
->CurrentQuestion
;
2917 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
2918 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
2919 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
2920 m
->CurrentQuestion
= q
->next
;
2922 m
->CurrentQuestion
= mDNSNULL
;
2925 mDNSlocal mDNSs32
CheckForSoonToExpireRecords(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const mDNSu32 slot
)
2927 const mDNSs32 threshhold
= m
->timenow
+ mDNSPlatformOneSecond
; // See if there are any records expiring within one second
2928 const mDNSs32 start
= m
->timenow
- 0x10000000;
2929 mDNSs32 delay
= start
;
2930 CacheGroup
*cg
= CacheGroupForName(m
, slot
, namehash
, name
);
2932 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2933 if (threshhold
- RRExpireTime(rr
) >= 0) // If we have records about to expire within a second
2934 if (delay
- RRExpireTime(rr
) < 0) // then delay until after they've been deleted
2935 delay
= RRExpireTime(rr
);
2936 if (delay
- start
> 0) return(NonZeroTime(delay
));
2940 // CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
2941 // If new questions are created as a result of invoking client callbacks, they will be added to
2942 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
2943 // rr is a new CacheRecord just received into our cache
2944 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
2945 // NOTE: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
2946 // which may change the record list and/or question list.
2947 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
2948 mDNSlocal
void CacheRecordAdd(mDNS
*const m
, CacheRecord
*rr
)
2952 // We stop when we get to NewQuestions -- if we increment their CurrentAnswers/LargeAnswers/UniqueAnswers
2953 // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
2954 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
2956 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
2958 // If this question is one that's actively sending queries, and it's received ten answers within one
2959 // second of sending the last query packet, then that indicates some radical network topology change,
2960 // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
2961 // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
2962 // because we will anyway send another query within a few seconds. The first reset query is sent out
2963 // randomized over the next four seconds to reduce possible synchronization between machines.
2964 if (q
->LastAnswerPktNum
!= m
->PktNum
)
2966 q
->LastAnswerPktNum
= m
->PktNum
;
2967 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
) && ++q
->RecentAnswerPkts
>= 10 &&
2968 q
->ThisQInterval
> InitialQuestionInterval
* QuestionIntervalStep3
&& m
->timenow
- q
->LastQTxTime
< mDNSPlatformOneSecond
)
2970 LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst (%d); restarting exponential backoff sequence (%d)",
2971 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->RecentAnswerPkts
, q
->ThisQInterval
);
2972 q
->LastQTime
= m
->timenow
- InitialQuestionInterval
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*4);
2973 q
->ThisQInterval
= InitialQuestionInterval
;
2974 SetNextQueryTime(m
,q
);
2977 verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
2978 rr
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), rr
->resrec
.rroriginalttl
);
2979 q
->CurrentAnswers
++;
2980 q
->unansweredQueries
= 0;
2981 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
2982 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
2983 if (q
->CurrentAnswers
> 4000)
2985 static int msgcount
= 0;
2986 if (msgcount
++ < 10)
2987 LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
2988 q
->qname
.c
, DNSTypeName(q
->qtype
), q
->CurrentAnswers
);
2989 rr
->resrec
.rroriginalttl
= 0;
2990 rr
->UnansweredQueries
= MaxUnansweredQueries
;
2995 if (!rr
->DelayDelivery
)
2997 if (m
->CurrentQuestion
)
2998 LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
2999 m
->CurrentQuestion
= m
->Questions
;
3000 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3002 q
= m
->CurrentQuestion
;
3003 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3004 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3005 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3006 m
->CurrentQuestion
= q
->next
;
3008 m
->CurrentQuestion
= mDNSNULL
;
3011 SetNextCacheCheckTime(m
, rr
);
3014 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
3015 // If new questions are created as a result of invoking client callbacks, they will be added to
3016 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3017 // rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
3018 // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
3019 // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
3020 // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
3021 // NOTE: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3022 // which may change the record list and/or question list.
3023 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3024 mDNSlocal
void NoCacheAnswer(mDNS
*const m
, CacheRecord
*rr
)
3026 LogMsg("No cache space: Delivering non-cached result for %##s", m
->rec
.r
.resrec
.name
->c
);
3027 if (m
->CurrentQuestion
)
3028 LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3029 m
->CurrentQuestion
= m
->Questions
;
3030 // We do this for *all* questions, not stopping when we get to m->NewQuestions,
3031 // since we're not caching the record and we'll get no opportunity to do this later
3032 while (m
->CurrentQuestion
)
3034 DNSQuestion
*q
= m
->CurrentQuestion
;
3035 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3036 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_addnocache
); // QC_addnocache means "don't expect remove events for this"
3037 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3038 m
->CurrentQuestion
= q
->next
;
3040 m
->CurrentQuestion
= mDNSNULL
;
3043 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute.
3044 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
3045 // If new questions are created as a result of invoking client callbacks, they will be added to
3046 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
3047 // rr is an existing cache CacheRecord that just expired and is being deleted
3048 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
3049 // NOTE: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
3050 // which may change the record list and/or question list.
3051 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3052 mDNSlocal
void CacheRecordRmv(mDNS
*const m
, CacheRecord
*rr
)
3054 if (m
->CurrentQuestion
)
3055 LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3056 m
->CurrentQuestion
= m
->Questions
;
3058 // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
3059 // will all still be zero because we haven't yet gone through the cache counting how many answers we have for them.
3060 while (m
->CurrentQuestion
&& m
->CurrentQuestion
!= m
->NewQuestions
)
3062 DNSQuestion
*q
= m
->CurrentQuestion
;
3063 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3065 verbosedebugf("CacheRecordRmv %p %s", rr
, CRDisplayString(m
, rr
));
3066 q
->FlappingInterface1
= mDNSNULL
;
3067 q
->FlappingInterface2
= mDNSNULL
;
3068 if (q
->CurrentAnswers
== 0)
3069 LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
3070 q
, q
->qname
.c
, DNSTypeName(q
->qtype
));
3073 q
->CurrentAnswers
--;
3074 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
--;
3075 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
--;
3077 if (rr
->resrec
.rdata
->MaxRDLength
) // Never generate "remove" events for negative results
3079 if (q
->CurrentAnswers
== 0)
3081 LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
3082 q
->qname
.c
, DNSTypeName(q
->qtype
));
3083 ReconfirmAntecedents(m
, &q
->qname
, q
->qnamehash
, 0);
3085 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_rmv
);
3088 if (m
->CurrentQuestion
== q
) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
3089 m
->CurrentQuestion
= q
->next
;
3091 m
->CurrentQuestion
= mDNSNULL
;
3094 mDNSlocal
void ReleaseCacheEntity(mDNS
*const m
, CacheEntity
*e
)
3096 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
3098 for (i
=0; i
<sizeof(*e
); i
++) ((char*)e
)[i
] = 0xFF;
3100 e
->next
= m
->rrcache_free
;
3101 m
->rrcache_free
= e
;
3102 m
->rrcache_totalused
--;
3105 mDNSlocal
void ReleaseCacheGroup(mDNS
*const m
, CacheGroup
**cp
)
3107 CacheEntity
*e
= (CacheEntity
*)(*cp
);
3108 //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
3109 if ((*cp
)->rrcache_tail
!= &(*cp
)->members
)
3110 LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
3111 //if ((*cp)->name != (domainname*)((*cp)->namestorage))
3112 // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
3113 if ((*cp
)->name
!= (domainname
*)((*cp
)->namestorage
)) mDNSPlatformMemFree((*cp
)->name
);
3114 (*cp
)->name
= mDNSNULL
;
3115 *cp
= (*cp
)->next
; // Cut record from list
3116 ReleaseCacheEntity(m
, e
);
3119 mDNSlocal
void ReleaseCacheRecord(mDNS
*const m
, CacheRecord
*r
)
3121 //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
3122 if (r
->resrec
.rdata
&& r
->resrec
.rdata
!= (RData
*)&r
->rdatastorage
) mDNSPlatformMemFree(r
->resrec
.rdata
);
3123 r
->resrec
.rdata
= mDNSNULL
;
3124 ReleaseCacheEntity(m
, (CacheEntity
*)r
);
3127 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
3128 // CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
3129 // callbacks for old records are delivered before callbacks for newer records.
3130 mDNSlocal
void CheckCacheExpiration(mDNS
*const m
, CacheGroup
*const cg
)
3132 CacheRecord
**rp
= &cg
->members
;
3134 if (m
->lock_rrcache
) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
3135 m
->lock_rrcache
= 1;
3139 CacheRecord
*const rr
= *rp
;
3140 mDNSs32 event
= RRExpireTime(rr
);
3141 if (m
->timenow
- event
>= 0) // If expired, delete it
3143 *rp
= rr
->next
; // Cut it from the list
3144 verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
3145 m
->timenow
- rr
->TimeRcvd
, rr
->resrec
.rroriginalttl
, rr
->CRActiveQuestion
, CRDisplayString(m
, rr
));
3146 if (rr
->CRActiveQuestion
) // If this record has one or more active questions, tell them it's going away
3148 CacheRecordRmv(m
, rr
);
3149 m
->rrcache_active
--;
3151 ReleaseCacheRecord(m
, rr
);
3153 else // else, not expired; see if we need to query
3155 if (rr
->DelayDelivery
&& rr
->DelayDelivery
- m
->timenow
> 0)
3156 event
= rr
->DelayDelivery
;
3159 if (rr
->DelayDelivery
) CacheRecordDeferredAdd(m
, rr
);
3160 if (rr
->CRActiveQuestion
&& rr
->UnansweredQueries
< MaxUnansweredQueries
)
3162 if (m
->timenow
- rr
->NextRequiredQuery
< 0) // If not yet time for next query
3163 event
= rr
->NextRequiredQuery
; // then just record when we want the next query
3164 else // else trigger our question to go out now
3166 // Set NextScheduledQuery to timenow so that SendQueries() will run.
3167 // SendQueries() will see that we have records close to expiration, and send FEQs for them.
3168 m
->NextScheduledQuery
= m
->timenow
;
3169 // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
3170 // which will correctly update m->NextCacheCheck for us.
3171 event
= m
->timenow
+ 0x3FFFFFFF;
3175 verbosedebugf("CheckCacheExpiration:%6d %5d %s",
3176 (event
- m
->timenow
) / mDNSPlatformOneSecond
, CacheCheckGracePeriod(rr
), CRDisplayString(m
, rr
));
3177 if (m
->NextCacheCheck
- (event
+ CacheCheckGracePeriod(rr
)) > 0)
3178 m
->NextCacheCheck
= (event
+ CacheCheckGracePeriod(rr
));
3182 if (cg
->rrcache_tail
!= rp
) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg
->rrcache_tail
, rp
);
3183 cg
->rrcache_tail
= rp
;
3184 m
->lock_rrcache
= 0;
3187 mDNSlocal
void AnswerNewQuestion(mDNS
*const m
)
3189 mDNSBool ShouldQueryImmediately
= mDNStrue
;
3190 DNSQuestion
*q
= m
->NewQuestions
; // Grab the question we're going to answer
3191 const mDNSu32 slot
= HashSlot(&q
->qname
);
3192 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3194 verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3196 if (cg
) CheckCacheExpiration(m
, cg
);
3197 m
->NewQuestions
= q
->next
; // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
3199 if (m
->lock_rrcache
) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
3200 // This should be safe, because calling the client's question callback may cause the
3201 // question list to be modified, but should not ever cause the rrcache list to be modified.
3202 // If the client's question callback deletes the question, then m->CurrentQuestion will
3203 // be advanced, and we'll exit out of the loop
3204 m
->lock_rrcache
= 1;
3205 if (m
->CurrentQuestion
)
3206 LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3207 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
3209 if (q
->NoAnswer
== NoAnswer_Fail
)
3211 LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3212 MakeNegativeCacheRecord(m
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60);
3213 q
->NoAnswer
= NoAnswer_Normal
; // Temporarily turn off answer suppression
3214 AnswerCurrentQuestionWithResourceRecord(m
, &m
->rec
.r
, QC_addnocache
);
3215 q
->NoAnswer
= NoAnswer_Fail
; // Restore NoAnswer state
3216 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3219 // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
3220 if (m
->CurrentQuestion
== q
&& q
->InterfaceID
== mDNSInterface_Any
)
3222 if (m
->CurrentRecord
)
3223 LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3224 m
->CurrentRecord
= m
->ResourceRecords
;
3225 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
3227 AuthRecord
*rr
= m
->CurrentRecord
;
3228 m
->CurrentRecord
= rr
->next
;
3229 if (rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
)
3230 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3232 AnswerLocalOnlyQuestionWithResourceRecord(m
, q
, rr
, mDNStrue
);
3233 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
3236 m
->CurrentRecord
= mDNSNULL
;
3239 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
3241 if (m
->CurrentQuestion
== q
)
3244 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
3245 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
))
3247 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
3248 mDNSu32 SecsSinceRcvd
= ((mDNSu32
)(m
->timenow
- rr
->TimeRcvd
)) / mDNSPlatformOneSecond
;
3249 if (rr
->resrec
.rroriginalttl
<= SecsSinceRcvd
)
3251 LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s) %d %d",
3252 rr
->resrec
.rroriginalttl
, SecsSinceRcvd
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), m
->timenow
, rr
->TimeRcvd
);
3253 continue; // Go to next one in loop
3256 // If this record set is marked unique, then that means we can reasonably assume we have the whole set
3257 // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
3258 if ((rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) || (q
->ExpectUnique
))
3259 ShouldQueryImmediately
= mDNSfalse
;
3260 q
->CurrentAnswers
++;
3261 if (rr
->resrec
.rdlength
> SmallRecordLimit
) q
->LargeAnswers
++;
3262 if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) q
->UniqueAnswers
++;
3263 AnswerCurrentQuestionWithResourceRecord(m
, rr
, QC_add
);
3264 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
3266 else if (RRTypeIsAddressType(rr
->resrec
.rrtype
) && RRTypeIsAddressType(q
->qtype
))
3267 if (rr
->resrec
.namehash
== q
->qnamehash
&& SameDomainName(rr
->resrec
.name
, &q
->qname
))
3268 ShouldQueryImmediately
= mDNSfalse
;
3271 if (m
->CurrentQuestion
!= q
) debugf("AnswerNewQuestion: question deleted while giving cache answers");
3273 if (m
->CurrentQuestion
== q
&& ShouldQueryImmediately
&& ActiveQuestion(q
))
3275 debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3276 q
->ThisQInterval
= InitialQuestionInterval
;
3277 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
3278 if (mDNSOpaque16IsZero(q
->TargetQID
)) // For mDNS, spread packets to avoid a burst of simultaneous queries
3280 // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
3281 if (!m
->RandomQueryDelay
)
3282 m
->RandomQueryDelay
= (mDNSPlatformOneSecond
+ mDNSRandom(mDNSPlatformOneSecond
*5) - 1) / 50 + 1;
3283 q
->LastQTime
+= m
->RandomQueryDelay
;
3286 if (m
->NextScheduledQuery
- (q
->LastQTime
+ q
->ThisQInterval
) > 0)
3287 m
->NextScheduledQuery
= (q
->LastQTime
+ q
->ThisQInterval
);
3290 m
->CurrentQuestion
= mDNSNULL
;
3291 m
->lock_rrcache
= 0;
3294 // When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
3295 // appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
3296 mDNSlocal
void AnswerNewLocalOnlyQuestion(mDNS
*const m
)
3298 DNSQuestion
*q
= m
->NewLocalOnlyQuestions
; // Grab the question we're going to answer
3299 m
->NewLocalOnlyQuestions
= q
->next
; // Advance NewLocalOnlyQuestions to the next (if any)
3301 debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3303 if (m
->CurrentQuestion
)
3304 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3305 m
->CurrentQuestion
= q
; // Indicate which question we're answering, so we'll know if it gets deleted
3307 if (m
->CurrentRecord
)
3308 LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
3309 m
->CurrentRecord
= m
->ResourceRecords
;
3311 while (m
->CurrentRecord
&& m
->CurrentRecord
!= m
->NewLocalRecords
)
3313 AuthRecord
*rr
= m
->CurrentRecord
;
3314 m
->CurrentRecord
= rr
->next
;
3315 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
3317 AnswerLocalOnlyQuestionWithResourceRecord(m
, q
, rr
, mDNStrue
);
3318 if (m
->CurrentQuestion
!= q
) break; // If callback deleted q, then we're finished here
3322 m
->CurrentQuestion
= mDNSNULL
;
3323 m
->CurrentRecord
= mDNSNULL
;
3326 mDNSlocal CacheEntity
*GetCacheEntity(mDNS
*const m
, const CacheGroup
*const PreserveCG
)
3328 CacheEntity
*e
= mDNSNULL
;
3330 if (m
->lock_rrcache
) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL
); }
3331 m
->lock_rrcache
= 1;
3333 // If we have no free records, ask the client layer to give us some more memory
3334 if (!m
->rrcache_free
&& m
->MainCallback
)
3336 if (m
->rrcache_totalused
!= m
->rrcache_size
)
3337 LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
3338 m
->rrcache_totalused
, m
->rrcache_size
);
3340 // We don't want to be vulnerable to a malicious attacker flooding us with an infinite
3341 // number of bogus records so that we keep growing our cache until the machine runs out of memory.
3342 // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
3343 // and we're actively using less than 1/32 of that cache, then we purge all the unused records
3344 // and recycle them, instead of allocating more memory.
3345 if (m
->rrcache_size
> 3000 && m
->rrcache_size
/ 32 > m
->rrcache_active
)
3346 LogOperation("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
3347 m
->rrcache_size
, m
->rrcache_active
);
3350 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3351 m
->MainCallback(m
, mStatus_GrowCache
);
3352 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3356 // If we still have no free records, recycle all the records we can.
3357 // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
3358 if (!m
->rrcache_free
)
3360 #if LogAllOperations || MDNS_DEBUGMSGS
3361 mDNSu32 oldtotalused
= m
->rrcache_totalused
;
3364 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
3366 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
3369 CacheRecord
**rp
= &(*cp
)->members
;
3372 // Records that answer still-active questions are not candidates for recycling
3373 // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
3374 if ((*rp
)->CRActiveQuestion
|| (*rp
)->NextInCFList
)
3378 CacheRecord
*rr
= *rp
;
3379 *rp
= (*rp
)->next
; // Cut record from list
3380 ReleaseCacheRecord(m
, rr
);
3383 if ((*cp
)->rrcache_tail
!= rp
)
3384 verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot
, (*cp
)->rrcache_tail
, rp
);
3385 (*cp
)->rrcache_tail
= rp
;
3386 if ((*cp
)->members
|| (*cp
)==PreserveCG
) cp
=&(*cp
)->next
;
3387 else ReleaseCacheGroup(m
, cp
);
3390 LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d",
3391 oldtotalused
- m
->rrcache_totalused
, oldtotalused
, m
->rrcache_totalused
);
3394 if (m
->rrcache_free
) // If there are records in the free list, take one
3396 e
= m
->rrcache_free
;
3397 m
->rrcache_free
= e
->next
;
3398 if (++m
->rrcache_totalused
>= m
->rrcache_report
)
3400 LogOperation("RR Cache now using %ld objects", m
->rrcache_totalused
);
3401 if (m
->rrcache_report
< 100) m
->rrcache_report
+= 10;
3402 else m
->rrcache_report
+= 100;
3404 mDNSPlatformMemZero(e
, sizeof(*e
));
3407 m
->lock_rrcache
= 0;
3412 mDNSlocal CacheRecord
*GetCacheRecord(mDNS
*const m
, CacheGroup
*cg
, mDNSu16 RDLength
)
3414 CacheRecord
*r
= (CacheRecord
*)GetCacheEntity(m
, cg
);
3417 r
->resrec
.rdata
= (RData
*)&r
->rdatastorage
; // By default, assume we're usually going to be using local storage
3418 if (RDLength
> InlineCacheRDSize
) // If RDLength is too big, allocate extra storage
3420 r
->resrec
.rdata
= (RData
*)mDNSPlatformMemAllocate(sizeofRDataHeader
+ RDLength
);
3421 if (r
->resrec
.rdata
) r
->resrec
.rdata
->MaxRDLength
= r
->resrec
.rdlength
= RDLength
;
3422 else { ReleaseCacheEntity(m
, (CacheEntity
*)r
); r
= mDNSNULL
; }
3428 mDNSlocal CacheGroup
*GetCacheGroup(mDNS
*const m
, const mDNSu32 slot
, const ResourceRecord
*const rr
)
3430 mDNSu16 namelen
= DomainNameLength(rr
->name
);
3431 CacheGroup
*cg
= (CacheGroup
*)GetCacheEntity(m
, mDNSNULL
);
3432 if (!cg
) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr
->name
->c
); return(mDNSNULL
); }
3433 cg
->next
= m
->rrcache_hash
[slot
];
3434 cg
->namehash
= rr
->namehash
;
3435 cg
->members
= mDNSNULL
;
3436 cg
->rrcache_tail
= &cg
->members
;
3437 cg
->name
= (domainname
*)cg
->namestorage
;
3438 //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
3439 // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
3440 if (namelen
> InlineCacheGroupNameSize
) cg
->name
= mDNSPlatformMemAllocate(namelen
);
3443 LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr
->name
->c
);
3444 ReleaseCacheEntity(m
, (CacheEntity
*)cg
);
3447 AssignDomainName(cg
->name
, rr
->name
);
3449 if (CacheGroupForRecord(m
, slot
, rr
)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr
->name
->c
);
3450 m
->rrcache_hash
[slot
] = cg
;
3451 if (CacheGroupForRecord(m
, slot
, rr
) != cg
) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr
->name
->c
);
3456 mDNSexport
void mDNS_PurgeCacheResourceRecord(mDNS
*const m
, CacheRecord
*rr
)
3458 // Make sure we mark this record as thoroughly expired -- we don't ever want to give
3459 // a positive answer using an expired record (e.g. from an interface that has gone away).
3460 // We don't want to clear CRActiveQuestion here, because that would leave the record subject to
3461 // summary deletion without giving the proper callback to any questions that are monitoring it.
3462 // By setting UnansweredQueries to MaxUnansweredQueries we ensure it won't trigger any further expiration queries.
3463 rr
->TimeRcvd
= m
->timenow
- mDNSPlatformOneSecond
* 60;
3464 rr
->UnansweredQueries
= MaxUnansweredQueries
;
3465 rr
->resrec
.rroriginalttl
= 0;
3466 SetNextCacheCheckTime(m
, rr
);
3469 mDNSexport mDNSs32
mDNS_TimeNow(const mDNS
*const m
)
3472 mDNSPlatformLock(m
);
3475 LogMsg("mDNS_TimeNow called while holding mDNS lock. This is incorrect. Code protected by lock should just use m->timenow.");
3476 if (!m
->timenow
) LogMsg("mDNS_TimeNow: m->mDNS_busy is %ld but m->timenow not set", m
->mDNS_busy
);
3479 if (m
->timenow
) time
= m
->timenow
;
3480 else time
= mDNS_TimeNow_NoLock(m
);
3481 mDNSPlatformUnlock(m
);
3485 mDNSexport mDNSs32
mDNS_Execute(mDNS
*const m
)
3487 mDNS_Lock(m
); // Must grab lock before trying to read m->timenow
3489 if (m
->timenow
- m
->NextScheduledEvent
>= 0)
3493 verbosedebugf("mDNS_Execute");
3494 if (m
->CurrentQuestion
)
3495 LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3497 // 1. If we're past the probe suppression time, we can clear it
3498 if (m
->SuppressProbes
&& m
->timenow
- m
->SuppressProbes
>= 0) m
->SuppressProbes
= 0;
3500 // 2. If it's been more than ten seconds since the last probe failure, we can clear the counter
3501 if (m
->NumFailedProbes
&& m
->timenow
- m
->ProbeFailTime
>= mDNSPlatformOneSecond
* 10) m
->NumFailedProbes
= 0;
3503 // 3. Purge our cache of stale old records
3504 if (m
->rrcache_size
&& m
->timenow
- m
->NextCacheCheck
>= 0)
3507 m
->NextCacheCheck
= m
->timenow
+ 0x3FFFFFFF;
3508 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
3510 CacheGroup
**cp
= &m
->rrcache_hash
[slot
];
3513 CheckCacheExpiration(m
, *cp
);
3514 if ((*cp
)->members
) cp
=&(*cp
)->next
;
3515 else ReleaseCacheGroup(m
, cp
);
3520 // 4. See if we can answer any of our new local questions from the cache
3521 for (i
=0; m
->NewQuestions
&& i
<1000; i
++)
3523 if (m
->NewQuestions
->DelayAnswering
&& m
->timenow
- m
->NewQuestions
->DelayAnswering
< 0) break;
3524 AnswerNewQuestion(m
);
3526 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
3528 for (i
=0; m
->NewLocalOnlyQuestions
&& i
<1000; i
++) AnswerNewLocalOnlyQuestion(m
);
3529 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
3531 for (i
=0; i
<1000 && m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
); i
++)
3533 AuthRecord
*rr
= m
->NewLocalRecords
;
3534 m
->NewLocalRecords
= m
->NewLocalRecords
->next
;
3535 AnswerLocalQuestions(m
, rr
, mDNStrue
);
3537 if (i
>= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
3539 // 5. See what packets we need to send
3540 if (m
->mDNSPlatformStatus
!= mStatus_NoError
|| m
->SleepState
) DiscardDeregistrations(m
);
3541 else if (m
->SuppressSending
== 0 || m
->timenow
- m
->SuppressSending
>= 0)
3543 // If the platform code is ready, and we're not suppressing packet generation right now
3544 // then send our responses, probes, and questions.
3545 // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
3546 // We send queries next, because there might be final-stage probes that complete their probing here, causing
3547 // them to advance to announcing state, and we want those to be included in any announcements we send out.
3548 // Finally, we send responses, including the previously mentioned records that just completed probing.
3549 m
->SuppressSending
= 0;
3551 // 6. Send Query packets. This may cause some probing records to advance to announcing state
3552 if (m
->timenow
- m
->NextScheduledQuery
>= 0 || m
->timenow
- m
->NextScheduledProbe
>= 0) SendQueries(m
);
3553 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
3556 LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
3557 m
->timenow
, m
->NextScheduledQuery
, m
->timenow
- m
->NextScheduledQuery
);
3558 m
->NextScheduledQuery
= m
->timenow
+ mDNSPlatformOneSecond
;
3559 for (q
= m
->Questions
; q
&& q
!= m
->NewQuestions
; q
=q
->next
)
3560 if (ActiveQuestion(q
) && q
->LastQTime
+ q
->ThisQInterval
- m
->timenow
<= 0)
3561 LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3563 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
3565 LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
3566 m
->timenow
, m
->NextScheduledProbe
, m
->timenow
- m
->NextScheduledProbe
);
3567 m
->NextScheduledProbe
= m
->timenow
+ mDNSPlatformOneSecond
;
3570 // 7. Send Response packets, including probing records just advanced to announcing state
3571 if (m
->timenow
- m
->NextScheduledResponse
>= 0) SendResponses(m
);
3572 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
3574 LogMsg("mDNS_Execute: SendResponses didn't send all its responses; will try again in one second");
3575 m
->NextScheduledResponse
= m
->timenow
+ mDNSPlatformOneSecond
;
3579 // Clear RandomDelay values, ready to pick a new different value next time
3580 m
->RandomQueryDelay
= 0;
3581 m
->RandomReconfirmDelay
= 0;
3584 // Note about multi-threaded systems:
3585 // On a multi-threaded system, some other thread could run right after the mDNS_Unlock(),
3586 // performing mDNS API operations that change our next scheduled event time.
3588 // On multi-threaded systems (like the current Windows implementation) that have a single main thread
3589 // calling mDNS_Execute() (and other threads allowed to call mDNS API routines) it is the responsibility
3590 // of the mDNSPlatformUnlock() routine to signal some kind of stateful condition variable that will
3591 // signal whatever blocking primitive the main thread is using, so that it will wake up and execute one
3592 // more iteration of its loop, and immediately call mDNS_Execute() again. The signal has to be stateful
3593 // in the sense that if the main thread has not yet entered its blocking primitive, then as soon as it
3594 // does, the state of the signal will be noticed, causing the blocking primitive to return immediately
3595 // without blocking. This avoids the race condition between the signal from the other thread arriving
3596 // just *before* or just *after* the main thread enters the blocking primitive.
3598 // On multi-threaded systems (like the current Mac OS 9 implementation) that are entirely timer-driven,
3599 // with no main mDNS_Execute() thread, it is the responsibility of the mDNSPlatformUnlock() routine to
3600 // set the timer according to the m->NextScheduledEvent value, and then when the timer fires, the timer
3601 // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
3602 // by the time it gets to the timer callback function).
3604 #ifndef UNICAST_DISABLED
3607 mDNS_Unlock(m
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
3608 return(m
->NextScheduledEvent
);
3611 mDNSlocal
void SuspendLLQs(mDNS
*m
)
3614 for (q
= m
->Questions
; q
; q
= q
->next
)
3615 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
&& q
->state
== LLQ_Established
)
3616 { q
->ReqLease
= 0; sendLLQRefresh(m
, q
); }
3619 // ActivateUnicastQuery() is called from three places:
3620 // 1. When a new question is created
3621 // 2. On wake from sleep
3622 // 3. When the DNS configuration changes
3623 // In case 1 we don't want to mess with our established ThisQInterval and LastQTime (ScheduleImmediately is false)
3624 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
3625 mDNSlocal
void ActivateUnicastQuery(mDNS
*const m
, DNSQuestion
*const question
, mDNSBool ScheduleImmediately
)
3627 // For now this AutoTunnel stuff is specific to Mac OS X.
3628 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
3629 #if APPLE_OSX_mDNSResponder
3630 // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
3631 // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
3632 // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
3633 // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
3634 // returns results for both at the same time.
3635 if (RRTypeIsAddressType(question
->qtype
) && question
->AuthInfo
&& question
->AuthInfo
->AutoTunnel
&& question
->QuestionCallback
!= AutoTunnelCallback
)
3637 question
->NoAnswer
= NoAnswer_Suspended
;
3638 AddNewClientTunnel(m
, question
);
3641 #endif // APPLE_OSX_mDNSResponder
3643 if (!question
->DuplicateOf
)
3645 LogOperation("ActivateUnicastQuery: %##s %s%s%s",
3646 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->AuthInfo
? " (Private)" : "", ScheduleImmediately
? " ScheduleImmediately" : "");
3647 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
3648 if (question
->LongLived
)
3650 question
->state
= LLQ_InitialRequest
;
3651 question
->id
= zeroOpaque64
;
3652 question
->servPort
= zeroIPPort
;
3653 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
3655 if (ScheduleImmediately
)
3657 question
->ThisQInterval
= InitialQuestionInterval
;
3658 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
3659 SetNextQueryTime(m
, question
);
3664 // Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep.
3665 // Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up.
3666 // Normally, the platform support layer below mDNSCore should call this, not the client layer above.
3667 // Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call
3668 // mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just
3669 // found itself in a new network environment. For example, if the Ethernet hardware indicates that the
3670 // cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse)
3671 // to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc.
3672 // While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network
3673 // traffic, so it should only be called when there is legitimate reason to believe the machine
3674 // may have become attached to a new network.
3675 mDNSexport
void mDNSCoreMachineSleep(mDNS
*const m
, mDNSBool sleepstate
)
3681 m
->SleepState
= sleepstate
;
3682 LogOperation("%s at %ld", sleepstate
? "Sleeping" : "Waking", m
->timenow
);
3686 #ifndef UNICAST_DISABLED
3688 SleepServiceRegistrations(m
);
3689 SleepRecordRegistrations(m
);
3691 // Mark all the records we need to deregister and send them
3692 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3693 if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
&& rr
->RequireGoodbye
)
3694 rr
->ImmedAnswer
= mDNSInterfaceMark
;
3704 #ifndef UNICAST_DISABLED
3705 // On wake, retrigger all our uDNS questions
3706 if (m
->CurrentQuestion
)
3707 LogMsg("RestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m
->CurrentQuestion
->qname
.c
, DNSTypeName(m
->CurrentQuestion
->qtype
));
3708 m
->CurrentQuestion
= m
->Questions
;
3709 while (m
->CurrentQuestion
)
3711 q
= m
->CurrentQuestion
;
3712 m
->CurrentQuestion
= m
->CurrentQuestion
->next
;
3713 if (!mDNSOpaque16IsZero(q
->TargetQID
)) ActivateUnicastQuery(m
, q
, mDNStrue
);
3715 // and reactivtate service registrations
3716 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
);
3717 LogOperation("WakeServiceRegistrations %d %d", m
->timenow
, m
->NextSRVUpdate
);
3719 // 1. Retrigger all our mDNS questions
3720 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
3721 if (mDNSOpaque16IsZero(q
->TargetQID
) && ActiveQuestion(q
))
3723 q
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
3724 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
3725 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
;
3726 q
->RecentAnswerPkts
= 0;
3727 ExpireDupSuppressInfo(q
->DupSuppress
, m
->timenow
);
3728 m
->NextScheduledQuery
= m
->timenow
;
3731 // 2. Re-validate our cache records
3732 m
->NextCacheCheck
= m
->timenow
;
3733 FORALL_CACHERECORDS(slot
, cg
, cr
)
3734 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForWake
);
3736 // 3. Retrigger probing and announcing for all our authoritative records
3737 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3738 if (AuthRecord_uDNS(rr
))
3740 ActivateUnicastRegistration(m
, rr
);
3744 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
3745 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
3746 rr
->AnnounceCount
= InitialAnnounceCount
;
3747 InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
));
3754 // ***************************************************************************
3755 #if COMPILER_LIKES_PRAGMA_MARK
3757 #pragma mark - Packet Reception Functions
3760 #define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo)
3762 mDNSlocal mDNSu8
*GenerateUnicastResponse(const DNSMessage
*const query
, const mDNSu8
*const end
,
3763 const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, DNSMessage
*const response
, AuthRecord
*ResponseRecords
)
3765 mDNSu8
*responseptr
= response
->data
;
3766 const mDNSu8
*const limit
= response
->data
+ sizeof(response
->data
);
3767 const mDNSu8
*ptr
= query
->data
;
3769 mDNSu32 maxttl
= 0x70000000;
3772 // Initialize the response fields so we can answer the questions
3773 InitializeDNSMessage(&response
->h
, query
->h
.id
, ResponseFlags
);
3776 // *** 1. Write out the list of questions we are actually going to answer with this packet
3781 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
3784 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &q
); // get the question...
3785 if (!ptr
) return(mDNSNULL
);
3787 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
) // and search our list of proposed answers
3789 if (rr
->NR_AnswerTo
== ptr
) // If we're going to generate a record answering this question
3790 { // then put the question in the question section
3791 responseptr
= putQuestion(response
, responseptr
, limit
, &q
.qname
, q
.qtype
, q
.qclass
);
3792 if (!responseptr
) { debugf("GenerateUnicastResponse: Ran out of space for questions!"); return(mDNSNULL
); }
3793 break; // break out of the ResponseRecords loop, and go on to the next question
3798 if (response
->h
.numQuestions
== 0) { LogMsg("GenerateUnicastResponse: ERROR! Why no questions?"); return(mDNSNULL
); }
3802 // *** 2. Write Answers
3804 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
3805 if (rr
->NR_AnswerTo
)
3807 mDNSu8
*p
= PutResourceRecordCappedTTL(response
, responseptr
, &response
->h
.numAnswers
, &rr
->resrec
, maxttl
);
3808 if (p
) responseptr
= p
;
3809 else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response
->h
.flags
.b
[0] |= kDNSFlag0_TC
; }
3813 // *** 3. Write Additionals
3815 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
3816 if (rr
->NR_AdditionalTo
&& !rr
->NR_AnswerTo
)
3818 mDNSu8
*p
= PutResourceRecordCappedTTL(response
, responseptr
, &response
->h
.numAdditionals
, &rr
->resrec
, maxttl
);
3819 if (p
) responseptr
= p
;
3820 else debugf("GenerateUnicastResponse: No more space for additionals");
3823 return(responseptr
);
3826 // AuthRecord *our is our Resource Record
3827 // CacheRecord *pkt is the Resource Record from the response packet we've witnessed on the network
3828 // Returns 0 if there is no conflict
3829 // Returns +1 if there was a conflict and we won
3830 // Returns -1 if there was a conflict and we lost and have to rename
3831 mDNSlocal
int CompareRData(AuthRecord
*our
, CacheRecord
*pkt
)
3833 mDNSu8 ourdata
[256], *ourptr
= ourdata
, *ourend
;
3834 mDNSu8 pktdata
[256], *pktptr
= pktdata
, *pktend
;
3835 if (!our
) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
3836 if (!pkt
) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
3838 ourend
= putRData(mDNSNULL
, ourdata
, ourdata
+ sizeof(ourdata
), &our
->resrec
);
3839 pktend
= putRData(mDNSNULL
, pktdata
, pktdata
+ sizeof(pktdata
), &pkt
->resrec
);
3840 while (ourptr
< ourend
&& pktptr
< pktend
&& *ourptr
== *pktptr
) { ourptr
++; pktptr
++; }
3841 if (ourptr
>= ourend
&& pktptr
>= pktend
) return(0); // If data identical, not a conflict
3843 if (ourptr
>= ourend
) return(-1); // Our data ran out first; We lost
3844 if (pktptr
>= pktend
) return(+1); // Packet data ran out first; We won
3845 if (*pktptr
> *ourptr
) return(-1); // Our data is numerically lower; We lost
3846 if (*pktptr
< *ourptr
) return(+1); // Packet data is numerically lower; We won
3848 LogMsg("CompareRData ERROR: Invalid state");
3852 // See if we have an authoritative record that's identical to this packet record,
3853 // whose canonical DependentOn record is the specified master record.
3854 // The DependentOn pointer is typically used for the TXT record of service registrations
3855 // It indicates that there is no inherent conflict detection for the TXT record
3856 // -- it depends on the SRV record to resolve name conflicts
3857 // If we find any identical ResourceRecords in our authoritative list, then follow their DependentOn
3858 // pointer chain (if any) to make sure we reach the canonical DependentOn record
3859 // If the record has no DependentOn, then just return that record's pointer
3860 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
3861 mDNSlocal mDNSBool
MatchDependentOn(const mDNS
*const m
, const CacheRecord
*const pktrr
, const AuthRecord
*const master
)
3863 const AuthRecord
*r1
;
3864 for (r1
= m
->ResourceRecords
; r1
; r1
=r1
->next
)
3866 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
3868 const AuthRecord
*r2
= r1
;
3869 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
3870 if (r2
== master
) return(mDNStrue
);
3873 for (r1
= m
->DuplicateRecords
; r1
; r1
=r1
->next
)
3875 if (IdenticalResourceRecord(&r1
->resrec
, &pktrr
->resrec
))
3877 const AuthRecord
*r2
= r1
;
3878 while (r2
->DependentOn
) r2
= r2
->DependentOn
;
3879 if (r2
== master
) return(mDNStrue
);
3885 // Find the canonical RRSet pointer for this RR received in a packet.
3886 // If we find any identical AuthRecord in our authoritative list, then follow its RRSet
3887 // pointers (if any) to make sure we return the canonical member of this name/type/class
3888 // Returns NULL if we don't have any local RRs that are identical to the one from the packet
3889 mDNSlocal
const AuthRecord
*FindRRSet(const mDNS
*const m
, const CacheRecord
*const pktrr
)
3891 const AuthRecord
*rr
;
3892 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
3894 if (IdenticalResourceRecord(&rr
->resrec
, &pktrr
->resrec
))
3896 while (rr
->RRSet
&& rr
!= rr
->RRSet
) rr
= rr
->RRSet
;
3903 // PacketRRConflict is called when we've received an RR (pktrr) which has the same name
3904 // as one of our records (our) but different rdata.
3905 // 1. If our record is not a type that's supposed to be unique, we don't care.
3906 // 2a. If our record is marked as dependent on some other record for conflict detection, ignore this one.
3907 // 2b. If the packet rr exactly matches one of our other RRs, and *that* record's DependentOn pointer
3908 // points to our record, ignore this conflict (e.g. the packet record matches one of our
3909 // TXT records, and that record is marked as dependent on 'our', its SRV record).
3910 // 3. If we have some *other* RR that exactly matches the one from the packet, and that record and our record
3911 // are members of the same RRSet, then this is not a conflict.
3912 mDNSlocal mDNSBool
PacketRRConflict(const mDNS
*const m
, const AuthRecord
*const our
, const CacheRecord
*const pktrr
)
3914 const AuthRecord
*ourset
= our
->RRSet
? our
->RRSet
: our
;
3916 // If not supposed to be unique, not a conflict
3917 if (!(our
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)) return(mDNSfalse
);
3919 // If a dependent record, not a conflict
3920 if (our
->DependentOn
|| MatchDependentOn(m
, pktrr
, our
)) return(mDNSfalse
);
3922 // If the pktrr matches a member of ourset, not a conflict
3923 if (FindRRSet(m
, pktrr
) == ourset
) return(mDNSfalse
);
3925 // Okay, this is a conflict
3929 // NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change
3930 // the record list and/or question list.
3931 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
3932 mDNSlocal
void ResolveSimultaneousProbe(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
3933 DNSQuestion
*q
, AuthRecord
*our
)
3936 const mDNSu8
*ptr
= LocateAuthorities(query
, end
);
3937 mDNSBool FoundUpdate
= mDNSfalse
;
3939 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
3941 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
3943 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
3945 FoundUpdate
= mDNStrue
;
3946 if (PacketRRConflict(m
, our
, &m
->rec
.r
))
3948 int result
= (int)our
->resrec
.rrclass
- (int)m
->rec
.r
.resrec
.rrclass
;
3949 if (!result
) result
= (int)our
->resrec
.rrtype
- (int)m
->rec
.r
.resrec
.rrtype
;
3950 if (!result
) result
= CompareRData(our
, &m
->rec
.r
);
3952 LogOperation("ResolveSimultaneousProbe: %##s (%s): We won", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
3953 else if (result
< 0)
3955 LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
3956 mDNS_Deregister_internal(m
, our
, mDNS_Dereg_conflict
);
3961 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3964 LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our
->resrec
.name
->c
, DNSTypeName(our
->resrec
.rrtype
));
3966 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
3969 mDNSlocal CacheRecord
*FindIdenticalRecordInCache(const mDNS
*const m
, const ResourceRecord
*const pktrr
)
3971 mDNSu32 slot
= HashSlot(pktrr
->name
);
3972 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, pktrr
);
3974 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
3975 if (pktrr
->InterfaceID
== rr
->resrec
.InterfaceID
&& IdenticalSameNameRecord(pktrr
, &rr
->resrec
)) break;
3979 // ProcessQuery examines a received query to see if we have any answers to give
3980 mDNSlocal mDNSu8
*ProcessQuery(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*const end
,
3981 const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
, mDNSBool LegacyQuery
, mDNSBool QueryWasMulticast
,
3982 mDNSBool QueryWasLocalUnicast
, DNSMessage
*const response
)
3984 mDNSBool FromLocalSubnet
= srcaddr
&& AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
3985 AuthRecord
*ResponseRecords
= mDNSNULL
;
3986 AuthRecord
**nrp
= &ResponseRecords
;
3987 CacheRecord
*ExpectedAnswers
= mDNSNULL
; // Records in our cache we expect to see updated
3988 CacheRecord
**eap
= &ExpectedAnswers
;
3989 DNSQuestion
*DupQuestions
= mDNSNULL
; // Our questions that are identical to questions in this packet
3990 DNSQuestion
**dqp
= &DupQuestions
;
3991 mDNSs32 delayresponse
= 0;
3992 mDNSBool SendLegacyResponse
= mDNSfalse
;
3993 const mDNSu8
*ptr
= query
->data
;
3994 mDNSu8
*responseptr
= mDNSNULL
;
3999 // *** 1. Parse Question Section and mark potential answers
4001 for (i
=0; i
<query
->h
.numQuestions
; i
++) // For each question...
4003 mDNSBool QuestionNeedsMulticastResponse
;
4004 int NumAnswersForThisQuestion
= 0;
4005 DNSQuestion pktq
, *q
;
4006 ptr
= getQuestion(query
, ptr
, end
, InterfaceID
, &pktq
); // get the question...
4007 if (!ptr
) goto exit
;
4009 // The only queries that *need* a multicast response are:
4010 // * Queries sent via multicast
4012 // * that don't have the kDNSQClass_UnicastResponse bit set
4013 // These queries need multicast responses because other clients will:
4014 // * suppress their own identical questions when they see these questions, and
4015 // * expire their cache records if they don't see the expected responses
4016 // For other queries, we may still choose to send the occasional multicast response anyway,
4017 // to keep our neighbours caches warm, and for ongoing conflict detection.
4018 QuestionNeedsMulticastResponse
= QueryWasMulticast
&& !LegacyQuery
&& !(pktq
.qclass
& kDNSQClass_UnicastResponse
);
4019 // Clear the UnicastResponse flag -- don't want to confuse the rest of the code that follows later
4020 pktq
.qclass
&= ~kDNSQClass_UnicastResponse
;
4022 // Note: We use the m->CurrentRecord mechanism here because calling ResolveSimultaneousProbe
4023 // can result in user callbacks which may change the record list and/or question list.
4024 // Also note: we just mark potential answer records here, without trying to build the
4025 // "ResponseRecords" list, because we don't want to risk user callbacks deleting records
4026 // from that list while we're in the middle of trying to build it.
4027 if (m
->CurrentRecord
)
4028 LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4029 m
->CurrentRecord
= m
->ResourceRecords
;
4030 while (m
->CurrentRecord
)
4032 rr
= m
->CurrentRecord
;
4033 m
->CurrentRecord
= rr
->next
;
4034 if (ResourceRecordAnswersQuestion(&rr
->resrec
, &pktq
) && (QueryWasMulticast
|| QueryWasLocalUnicast
|| rr
->AllowRemoteQuery
))
4036 if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
4037 ResolveSimultaneousProbe(m
, query
, end
, &pktq
, rr
);
4038 else if (ResourceRecordIsValidAnswer(rr
))
4040 NumAnswersForThisQuestion
++;
4042 // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
4043 // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
4044 // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later)
4045 // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
4046 // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
4047 // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
4048 if (QuestionNeedsMulticastResponse
|| (!FromLocalSubnet
&& QueryWasMulticast
&& !LegacyQuery
))
4050 // We only mark this question for sending if it is at least one second since the last time we multicast it
4051 // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
4052 // This is to guard against the case where someone blasts us with queries as fast as they can.
4053 if (m
->timenow
- (rr
->LastMCTime
+ mDNSPlatformOneSecond
) >= 0 ||
4054 (rr
->LastMCInterface
!= mDNSInterfaceMark
&& rr
->LastMCInterface
!= InterfaceID
))
4055 rr
->NR_AnswerTo
= (mDNSu8
*)~0;
4057 else if (!rr
->NR_AnswerTo
) rr
->NR_AnswerTo
= LegacyQuery
? ptr
: (mDNSu8
*)~1;
4062 // If we couldn't answer this question, someone else might be able to,
4063 // so use random delay on response to reduce collisions
4064 if (NumAnswersForThisQuestion
== 0) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
4066 // We only do the following accelerated cache expiration processing and duplicate question suppression processing
4067 // for multicast queries with multicast responses.
4068 // For any query generating a unicast response we don't do this because we can't assume we will see the response
4069 if (QuestionNeedsMulticastResponse
)
4071 const mDNSu32 slot
= HashSlot(&pktq
.qname
);
4072 CacheGroup
*cg
= CacheGroupForName(m
, slot
, pktq
.qnamehash
, &pktq
.qname
);
4075 // Make a list indicating which of our own cache records we expect to see updated as a result of this query
4076 // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
4077 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
=cr
->next
)
4078 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &pktq
) && cr
->resrec
.rdlength
<= SmallRecordLimit
)
4079 if (!cr
->NextInKAList
&& eap
!= &cr
->NextInKAList
)
4082 eap
= &cr
->NextInKAList
;
4083 if (cr
->MPUnansweredQ
== 0 || m
->timenow
- cr
->MPLastUnansweredQT
>= mDNSPlatformOneSecond
)
4085 // Although MPUnansweredQ is only really used for multi-packet query processing,
4086 // we increment it for both single-packet and multi-packet queries, so that it stays in sync
4087 // with the MPUnansweredKA value, which by necessity is incremented for both query types.
4088 cr
->MPUnansweredQ
++;
4089 cr
->MPLastUnansweredQT
= m
->timenow
;
4090 cr
->MPExpectingKA
= mDNStrue
;
4094 // Check if this question is the same as any of mine.
4095 // We only do this for non-truncated queries. Right now it would be too complicated to try
4096 // to keep track of duplicate suppression state between multiple packets, especially when we
4097 // can't guarantee to receive all of the Known Answer packets that go with a particular query.
4098 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
4099 for (q
= m
->Questions
; q
; q
=q
->next
)
4100 if (!q
->Target
.type
&& ActiveQuestion(q
) && m
->timenow
- q
->LastQTxTime
> mDNSPlatformOneSecond
/ 4)
4101 if (!q
->InterfaceID
|| q
->InterfaceID
== InterfaceID
)
4102 if (q
->NextInDQList
== mDNSNULL
&& dqp
!= &q
->NextInDQList
)
4103 if (q
->qtype
== pktq
.qtype
&&
4104 q
->qclass
== pktq
.qclass
&&
4105 q
->qnamehash
== pktq
.qnamehash
&& SameDomainName(&q
->qname
, &pktq
.qname
))
4106 { *dqp
= q
; dqp
= &q
->NextInDQList
; }
4111 // *** 2. Now we can safely build the list of marked answers
4113 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) // Now build our list of potential answers
4114 if (rr
->NR_AnswerTo
) // If we marked the record...
4115 AddRecordToResponseList(&nrp
, rr
, mDNSNULL
); // ... add it to the list
4118 // *** 3. Add additional records
4120 AddAdditionalsToResponseList(m
, ResponseRecords
, &nrp
, InterfaceID
);
4123 // *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list
4125 for (i
=0; i
<query
->h
.numAnswers
; i
++) // For each record in the query's answer section...
4127 // Get the record...
4128 CacheRecord
*ourcacherr
;
4129 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &m
->rec
);
4130 if (!ptr
) goto exit
;
4132 // See if this Known-Answer suppresses any of our currently planned answers
4133 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
4134 if (MustSendRecord(rr
) && ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
4135 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
4137 // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
4138 for (rr
=m
->ResourceRecords
; rr
; rr
=rr
->next
)
4140 // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
4141 if (rr
->ImmedAnswer
== InterfaceID
&& ShouldSuppressKnownAnswer(&m
->rec
.r
, rr
))
4143 if (srcaddr
->type
== mDNSAddrType_IPv4
)
4145 if (mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= zerov4Addr
;
4147 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
4149 if (mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= zerov6Addr
;
4151 if (mDNSIPv4AddressIsZero(rr
->v4Requester
) && mDNSIPv6AddressIsZero(rr
->v6Requester
))
4153 rr
->ImmedAnswer
= mDNSNULL
;
4154 rr
->ImmedUnicast
= mDNSfalse
;
4155 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4156 LogMsg("Suppressed after%4d: %s", m
->timenow
- rr
->ImmedAnswerMarkTime
, ARDisplayString(m
, rr
));
4162 // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
4163 // 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).
4164 ourcacherr
= FindIdenticalRecordInCache(m
, &m
->rec
.r
.resrec
);
4165 if (ourcacherr
&& ourcacherr
->MPExpectingKA
&& m
->timenow
- ourcacherr
->MPLastUnansweredQT
< mDNSPlatformOneSecond
)
4167 ourcacherr
->MPUnansweredKA
++;
4168 ourcacherr
->MPExpectingKA
= mDNSfalse
;
4171 // Having built our ExpectedAnswers list from the questions in this packet, we can definitively
4172 // remove from our ExpectedAnswers list any records that are suppressed in the very same packet.
4173 // For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them.
4174 eap
= &ExpectedAnswers
;
4177 CacheRecord
*cr
= *eap
;
4178 if (cr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalResourceRecord(&m
->rec
.r
.resrec
, &cr
->resrec
))
4179 { *eap
= cr
->NextInKAList
; cr
->NextInKAList
= mDNSNULL
; }
4180 else eap
= &cr
->NextInKAList
;
4183 // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
4186 dqp
= &DupQuestions
;
4189 DNSQuestion
*q
= *dqp
;
4190 if (ResourceRecordAnswersQuestion(&m
->rec
.r
.resrec
, q
))
4191 { *dqp
= q
->NextInDQList
; q
->NextInDQList
= mDNSNULL
; }
4192 else dqp
= &q
->NextInDQList
;
4195 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4199 // *** 5. Cancel any additionals that were added because of now-deleted records
4201 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
4202 if (rr
->NR_AdditionalTo
&& !MustSendRecord(rr
->NR_AdditionalTo
))
4203 { rr
->NR_AnswerTo
= mDNSNULL
; rr
->NR_AdditionalTo
= mDNSNULL
; }
4206 // *** 6. Mark the send flags on the records we plan to send
4208 for (rr
=ResponseRecords
; rr
; rr
=rr
->NextResponse
)
4210 if (rr
->NR_AnswerTo
)
4212 mDNSBool SendMulticastResponse
= mDNSfalse
; // Send modern multicast response
4213 mDNSBool SendUnicastResponse
= mDNSfalse
; // Send modern unicast response (not legacy unicast response)
4215 // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
4216 if (m
->timenow
- (rr
->LastMCTime
+ TicksTTL(rr
)/4) >= 0)
4218 SendMulticastResponse
= mDNStrue
;
4219 // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
4220 // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
4221 // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
4222 if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) rr
->NR_AnswerTo
= (mDNSu8
*)~0;
4225 // If the client insists on a multicast response, then we'd better send one
4226 if (rr
->NR_AnswerTo
== (mDNSu8
*)~0) SendMulticastResponse
= mDNStrue
;
4227 else if (rr
->NR_AnswerTo
== (mDNSu8
*)~1) SendUnicastResponse
= mDNStrue
;
4228 else if (rr
->NR_AnswerTo
) SendLegacyResponse
= mDNStrue
;
4230 if (SendMulticastResponse
|| SendUnicastResponse
)
4232 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4233 rr
->ImmedAnswerMarkTime
= m
->timenow
;
4235 m
->NextScheduledResponse
= m
->timenow
;
4236 // If we're already planning to send this on another interface, just send it on all interfaces
4237 if (rr
->ImmedAnswer
&& rr
->ImmedAnswer
!= InterfaceID
)
4238 rr
->ImmedAnswer
= mDNSInterfaceMark
;
4241 rr
->ImmedAnswer
= InterfaceID
; // Record interface to send it on
4242 if (SendUnicastResponse
) rr
->ImmedUnicast
= mDNStrue
;
4243 if (srcaddr
->type
== mDNSAddrType_IPv4
)
4245 if (mDNSIPv4AddressIsZero(rr
->v4Requester
)) rr
->v4Requester
= srcaddr
->ip
.v4
;
4246 else if (!mDNSSameIPv4Address(rr
->v4Requester
, srcaddr
->ip
.v4
)) rr
->v4Requester
= onesIPv4Addr
;
4248 else if (srcaddr
->type
== mDNSAddrType_IPv6
)
4250 if (mDNSIPv6AddressIsZero(rr
->v6Requester
)) rr
->v6Requester
= srcaddr
->ip
.v6
;
4251 else if (!mDNSSameIPv6Address(rr
->v6Requester
, srcaddr
->ip
.v6
)) rr
->v6Requester
= onesIPv6Addr
;
4255 // If TC flag is set, it means we should expect that additional known answers may be coming in another packet,
4256 // so we allow roughly half a second before deciding to reply (we've observed inter-packet delays of 100-200ms on 802.11)
4257 // else, if record is a shared one, spread responses over 100ms to avoid implosion of simultaneous responses
4258 // else, for a simple unique record reply, we can reply immediately; no need for delay
4259 if (query
->h
.flags
.b
[0] & kDNSFlag0_TC
) delayresponse
= mDNSPlatformOneSecond
* 20; // Divided by 50 = 400ms
4260 else if (rr
->resrec
.RecordType
== kDNSRecordTypeShared
) delayresponse
= mDNSPlatformOneSecond
; // Divided by 50 = 20ms
4262 else if (rr
->NR_AdditionalTo
&& rr
->NR_AdditionalTo
->NR_AnswerTo
== (mDNSu8
*)~0)
4264 // Since additional records are an optimization anyway, we only ever send them on one interface at a time
4265 // If two clients on different interfaces do queries that invoke the same optional additional answer,
4266 // then the earlier client is out of luck
4267 rr
->ImmedAdditional
= InterfaceID
;
4268 // No need to set m->NextScheduledResponse here
4269 // We'll send these additional records when we send them, or not, as the case may be
4274 // *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer
4276 if (delayresponse
&& (!m
->SuppressSending
|| (m
->SuppressSending
- m
->timenow
) < (delayresponse
+ 49) / 50))
4278 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4279 mDNSs32 oldss
= m
->SuppressSending
;
4280 if (oldss
&& delayresponse
)
4281 LogMsg("Current SuppressSending delay%5ld; require%5ld", m
->SuppressSending
- m
->timenow
, (delayresponse
+ 49) / 50);
4283 // Pick a random delay:
4284 // We start with the base delay chosen above (typically either 1 second or 20 seconds),
4285 // and add a random value in the range 0-5 seconds (making 1-6 seconds or 20-25 seconds).
4286 // This is an integer value, with resolution determined by the platform clock rate.
4287 // We then divide that by 50 to get the delay value in ticks. We defer the division until last
4288 // to get better results on platforms with coarse clock granularity (e.g. ten ticks per second).
4289 // The +49 before dividing is to ensure we round up, not down, to ensure that even
4290 // on platforms where the native clock rate is less than fifty ticks per second,
4291 // we still guarantee that the final calculated delay is at least one platform tick.
4292 // We want to make sure we don't ever allow the delay to be zero ticks,
4293 // because if that happens we'll fail the Bonjour Conformance Test.
4294 // Our final computed delay is 20-120ms for normal delayed replies,
4295 // or 400-500ms in the case of multi-packet known-answer lists.
4296 m
->SuppressSending
= m
->timenow
+ (delayresponse
+ (mDNSs32
)mDNSRandom((mDNSu32
)mDNSPlatformOneSecond
*5) + 49) / 50;
4297 if (m
->SuppressSending
== 0) m
->SuppressSending
= 1;
4298 #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
4299 if (oldss
&& delayresponse
)
4300 LogMsg("Set SuppressSending to %5ld", m
->SuppressSending
- m
->timenow
);
4305 // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too
4307 if (SendLegacyResponse
)
4308 responseptr
= GenerateUnicastResponse(query
, end
, InterfaceID
, LegacyQuery
, response
, ResponseRecords
);
4311 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4314 // *** 9. Finally, clear our link chains ready for use next time
4316 while (ResponseRecords
)
4318 rr
= ResponseRecords
;
4319 ResponseRecords
= rr
->NextResponse
;
4320 rr
->NextResponse
= mDNSNULL
;
4321 rr
->NR_AnswerTo
= mDNSNULL
;
4322 rr
->NR_AdditionalTo
= mDNSNULL
;
4325 while (ExpectedAnswers
)
4327 CacheRecord
*cr
= ExpectedAnswers
;
4328 ExpectedAnswers
= cr
->NextInKAList
;
4329 cr
->NextInKAList
= mDNSNULL
;
4331 // For non-truncated queries, we can definitively say that we should expect
4332 // to be seeing a response for any records still left in the ExpectedAnswers list
4333 if (!(query
->h
.flags
.b
[0] & kDNSFlag0_TC
))
4334 if (cr
->UnansweredQueries
== 0 || m
->timenow
- cr
->LastUnansweredTime
>= mDNSPlatformOneSecond
)
4336 cr
->UnansweredQueries
++;
4337 cr
->LastUnansweredTime
= m
->timenow
;
4338 if (cr
->UnansweredQueries
> 1)
4339 debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
4340 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
4341 SetNextCacheCheckTime(m
, cr
);
4344 // If we've seen multiple unanswered queries for this record,
4345 // then mark it to expire in five seconds if we don't get a response by then.
4346 if (cr
->UnansweredQueries
>= MaxUnansweredQueries
)
4348 // Only show debugging message if this record was not about to expire anyway
4349 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
4350 debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
4351 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
4352 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
4354 // Make a guess, based on the multi-packet query / known answer counts, whether we think we
4355 // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
4356 // possible packet loss of up to 20% of the additional KA packets.)
4357 else if (cr
->MPUnansweredQ
* 4 > cr
->MPUnansweredKA
* 5 + 8)
4359 // We want to do this conservatively.
4360 // If there are so many machines on the network that they have to use multi-packet known-answer lists,
4361 // then we don't want them to all hit the network simultaneously with their final expiration queries.
4362 // By setting the record to expire in four minutes, we achieve two things:
4363 // (a) the 90-95% final expiration queries will be less bunched together
4364 // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
4365 mDNSu32 remain
= (mDNSu32
)(RRExpireTime(cr
) - m
->timenow
) / 4;
4366 if (remain
> 240 * (mDNSu32
)mDNSPlatformOneSecond
)
4367 remain
= 240 * (mDNSu32
)mDNSPlatformOneSecond
;
4369 // Only show debugging message if this record was not about to expire anyway
4370 if (RRExpireTime(cr
) - m
->timenow
> 4 * mDNSPlatformOneSecond
)
4371 debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
4372 cr
->UnansweredQueries
, cr
->MPUnansweredQ
, cr
->MPUnansweredKA
, CRDisplayString(m
, cr
));
4374 if (remain
<= 60 * (mDNSu32
)mDNSPlatformOneSecond
)
4375 cr
->UnansweredQueries
++; // Treat this as equivalent to one definite unanswered query
4376 cr
->MPUnansweredQ
= 0; // Clear MPQ/MPKA statistics
4377 cr
->MPUnansweredKA
= 0;
4378 cr
->MPExpectingKA
= mDNSfalse
;
4380 if (remain
< kDefaultReconfirmTimeForNoAnswer
)
4381 remain
= kDefaultReconfirmTimeForNoAnswer
;
4382 mDNS_Reconfirm_internal(m
, cr
, remain
);
4386 while (DupQuestions
)
4388 DNSQuestion
*q
= DupQuestions
;
4389 DupQuestions
= q
->NextInDQList
;
4390 q
->NextInDQList
= mDNSNULL
;
4391 i
= RecordDupSuppressInfo(q
->DupSuppress
, m
->timenow
, InterfaceID
, srcaddr
->type
);
4392 debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s %d", q
->qname
.c
, DNSTypeName(q
->qtype
), InterfaceID
,
4393 srcaddr
->type
== mDNSAddrType_IPv4
? "v4" : "v6", i
);
4396 return(responseptr
);
4399 mDNSlocal
void mDNSCoreReceiveQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
4400 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
4401 const mDNSInterfaceID InterfaceID
)
4403 mDNSu8
*responseend
= mDNSNULL
;
4404 mDNSBool QueryWasLocalUnicast
= srcaddr
&& dstaddr
&&
4405 !mDNSAddrIsDNSMulticast(dstaddr
) && AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
4407 if (!InterfaceID
&& dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
))
4409 LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
4410 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
4411 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
4412 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
4413 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
4414 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
4415 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
4419 verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
4420 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
4421 srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
,
4422 msg
->h
.numQuestions
, msg
->h
.numQuestions
== 1 ? ", " : "s,",
4423 msg
->h
.numAnswers
, msg
->h
.numAnswers
== 1 ? ", " : "s,",
4424 msg
->h
.numAuthorities
, msg
->h
.numAuthorities
== 1 ? "y, " : "ies,",
4425 msg
->h
.numAdditionals
, msg
->h
.numAdditionals
== 1 ? "" : "s");
4427 responseend
= ProcessQuery(m
, msg
, end
, srcaddr
, InterfaceID
,
4428 !mDNSSameIPPort(srcport
, MulticastDNSPort
), mDNSAddrIsDNSMulticast(dstaddr
), QueryWasLocalUnicast
, &m
->omsg
);
4430 if (responseend
) // If responseend is non-null, that means we built a unicast response packet
4432 debugf("Unicast Response: %d Question%s, %d Answer%s, %d Additional%s to %#-15a:%d on %p/%ld",
4433 m
->omsg
.h
.numQuestions
, m
->omsg
.h
.numQuestions
== 1 ? "" : "s",
4434 m
->omsg
.h
.numAnswers
, m
->omsg
.h
.numAnswers
== 1 ? "" : "s",
4435 m
->omsg
.h
.numAdditionals
, m
->omsg
.h
.numAdditionals
== 1 ? "" : "s",
4436 srcaddr
, mDNSVal16(srcport
), InterfaceID
, srcaddr
->type
);
4437 mDNSSendDNSMessage(m
, &m
->omsg
, responseend
, InterfaceID
, mDNSNULL
, srcaddr
, srcport
, mDNSNULL
, mDNSNULL
);
4442 mDNSlocal mDNSBool
TrustedSource(const mDNS
*const m
, const mDNSAddr
*const srcaddr
)
4446 (void)srcaddr
; // Unused
4447 for (s
= m
->DNSServers
; s
; s
= s
->next
)
4448 if (mDNSSameAddress(srcaddr
, &s
->addr
)) return(mDNStrue
);
4453 struct UDPSocket_struct
4455 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
4458 mDNSlocal
const DNSQuestion
*ExpectingUnicastResponseForQuestion(const mDNS
*const m
, const mDNSIPPort port
, const mDNSOpaque16 id
, const DNSQuestion
*const question
)
4461 for (q
= m
->Questions
; q
; q
=q
->next
)
4462 if (mDNSSameIPPort(q
->LocalSocket
? q
->LocalSocket
->port
: MulticastDNSPort
, port
) &&
4463 mDNSSameOpaque16(q
->TargetQID
, id
) &&
4464 q
->qtype
== question
->qtype
&&
4465 q
->qclass
== question
->qclass
&&
4466 q
->qnamehash
== question
->qnamehash
&&
4467 SameDomainName(&q
->qname
, &question
->qname
))
4472 mDNSlocal mDNSBool
ExpectingUnicastResponseForRecord(mDNS
*const m
, const mDNSAddr
*const srcaddr
, const mDNSBool SrcLocal
, const mDNSIPPort port
, const mDNSOpaque16 id
, const CacheRecord
*const rr
)
4477 for (q
= m
->Questions
; q
; q
=q
->next
)
4478 if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
4480 if (!mDNSOpaque16IsZero(q
->TargetQID
))
4482 debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id
), mDNSVal16(q
->TargetQID
), CRDisplayString(m
, rr
));
4483 if (mDNSSameOpaque16(q
->TargetQID
, id
))
4485 if (mDNSSameIPPort(q
->LocalSocket
? q
->LocalSocket
->port
: MulticastDNSPort
, port
)) return(mDNStrue
);
4486 // if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
4487 // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
4488 // if (TrustedSource(m, srcaddr)) return(mDNStrue);
4489 LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a] from %#a: %s",
4490 q
->qname
.c
, DNSTypeName(q
->qtype
), &q
->Target
, srcaddr
, CRDisplayString(m
, rr
));
4496 if (SrcLocal
&& q
->ExpectUnicastResp
&& (mDNSu32
)(m
->timenow
- q
->ExpectUnicastResp
) < (mDNSu32
)(mDNSPlatformOneSecond
*2))
4503 mDNSexport CacheRecord
*CreateNewCacheEntry(mDNS
*const m
, const mDNSu32 slot
, CacheGroup
*cg
)
4505 CacheRecord
*rr
= mDNSNULL
;
4507 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
4508 // Currently this applies only to rdata types containing more than one domainname,
4509 // or types where the domainname is not the last item in the structure
4511 switch (m
->rec
.r
.resrec
.rrtype
)
4513 case kDNSType_SOA
: RDLength
= sizeof(rdataSOA
); break;
4514 case kDNSType_RP
: RDLength
= sizeof(rdataRP
); break;
4515 case kDNSType_PX
: RDLength
= sizeof(rdataPX
); break;
4516 default: RDLength
= m
->rec
.r
.resrec
.rdlength
; break;
4519 if (!m
->rec
.r
.resrec
.InterfaceID
) debugf("CreateNewCacheEntry %s", CRDisplayString(m
, &m
->rec
.r
));
4521 //if (RDLength > InlineCacheRDSize)
4522 // LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
4524 if (!cg
) cg
= GetCacheGroup(m
, slot
, &m
->rec
.r
.resrec
); // If we don't have a CacheGroup for this name, make one now
4525 if (cg
) rr
= GetCacheRecord(m
, cg
, RDLength
); // Make a cache record, being careful not to recycle cg
4526 if (!rr
) NoCacheAnswer(m
, &m
->rec
.r
);
4529 RData
*saveptr
= rr
->resrec
.rdata
; // Save the rr->resrec.rdata pointer
4530 *rr
= m
->rec
.r
; // Block copy the CacheRecord object
4531 rr
->resrec
.rdata
= saveptr
; // Restore rr->resrec.rdata after the structure assignment
4532 rr
->resrec
.name
= cg
->name
; // And set rr->resrec.name to point into our CacheGroup header
4534 // If this is an oversized record with external storage allocated, copy rdata to external storage
4535 if (rr
->resrec
.rdata
== (RData
*)&rr
->rdatastorage
&& RDLength
> InlineCacheRDSize
)
4536 LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
4537 else if (rr
->resrec
.rdata
!= (RData
*)&rr
->rdatastorage
&& RDLength
<= InlineCacheRDSize
)
4538 LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m
->rec
.r
.resrec
.name
->c
);
4539 if (RDLength
> InlineCacheRDSize
)
4540 mDNSPlatformMemCopy(rr
->resrec
.rdata
, m
->rec
.r
.resrec
.rdata
, sizeofRDataHeader
+ RDLength
);
4542 rr
->next
= mDNSNULL
; // Clear 'next' pointer
4543 *(cg
->rrcache_tail
) = rr
; // Append this record to tail of cache slot list
4544 cg
->rrcache_tail
= &(rr
->next
); // Advance tail pointer
4545 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
4546 rr
->DelayDelivery
= NonZeroTime(m
->timenow
);
4547 else if (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
&& // If marked unique,
4548 rr
->resrec
.rdata
->MaxRDLength
!= 0) // and non-negative, assume we may have
4549 rr
->DelayDelivery
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
); // to delay delivery of this 'add' event
4551 rr
->DelayDelivery
= CheckForSoonToExpireRecords(m
, rr
->resrec
.name
, rr
->resrec
.namehash
, slot
);
4553 CacheRecordAdd(m
, rr
); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
4558 mDNSlocal
void RefreshCacheRecord(mDNS
*const m
, CacheRecord
*rr
, mDNSu32 ttl
)
4560 rr
->TimeRcvd
= m
->timenow
;
4561 rr
->resrec
.rroriginalttl
= ttl
;
4562 rr
->UnansweredQueries
= 0;
4563 rr
->MPUnansweredQ
= 0;
4564 rr
->MPUnansweredKA
= 0;
4565 rr
->MPExpectingKA
= mDNSfalse
;
4566 SetNextCacheCheckTime(m
, rr
);
4569 mDNSexport
void GrantCacheExtensions(mDNS
*const m
, DNSQuestion
*q
, mDNSu32 lease
)
4572 const mDNSu32 slot
= HashSlot(&q
->qname
);
4573 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
4574 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4575 if (rr
->CRActiveQuestion
== q
)
4577 //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
4578 RefreshCacheRecord(m
, rr
, lease
);
4582 mDNSlocal mDNSu32
GetEffectiveTTL(const uDNS_LLQType LLQType
, mDNSu32 ttl
) // TTL in seconds
4584 if (LLQType
== uDNS_LLQ_Entire
) ttl
= kLLQ_DefLease
;
4585 else if (LLQType
== uDNS_LLQ_Events
)
4587 // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
4588 if (ttl
== 0xFFFFFFFF) ttl
= 0;
4589 else ttl
= kLLQ_DefLease
;
4591 else // else not LLQ (standard uDNS response)
4593 // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
4594 // also do this check here to make sure we can't get integer overflow below
4595 if (ttl
> 0x8000000UL
) ttl
= 0x8000000UL
;
4597 // Adjustment factor to avoid race condition:
4598 // 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.
4599 // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
4600 // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
4601 // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
4602 // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
4603 // the cached copy at our local caching server will already have expired, so the server will be forced
4604 // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
4607 // For mDNS, TTL zero means "delete this record"
4608 // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
4609 // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
4610 // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
4611 // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
4612 if (ttl
< 15) ttl
= 15;
4618 // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
4619 // the record list and/or question list.
4620 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
4621 mDNSlocal
void mDNSCoreReceiveResponse(mDNS
*const m
,
4622 const DNSMessage
*const response
, const mDNSu8
*end
,
4623 const mDNSAddr
*srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
,
4624 const mDNSInterfaceID InterfaceID
)
4627 mDNSBool ResponseMCast
= dstaddr
&& mDNSAddrIsDNSMulticast(dstaddr
);
4628 mDNSBool ResponseSrcLocal
= !srcaddr
|| AddressIsLocalSubnet(m
, InterfaceID
, srcaddr
);
4629 uDNS_LLQType LLQType
= uDNS_recvLLQResponse(m
, response
, end
, srcaddr
, srcport
);
4631 // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
4632 // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
4633 // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
4634 CacheRecord
*CacheFlushRecords
= (CacheRecord
*)1;
4635 CacheRecord
**cfp
= &CacheFlushRecords
;
4637 // All records in a DNS response packet are treated as equally valid statements of truth. If we want
4638 // to guard against spoof responses, then the only credible protection against that is cryptographic
4639 // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
4640 int firstauthority
= response
->h
.numAnswers
;
4641 int firstadditional
= firstauthority
+ response
->h
.numAuthorities
;
4642 int totalrecords
= firstadditional
+ response
->h
.numAdditionals
;
4643 const mDNSu8
*ptr
= response
->data
;
4645 // Currently used only for display in debugging message
4649 debugf("Received Response from %#-15a addressed to %#-15a on %p with "
4650 "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
4651 srcaddr
, dstaddr
, InterfaceID
,
4652 response
->h
.numQuestions
, response
->h
.numQuestions
== 1 ? ", " : "s,",
4653 response
->h
.numAnswers
, response
->h
.numAnswers
== 1 ? ", " : "s,",
4654 response
->h
.numAuthorities
, response
->h
.numAuthorities
== 1 ? "y, " : "ies,",
4655 response
->h
.numAdditionals
, response
->h
.numAdditionals
== 1 ? "" : "s", LLQType
);
4657 if (LLQType
== uDNS_LLQ_Ignore
) return;
4659 // 1. We ignore questions (if any) in mDNS response packets
4660 // 2. If this is an LLQ response, we handle it much the same
4661 // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
4662 // answer as being the authoritative complete RRSet, and respond by deleting all other
4663 // matching cache records that don't appear in this packet.
4664 // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
4665 if (ResponseMCast
|| LLQType
== uDNS_LLQ_Events
|| (response
->h
.flags
.b
[0] & kDNSFlag0_TC
))
4666 ptr
= LocateAnswers(response
, end
);
4667 // Otherwise, for one-shot queries, any answers in our cache that are not also contained
4668 // in this response packet are immediately deemed to be invalid.
4671 // We could possibly combine this with the similar loop at the end of this function --
4672 // instead of tagging cache records here and then rescuing them if we find them in the answer section,
4673 // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
4674 // which it was received (or refreshed), and then at the end if we find any cache records which
4675 // answer questions in this packet's question section, but which aren't tagged with this packet's
4676 // packet number, then we deduce they are old and delete them
4677 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
4680 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
4681 if (ptr
&& (!dstaddr
|| ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
)))
4684 const mDNSu32 slot
= HashSlot(&q
.qname
);
4685 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
4686 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4687 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
4689 //LogMsg("uDNS marking %s", CRDisplayString(m, rr));
4690 // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
4691 rr
->TimeRcvd
= m
->timenow
- TicksTTL(rr
) - 1;
4692 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4698 for (i
= 0; i
< totalrecords
&& ptr
&& ptr
< end
; i
++)
4700 // All responses sent via LL multicast are acceptable for caching
4701 // All responses received over our outbound TCP connections are acceptable for caching
4702 mDNSBool AcceptableResponse
= ResponseMCast
|| !dstaddr
|| LLQType
;
4703 // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
4704 // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
4706 const mDNSu8 RecordType
=
4707 (i
< firstauthority
) ? (mDNSu8
)kDNSRecordTypePacketAns
:
4708 (i
< firstadditional
) ? (mDNSu8
)kDNSRecordTypePacketAuth
: (mDNSu8
)kDNSRecordTypePacketAdd
;
4709 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, RecordType
, &m
->rec
);
4710 if (!ptr
) goto exit
; // Break out of the loop and clean up our CacheFlushRecords list before exiting
4712 // Don't want to cache OPT or TSIG pseudo-RRs
4713 if (m
->rec
.r
.resrec
.rrtype
== kDNSType_OPT
|| m
->rec
.r
.resrec
.rrtype
== kDNSType_TSIG
)
4714 { m
->rec
.r
.resrec
.RecordType
= 0; continue; }
4716 // When we receive uDNS LLQ responses, we assume a long cache lifetime --
4717 // In the case of active LLQs, we'll get remove events when the records actually do go away
4718 // In the case of polling LLQs, we assume the record remains valid until the next poll
4719 if (!mDNSOpaque16IsZero(response
->h
.id
))
4720 m
->rec
.r
.resrec
.rroriginalttl
= GetEffectiveTTL(LLQType
, m
->rec
.r
.resrec
.rroriginalttl
);
4722 // If response was not sent via LL multicast,
4723 // then see if it answers a recent query of ours, which would also make it acceptable for caching.
4724 if (!AcceptableResponse
) AcceptableResponse
= ExpectingUnicastResponseForRecord(m
, srcaddr
, ResponseSrcLocal
, dstport
, response
->h
.id
, &m
->rec
.r
);
4726 // 1. Check that this packet resource record does not conflict with any of ours
4727 if (mDNSOpaque16IsZero(response
->h
.id
))
4729 if (m
->CurrentRecord
)
4730 LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
4731 m
->CurrentRecord
= m
->ResourceRecords
;
4732 while (m
->CurrentRecord
)
4734 AuthRecord
*rr
= m
->CurrentRecord
;
4735 m
->CurrentRecord
= rr
->next
;
4736 // We accept all multicast responses, and unicast responses resulting from queries we issued
4737 // For other unicast responses, this code accepts them only for responses with an
4738 // (apparently) local source address that pertain to a record of our own that's in probing state
4739 if (!AcceptableResponse
&& !(ResponseSrcLocal
&& rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)) continue;
4740 if (PacketRRMatchesSignature(&m
->rec
.r
, rr
)) // If interface, name, type (if shared record) and class match...
4742 // ... check to see if type and rdata are identical
4743 if (m
->rec
.r
.resrec
.rrtype
== rr
->resrec
.rrtype
&& SameRData(&m
->rec
.r
.resrec
, &rr
->resrec
))
4745 // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
4746 if (m
->rec
.r
.resrec
.rroriginalttl
>= rr
->resrec
.rroriginalttl
/2 || m
->SleepState
)
4748 // If we were planning to send on this -- and only this -- interface, then we don't need to any more
4749 if (rr
->ImmedAnswer
== InterfaceID
) { rr
->ImmedAnswer
= mDNSNULL
; rr
->ImmedUnicast
= mDNSfalse
; }
4753 if (rr
->ImmedAnswer
== mDNSNULL
) { rr
->ImmedAnswer
= InterfaceID
; m
->NextScheduledResponse
= m
->timenow
; }
4754 else if (rr
->ImmedAnswer
!= InterfaceID
) { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
4757 // else, the packet RR has different type or different rdata -- check to see if this is a conflict
4758 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0 && PacketRRConflict(m
, rr
, &m
->rec
.r
))
4760 debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr
-> resrec
.rdatahash
, ARDisplayString(m
, rr
));
4761 debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m
->rec
.r
.resrec
.rdatahash
, CRDisplayString(m
, &m
->rec
.r
));
4763 // If this record is marked DependentOn another record for conflict detection purposes,
4764 // then *that* record has to be bumped back to probing state to resolve the conflict
4765 while (rr
->DependentOn
) rr
= rr
->DependentOn
;
4767 // If we've just whacked this record's ProbeCount, don't need to do it again
4768 if (rr
->ProbeCount
<= DefaultProbeCountForTypeUnique
)
4770 // If we'd previously verified this record, put it back to probing state and try again
4771 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
)
4773 debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
4774 rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
4775 rr
->ProbeCount
= DefaultProbeCountForTypeUnique
+ 1;
4776 InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique
));
4777 RecordProbeFailure(m
, rr
); // Repeated late conflicts also cause us to back off to the slower probing rate
4779 // If we're probing for this record, we just failed
4780 else if (rr
->resrec
.RecordType
== kDNSRecordTypeUnique
)
4782 debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
4783 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
4785 // We assumed this record must be unique, but we were wrong.
4786 // (e.g. There are two mDNSResponders on the same machine giving
4787 // different answers for the reverse mapping record.)
4788 // This is simply a misconfiguration, and we don't try to recover from it.
4789 else if (rr
->resrec
.RecordType
== kDNSRecordTypeKnownUnique
)
4791 debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
4792 rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
4793 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_conflict
);
4796 debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
4797 rr
->resrec
.RecordType
, rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
));
4800 // Else, matching signature, different type or rdata, but not a considered a conflict.
4801 // If the packet record has the cache-flush bit set, then we check to see if we
4802 // have any record(s) of the same type that we should re-assert to rescue them
4803 // (see note about "multi-homing and bridged networks" at the end of this function).
4804 else if (m
->rec
.r
.resrec
.rrtype
== rr
->resrec
.rrtype
)
4805 if ((m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && m
->timenow
- rr
->LastMCTime
> mDNSPlatformOneSecond
/2)
4806 { rr
->ImmedAnswer
= mDNSInterfaceMark
; m
->NextScheduledResponse
= m
->timenow
; }
4811 if (!AcceptableResponse
)
4814 for (cr
= CacheFlushRecords
; cr
!= (CacheRecord
*)1; cr
= cr
->NextInCFList
)
4816 domainname
*target
= GetRRDomainNameTarget(&cr
->resrec
);
4817 if (target
&& cr
->resrec
.rdatahash
== m
->rec
.r
.resrec
.namehash
&& SameDomainName(target
, m
->rec
.r
.resrec
.name
))
4818 { AcceptableResponse
= mDNStrue
; break; }
4822 // 2. See if we want to add this packet resource record to our cache
4823 // We only try to cache answers if we have a cache to put them in
4824 // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
4825 if (!AcceptableResponse
) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m
, &m
->rec
.r
));
4826 if (m
->rrcache_size
&& AcceptableResponse
)
4828 const mDNSu32 slot
= HashSlot(m
->rec
.r
.resrec
.name
);
4829 CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &m
->rec
.r
.resrec
);
4831 // 2a. Check if this packet resource record is already in our cache
4832 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
4834 // If we found this exact resource record, refresh its TTL
4835 if (rr
->resrec
.InterfaceID
== InterfaceID
&& IdenticalSameNameRecord(&m
->rec
.r
.resrec
, &rr
->resrec
))
4837 if (m
->rec
.r
.resrec
.rdlength
> InlineCacheRDSize
)
4838 verbosedebugf("Found record size %5d interface %p already in cache: %s",
4839 m
->rec
.r
.resrec
.rdlength
, InterfaceID
, CRDisplayString(m
, &m
->rec
.r
));
4840 rr
->TimeRcvd
= m
->timenow
;
4842 if (m
->rec
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
)
4844 // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
4845 if (rr
->NextInCFList
== mDNSNULL
&& cfp
!= &rr
->NextInCFList
&& LLQType
!= uDNS_LLQ_Events
)
4846 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
4848 // If this packet record is marked unique, and our previous cached copy was not, then fix it
4849 if (!(rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
))
4852 for (q
= m
->Questions
; q
; q
=q
->next
) if (ResourceRecordAnswersQuestion(&rr
->resrec
, q
)) q
->UniqueAnswers
++;
4853 rr
->resrec
.RecordType
= m
->rec
.r
.resrec
.RecordType
;
4857 if (!mDNSPlatformMemSame(m
->rec
.r
.resrec
.rdata
->u
.data
, rr
->resrec
.rdata
->u
.data
, m
->rec
.r
.resrec
.rdlength
))
4859 // If the rdata of the packet record differs in name capitalization from the record in our cache
4860 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
4861 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
4862 rr
->resrec
.rroriginalttl
= 0;
4863 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4864 SetNextCacheCheckTime(m
, rr
);
4865 // DO NOT break out here -- we want to continue as if we never found it
4867 else if (m
->rec
.r
.resrec
.rroriginalttl
> 0)
4869 //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
4870 RefreshCacheRecord(m
, rr
, m
->rec
.r
.resrec
.rroriginalttl
);
4875 // If the packet TTL is zero, that means we're deleting this record.
4876 // To give other hosts on the network a chance to protest, we push the deletion
4877 // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
4878 // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
4879 // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
4880 debugf("DE for %s", CRDisplayString(m
, rr
));
4881 rr
->resrec
.rroriginalttl
= 1;
4882 rr
->UnansweredQueries
= MaxUnansweredQueries
;
4883 SetNextCacheCheckTime(m
, rr
);
4889 // If packet resource record not in our cache, add it now
4890 // (unless it is just a deletion of a record we never had, in which case we don't care)
4891 if (!rr
&& m
->rec
.r
.resrec
.rroriginalttl
> 0)
4893 rr
= CreateNewCacheEntry(m
, slot
, cg
);
4894 if (rr
&& (rr
->resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) && LLQType
!= uDNS_LLQ_Events
)
4895 { *cfp
= rr
; cfp
= &rr
->NextInCFList
; *cfp
= (CacheRecord
*)1; }
4898 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4902 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
4904 // If we've just received one or more records with their cache flush bits set,
4905 // then scan that cache slot to see if there are any old stale records we need to flush
4906 while (CacheFlushRecords
!= (CacheRecord
*)1)
4908 CacheRecord
*r1
= CacheFlushRecords
, *r2
;
4909 const mDNSu32 slot
= HashSlot(r1
->resrec
.name
);
4910 const CacheGroup
*cg
= CacheGroupForRecord(m
, slot
, &r1
->resrec
);
4911 CacheFlushRecords
= CacheFlushRecords
->NextInCFList
;
4912 r1
->NextInCFList
= mDNSNULL
;
4914 // Look for records in the cache with the same signature as this new one with the cache flush
4915 // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
4916 // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
4917 // We make these TTL adjustments *only* for records that still have *more* than one second
4918 // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
4919 // (and now has half a second remaining) could inadvertently get its life extended, by either
4920 // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
4921 // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
4922 // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
4923 // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
4924 // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
4925 // To avoid this, we need to ensure that the cache flushing operation will only act to
4926 // *decrease* a record's remaining lifetime, never *increase* it.
4927 for (r2
= cg
? cg
->members
: mDNSNULL
; r2
; r2
=r2
->next
)
4928 if (r1
->resrec
.InterfaceID
== r2
->resrec
.InterfaceID
&&
4929 r1
->resrec
.rrtype
== r2
->resrec
.rrtype
&&
4930 r1
->resrec
.rrclass
== r2
->resrec
.rrclass
)
4932 // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
4933 // else, if record is old, mark it to be flushed
4934 if (m
->timenow
- r2
->TimeRcvd
< mDNSPlatformOneSecond
&& RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
4936 // If we find mismatched TTLs in an RRSet, correct them.
4937 // We only do this for records with a TTL of 2 or higher. It's possible to have a
4938 // goodbye announcement with the cache flush bit set (or a case change on record rdata,
4939 // which we treat as a goodbye followed by an addition) and in that case it would be
4940 // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
4941 // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
4942 // because certain early Bonjour devices are known to have this specific mismatch, and
4943 // there's no point filling syslog with messages about something we already know about.
4944 // We also don't log this for uDNS responses, since a caching name server is obliged
4945 // to give us an aged TTL to correct for how long it has held the record,
4946 // so our received TTLs are expected to vary in that case
4947 if (r2
->resrec
.rroriginalttl
!= r1
->resrec
.rroriginalttl
&& r1
->resrec
.rroriginalttl
> 1)
4949 if (!(r2
->resrec
.rroriginalttl
== 240 && r1
->resrec
.rroriginalttl
== 60 && r2
->resrec
.rrtype
== kDNSType_TXT
) &&
4950 mDNSOpaque16IsZero(response
->h
.id
))
4951 LogOperation("Correcting TTL from %4d to %4d for %s",
4952 r2
->resrec
.rroriginalttl
, r1
->resrec
.rroriginalttl
, CRDisplayString(m
, r2
));
4953 r2
->resrec
.rroriginalttl
= r1
->resrec
.rroriginalttl
;
4955 r2
->TimeRcvd
= m
->timenow
;
4957 else // else, if record is old, mark it to be flushed
4959 verbosedebugf("Cache flush %p X %p %s", r1
, r2
, CRDisplayString(m
, r2
));
4960 // We set stale records to expire in one second.
4961 // This gives the owner a chance to rescue it if necessary.
4962 // This is important in the case of multi-homing and bridged networks:
4963 // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
4964 // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
4965 // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
4966 // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
4967 // By delaying the deletion by one second, we give X a change to notice that this bridging has
4968 // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
4970 // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
4971 // final expiration queries for this record.
4973 // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
4974 // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
4975 // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
4976 if (r2
->TimeRcvd
== m
->timenow
&& r2
->resrec
.rroriginalttl
<= 1 && r2
->UnansweredQueries
== MaxUnansweredQueries
)
4978 debugf("Cache flush for DE record %s", CRDisplayString(m
, r2
));
4979 r2
->resrec
.rroriginalttl
= 0;
4980 m
->NextCacheCheck
= m
->timenow
;
4981 m
->NextScheduledEvent
= m
->timenow
;
4983 else if (RRExpireTime(r2
) - m
->timenow
> mDNSPlatformOneSecond
)
4985 // We only set a record to expire in one second if it currently has *more* than a second to live
4986 // If it's already due to expire in a second or less, we just leave it alone
4987 r2
->resrec
.rroriginalttl
= 1;
4988 r2
->UnansweredQueries
= MaxUnansweredQueries
;
4989 r2
->TimeRcvd
= m
->timenow
- 1;
4990 // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
4991 // that we marked for deletion via an explicit DE record
4994 SetNextCacheCheckTime(m
, r2
);
4996 if (r1
->DelayDelivery
) // If we were planning to delay delivery of this record, see if we still need to
4998 // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
4999 r1
->DelayDelivery
= CheckForSoonToExpireRecords(m
, r1
->resrec
.name
, r1
->resrec
.namehash
, slot
);
5000 if (!r1
->DelayDelivery
) CacheRecordDeferredAdd(m
, r1
);
5004 // See if we need to generate negative cache entries for unanswered unicast questions
5005 ptr
= response
->data
;
5006 for (i
= 0; i
< response
->h
.numQuestions
&& ptr
&& ptr
< end
; i
++)
5009 ptr
= getQuestion(response
, ptr
, end
, InterfaceID
, &q
);
5010 if (ptr
&& (!dstaddr
|| ExpectingUnicastResponseForQuestion(m
, dstport
, response
->h
.id
, &q
)))
5012 CacheRecord
*rr
, *neg
= mDNSNULL
;
5013 mDNSu32 slot
= HashSlot(&q
.qname
);
5014 CacheGroup
*cg
= CacheGroupForName(m
, slot
, q
.qnamehash
, &q
.qname
);
5015 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5016 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &q
))
5018 // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
5019 if (rr
->TimeRcvd
+ TicksTTL(rr
) - m
->timenow
> 0) break;
5020 // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
5021 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
) neg
= rr
;
5026 // We start off assuming a negative caching TTL of 60 seconds
5027 // but then look to see if we can find an SOA authority record to tell us a better value we should be using
5028 mDNSu32 negttl
= 60;
5030 const domainname
*name
= &q
.qname
;
5031 mDNSu32 hash
= q
.qnamehash
;
5033 // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
5034 if (response
->h
.numAuthorities
&& (ptr
= LocateAuthorities(response
, end
)) != mDNSNULL
)
5036 ptr
= GetLargeResourceRecord(m
, response
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &m
->rec
);
5037 if (ptr
&& m
->rec
.r
.resrec
.rrtype
== kDNSType_SOA
)
5039 mDNSu32 ttl_s
= m
->rec
.r
.resrec
.rroriginalttl
< m
->rec
.r
.resrec
.rdata
->u
.soa
.min
?
5040 m
->rec
.r
.resrec
.rroriginalttl
: m
->rec
.r
.resrec
.rdata
->u
.soa
.min
;
5041 if (negttl
< ttl_s
) negttl
= ttl_s
;
5043 // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
5044 // with an Authority Section SOA record for d.com, then this is a hint that the authority
5045 // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
5046 // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
5047 if (q
.qtype
== kDNSType_SOA
)
5049 int qcount
= CountLabels(&q
.qname
);
5050 int scount
= CountLabels(m
->rec
.r
.resrec
.name
);
5051 if (qcount
- 1 > scount
)
5052 if (SameDomainName(SkipLeadingLabels(&q
.qname
, qcount
- scount
), m
->rec
.r
.resrec
.name
))
5053 repeat
= qcount
- 1 - scount
;
5056 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5059 // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
5060 // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
5061 // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
5062 // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
5063 // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
5064 // so that we back off our polling rate and don't keep hitting the server continually.
5067 if (negttl
< neg
->resrec
.rroriginalttl
* 2)
5068 negttl
= neg
->resrec
.rroriginalttl
* 2;
5073 negttl
= GetEffectiveTTL(LLQType
, negttl
); // Add 25% grace period if necessary
5075 // If we already had a negative cache entry just update it, else make one or more new negative cache entries
5078 LogOperation("Renewing negative TTL from %d to %d %s", neg
->resrec
.rroriginalttl
, negttl
, CRDisplayString(m
, neg
));
5079 RefreshCacheRecord(m
, neg
, negttl
);
5083 LogOperation("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl
, name
->c
, DNSTypeName(q
.qtype
));
5084 MakeNegativeCacheRecord(m
, name
, hash
, q
.qtype
, q
.qclass
, negttl
);
5085 CreateNewCacheEntry(m
, slot
, cg
);
5086 m
->rec
.r
.resrec
.RecordType
= 0; // Clear RecordType to show we're not still using it
5089 name
= (const domainname
*)(name
->c
+ 1 + name
->c
[0]);
5090 hash
= DomainNameHashValue(name
);
5091 slot
= HashSlot(name
);
5092 cg
= CacheGroupForName(m
, slot
, hash
, name
);
5099 mDNSexport
void MakeNegativeCacheRecord(mDNS
*const m
, const domainname
*const name
, const mDNSu32 namehash
, const mDNSu16 rrtype
, const mDNSu16 rrclass
, mDNSu32 ttl_seconds
)
5101 // Create empty resource record
5102 m
->rec
.r
.resrec
.RecordType
= kDNSRecordTypePacketNegative
;
5103 m
->rec
.r
.resrec
.InterfaceID
= mDNSInterface_Any
;
5104 m
->rec
.r
.resrec
.name
= name
; // Will be updated to point to cg->name when we call CreateNewCacheEntry
5105 m
->rec
.r
.resrec
.rrtype
= rrtype
;
5106 m
->rec
.r
.resrec
.rrclass
= rrclass
;
5107 m
->rec
.r
.resrec
.rroriginalttl
= ttl_seconds
;
5108 m
->rec
.r
.resrec
.rdlength
= 0;
5109 m
->rec
.r
.resrec
.rdestimate
= 0;
5110 m
->rec
.r
.resrec
.namehash
= namehash
;
5111 m
->rec
.r
.resrec
.rdatahash
= 0;
5112 m
->rec
.r
.resrec
.rdata
= (RData
*)&m
->rec
.r
.rdatastorage
;
5113 m
->rec
.r
.resrec
.rdata
->MaxRDLength
= m
->rec
.r
.resrec
.rdlength
;
5115 m
->rec
.r
.NextInKAList
= mDNSNULL
;
5116 m
->rec
.r
.TimeRcvd
= m
->timenow
;
5117 m
->rec
.r
.DelayDelivery
= 0;
5118 m
->rec
.r
.NextRequiredQuery
= m
->timenow
;
5119 m
->rec
.r
.LastUsed
= m
->timenow
;
5120 m
->rec
.r
.CRActiveQuestion
= mDNSNULL
;
5121 m
->rec
.r
.UnansweredQueries
= 0;
5122 m
->rec
.r
.LastUnansweredTime
= 0;
5123 m
->rec
.r
.MPUnansweredQ
= 0;
5124 m
->rec
.r
.MPLastUnansweredQT
= 0;
5125 m
->rec
.r
.MPUnansweredKA
= 0;
5126 m
->rec
.r
.MPExpectingKA
= mDNSfalse
;
5127 m
->rec
.r
.NextInCFList
= mDNSNULL
;
5130 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, void *const pkt
, const mDNSu8
*const end
,
5131 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSIPPort dstport
,
5132 const mDNSInterfaceID InterfaceID
)
5134 mDNSInterfaceID ifid
= InterfaceID
;
5135 DNSMessage
*msg
= (DNSMessage
*)pkt
;
5136 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
5137 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
5138 const mDNSu8 UpdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
5140 mDNSu8
*ptr
= mDNSNULL
;
5141 mDNSBool TLS
= (dstaddr
== (mDNSAddr
*)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
5142 if (TLS
) dstaddr
= mDNSNULL
;
5144 #ifndef UNICAST_DISABLED
5145 if (mDNSSameAddress(srcaddr
, &m
->Router
))
5147 #ifdef _LEGACY_NAT_TRAVERSAL_
5148 if (mDNSSameIPPort(srcport
, SSDPPort
) || (m
->SSDPSocket
&& mDNSSameIPPort(dstport
, m
->SSDPSocket
->port
)))
5151 LNT_ConfigureRouterInfo(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
5156 if (mDNSSameIPPort(srcport
, NATPMPPort
))
5159 uDNS_ReceiveNATPMPPacket(m
, InterfaceID
, pkt
, (mDNSu16
)(end
- (mDNSu8
*)pkt
));
5165 if ((unsigned)(end
- (mDNSu8
*)pkt
) < sizeof(DNSMessageHeader
)) { LogMsg("DNS Message too short"); return; }
5166 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
5167 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
5168 ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
5169 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
5170 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
5171 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
5172 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
5174 if (!m
) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
5176 // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
5177 // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
5178 if (srcaddr
&& !mDNSAddressIsValid(srcaddr
)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr
); return; }
5182 #ifndef UNICAST_DISABLED
5183 if (!dstaddr
|| (!mDNSAddressIsAllDNSLinkGroup(dstaddr
) && (QR_OP
== StdR
|| QR_OP
== UpdR
)))
5184 if (!mDNSOpaque16IsZero(msg
->h
.id
)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses
5186 ifid
= mDNSInterface_Any
;
5187 if (mDNS_LogLevel
>= MDNS_LOG_VERBOSE_DEBUG
)
5188 DumpPacket(m
, mDNSfalse
, TLS
? "TLS" : !dstaddr
? "TCP" : "UDP", srcaddr
, srcport
, dstaddr
, dstport
, msg
, end
);
5189 uDNS_ReceiveMsg(m
, msg
, end
, srcaddr
, srcport
);
5190 // Note: mDNSCore also needs to get access to received unicast responses
5193 if (QR_OP
== StdQ
) mDNSCoreReceiveQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
5194 else if (QR_OP
== StdR
) mDNSCoreReceiveResponse(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, ifid
);
5195 else if (QR_OP
!= UpdR
)
5197 LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
5198 msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1], srcaddr
, mDNSVal16(srcport
), dstaddr
, mDNSVal16(dstport
), InterfaceID
);
5200 // Packet reception often causes a change to the task list:
5201 // 1. Inbound queries can cause us to need to send responses
5202 // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
5203 // 3. Other hosts announcing deletion of shared records can cause us to need to re-assert those records
5204 // 4. Response packets that answer questions may cause our client to issue new questions
5208 // ***************************************************************************
5209 #if COMPILER_LIKES_PRAGMA_MARK
5211 #pragma mark - Searcher Functions
5214 // Targets are considered the same if both queries are untargeted, or
5215 // if both are targeted to the same address+port
5216 // (If Target address is zero, TargetPort is undefined)
5217 #define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
5218 (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
5220 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
5221 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
5222 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
5223 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
5224 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
5226 mDNSlocal DNSQuestion
*FindDuplicateQuestion(const mDNS
*const m
, const DNSQuestion
*const question
)
5229 // Note: A question can only be marked as a duplicate of one that occurs *earlier* in the list.
5230 // This prevents circular references, where two questions are each marked as a duplicate of the other.
5231 // Accordingly, we break out of the loop when we get to 'question', because there's no point searching
5232 // further in the list.
5233 for (q
= m
->Questions
; q
&& q
!= question
; q
=q
->next
) // Scan our list for another question
5234 if (q
->InterfaceID
== question
->InterfaceID
&& // with the same InterfaceID,
5235 SameQTarget(q
, question
) && // and same unicast/multicast target settings
5236 q
->qtype
== question
->qtype
&& // type,
5237 q
->qclass
== question
->qclass
&& // class,
5238 q
->LongLived
== question
->LongLived
&& // and long-lived status matches
5239 (!q
->AuthInfo
|| question
->AuthInfo
) && // to avoid deadlock, don't make public query dup of a private one
5240 q
->qnamehash
== question
->qnamehash
&&
5241 SameDomainName(&q
->qname
, &question
->qname
)) // and name
5246 // This is called after a question is deleted, in case other identical questions were being suppressed as duplicates
5247 mDNSlocal
void UpdateQuestionDuplicates(mDNS
*const m
, DNSQuestion
*const question
)
5250 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
5251 if (q
->DuplicateOf
== question
) // To see if any questions were referencing this as their duplicate
5252 if ((q
->DuplicateOf
= FindDuplicateQuestion(m
, q
)) == mDNSNULL
)
5254 // If q used to be a duplicate, but now is not,
5255 // then inherit the state from the question that's going away
5256 q
->LastQTime
= question
->LastQTime
;
5257 q
->ThisQInterval
= question
->ThisQInterval
;
5258 q
->ExpectUnicastResp
= question
->ExpectUnicastResp
;
5259 q
->LastAnswerPktNum
= question
->LastAnswerPktNum
;
5260 q
->RecentAnswerPkts
= question
->RecentAnswerPkts
;
5261 q
->RequestUnicast
= question
->RequestUnicast
;
5262 q
->LastQTxTime
= question
->LastQTxTime
;
5263 q
->CNAMEReferrals
= question
->CNAMEReferrals
;
5264 q
->nta
= question
->nta
;
5265 q
->servAddr
= question
->servAddr
;
5266 q
->servPort
= question
->servPort
;
5267 q
->qDNSServer
= question
->qDNSServer
;
5268 q
->unansweredQueries
= question
->unansweredQueries
;
5270 q
->TargetQID
= question
->TargetQID
;
5271 q
->LocalSocket
= question
->LocalSocket
;
5273 q
->state
= question
->state
;
5274 // q->tcp = question->tcp;
5275 q
->ReqLease
= question
->ReqLease
;
5276 q
->expire
= question
->expire
;
5277 q
->ntries
= question
->ntries
;
5278 q
->id
= question
->id
;
5280 question
->LocalSocket
= mDNSNULL
;
5281 question
->nta
= mDNSNULL
; // If we've got a GetZoneData in progress, transfer it to the newly active question
5282 // question->tcp = mDNSNULL;
5285 LogOperation("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5289 LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5290 q
->nta
->ZoneDataContext
= q
;
5293 // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
5294 if (question
->tcp
) LogOperation("UpdateQuestionDuplicates did not transfer tcp pointer");
5296 if (question
->state
== LLQ_Established
)
5298 LogOperation("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
5299 question
->state
= 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server
5302 SetNextQueryTime(m
,q
);
5306 // Look up a DNS Server, matching by name in split-dns configurations.
5307 mDNSexport DNSServer
*GetServerForName(mDNS
*m
, const domainname
*name
)
5309 DNSServer
*curmatch
= mDNSNULL
, *p
;
5310 int curmatchlen
= -1, ncount
= name
? CountLabels(name
) : 0;
5312 for (p
= m
->DNSServers
; p
; p
= p
->next
)
5314 int scount
= CountLabels(&p
->domain
);
5315 if (!(p
->flags
& DNSServer_FlagDelete
) && ncount
>= scount
&& scount
> curmatchlen
)
5316 if (SameDomainName(SkipLeadingLabels(name
, ncount
- scount
), &p
->domain
))
5317 { curmatch
= p
; curmatchlen
= scount
; }
5322 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
5323 (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
5325 // Called in normal client context (lock not held)
5326 mDNSlocal
void LLQNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
5331 LogOperation("LLQNATCallback external address:port %.4a:%u", &n
->ExternalAddress
, mDNSVal16(n
->ExternalPort
));
5332 for (q
= m
->Questions
; q
; q
=q
->next
)
5333 if (ActiveQuestion(q
) && !mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
)
5334 startLLQHandshake(m
, q
); // If ExternalPort is zero, will do StartLLQPolling instead
5335 #if APPLE_OSX_mDNSResponder
5336 UpdateAutoTunnelDomainStatuses(m
);
5341 mDNSexport mStatus
mDNS_StartQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
5343 if (question
->Target
.type
&& !ValidQuestionTarget(question
))
5345 LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
5346 question
->Target
.type
, mDNSVal16(question
->TargetPort
));
5347 question
->Target
.type
= mDNSAddrType_None
;
5350 if (!question
->Target
.type
) // No question->Target specified, so clear TargetPort and TargetQID
5352 question
->TargetPort
= zeroIPPort
;
5353 question
->TargetQID
= zeroID
;
5356 question
->TargetQID
=
5357 #ifndef UNICAST_DISABLED
5358 (question
->InterfaceID
!= mDNSInterface_LocalOnly
&& !question
->ForceMCast
&& !IsLocalDomain(&question
->qname
)) ? mDNS_NewMessageID(m
) :
5359 #endif // UNICAST_DISABLED
5362 debugf("mDNS_StartQuery: %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
5364 if (m
->rrcache_size
== 0) // Can't do queries if we have no cache space allocated
5365 return(mStatus_NoCache
);
5371 if (!ValidateDomainName(&question
->qname
))
5373 LogMsg("Attempt to start query with invalid qname %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
5374 return(mStatus_Invalid
);
5377 // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
5379 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) q
= &m
->LocalOnlyQuestions
;
5380 while (*q
&& *q
!= question
) q
=&(*q
)->next
;
5384 LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list",
5385 question
->qname
.c
, DNSTypeName(question
->qtype
));
5386 return(mStatus_AlreadyRegistered
);
5391 // If this question is referencing a specific interface, verify it exists
5392 if (question
->InterfaceID
&& question
->InterfaceID
!= mDNSInterface_LocalOnly
)
5394 NetworkInterfaceInfo
*intf
;
5395 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
5396 if (intf
->InterfaceID
== question
->InterfaceID
) break;
5398 LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
5399 question
->InterfaceID
, question
->qname
.c
, DNSTypeName(question
->qtype
));
5402 // Note: In the case where we already have the answer to this question in our cache, that may be all the client
5403 // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
5404 // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
5405 // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
5406 // that to go out immediately.
5407 question
->next
= mDNSNULL
;
5408 question
->qnamehash
= DomainNameHashValue(&question
->qname
); // MUST do this before FindDuplicateQuestion()
5409 question
->DelayAnswering
= CheckForSoonToExpireRecords(m
, &question
->qname
, question
->qnamehash
, HashSlot(&question
->qname
));
5410 question
->LastQTime
= m
->timenow
;
5411 question
->ThisQInterval
= InitialQuestionInterval
; // MUST be > zero for an active question
5412 question
->ExpectUnicastResp
= 0;
5413 question
->LastAnswerPktNum
= m
->PktNum
;
5414 question
->RecentAnswerPkts
= 0;
5415 question
->CurrentAnswers
= 0;
5416 question
->LargeAnswers
= 0;
5417 question
->UniqueAnswers
= 0;
5418 question
->FlappingInterface1
= mDNSNULL
;
5419 question
->FlappingInterface2
= mDNSNULL
;
5420 question
->AuthInfo
= GetAuthInfoForQuestion(m
, question
); // Must do this before calling FindDuplicateQuestion()
5421 question
->DuplicateOf
= FindDuplicateQuestion(m
, question
);
5422 question
->NextInDQList
= mDNSNULL
;
5423 question
->SendQNow
= mDNSNULL
;
5424 question
->SendOnAll
= mDNSfalse
;
5425 question
->RequestUnicast
= 0;
5426 question
->LastQTxTime
= m
->timenow
;
5427 question
->CNAMEReferrals
= 0;
5429 question
->qDNSServer
= mDNSNULL
;
5430 question
->unansweredQueries
= 0;
5431 question
->nta
= mDNSNULL
;
5432 question
->servAddr
= zeroAddr
;
5433 question
->servPort
= zeroIPPort
;
5434 question
->tcp
= mDNSNULL
;
5435 question
->NoAnswer
= NoAnswer_Normal
;
5437 question
->state
= LLQ_InitialRequest
;
5438 question
->ReqLease
= 0;
5439 question
->expire
= 0;
5440 question
->ntries
= 0;
5441 question
->id
= zeroOpaque64
;
5443 question
->LocalSocket
= mDNSNULL
;
5445 if (question
->DuplicateOf
) question
->AuthInfo
= question
->DuplicateOf
->AuthInfo
;
5447 for (i
=0; i
<DupSuppressInfoSize
; i
++)
5448 question
->DupSuppress
[i
].InterfaceID
= mDNSNULL
;
5450 debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
5451 question
->qname
.c
, DNSTypeName(question
->qtype
), question
->InterfaceID
, m
->timenow
,
5452 question
->LastQTime
+ question
->ThisQInterval
- m
->timenow
,
5453 question
->DelayAnswering
? question
->DelayAnswering
- m
->timenow
: 0,
5454 question
, question
->DuplicateOf
? "duplicate of" : "not duplicate", question
->DuplicateOf
);
5456 if (question
->InterfaceID
== mDNSInterface_LocalOnly
)
5458 if (!m
->NewLocalOnlyQuestions
) m
->NewLocalOnlyQuestions
= question
;
5462 if (!m
->NewQuestions
) m
->NewQuestions
= question
;
5464 // If the question's id is non-zero, then it's Wide Area
5465 // MUST NOT do this Wide Area setup until near the end of
5466 // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
5467 // NS, etc.) and if we haven't finished setting up our own question and setting
5468 // m->NewQuestions if necessary then we could end up recursively re-entering
5469 // this routine with the question list data structures in an inconsistent state.
5470 if (!mDNSOpaque16IsZero(question
->TargetQID
))
5472 // We don't want to make a separate UDP socket for LLQs because (when we're using NAT)
5473 // they all share a single NAT mapping for receiving inbound add/remove events.
5474 if (!question
->DuplicateOf
&& !question
->LongLived
)
5476 question
->LocalSocket
= mDNSPlatformUDPSocket(m
, zeroIPPort
);
5477 debugf("mDNS_StartQuery_internal: dup %p %##s (%s) port %d",
5478 question
->DuplicateOf
, question
->qname
.c
, DNSTypeName(question
->qtype
), question
->LocalSocket
? mDNSVal16(question
->LocalSocket
->port
) : -1);
5479 // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion)
5480 // then we don't fail the query; we just let it use our pre-canned permanent socket, which is okay (it should
5481 // never happen in normal operation, and even if it does we still have our cryptographically strong transaction ID).
5484 question
->qDNSServer
= GetServerForName(m
, &question
->qname
);
5485 ActivateUnicastQuery(m
, question
, mDNSfalse
);
5487 // If long-lived query, and we don't have our NAT mapping active, start it now
5488 if (question
->LongLived
&& !m
->LLQNAT
.clientContext
)
5490 m
->LLQNAT
.Protocol
= NATOp_MapUDP
;
5491 m
->LLQNAT
.IntPort
= m
->UnicastPort4
;
5492 m
->LLQNAT
.RequestedPort
= m
->UnicastPort4
;
5493 m
->LLQNAT
.clientCallback
= LLQNATCallback
;
5494 m
->LLQNAT
.clientContext
= (void*)1; // Means LLQ NAT Traversal is active
5495 mDNS_StartNATOperation_internal(m
, &m
->LLQNAT
);
5498 #if APPLE_OSX_mDNSResponder
5499 if (question
->LongLived
)
5500 UpdateAutoTunnelDomainStatuses(m
);
5504 SetNextQueryTime(m
,question
);
5507 return(mStatus_NoError
);
5511 // CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
5512 mDNSexport
void CancelGetZoneData(mDNS
*const m
, ZoneData
*nta
)
5514 LogOperation("CancelGetZoneData %##s (%s)", nta
->question
.qname
.c
, DNSTypeName(nta
->question
.qtype
));
5515 mDNS_StopQuery_internal(m
, &nta
->question
);
5516 mDNSPlatformMemFree(nta
);
5519 mDNSexport mStatus
mDNS_StopQuery_internal(mDNS
*const m
, DNSQuestion
*const question
)
5521 const mDNSu32 slot
= HashSlot(&question
->qname
);
5522 CacheGroup
*cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
5524 DNSQuestion
**qp
= &m
->Questions
;
5526 //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
5528 if (question
->InterfaceID
== mDNSInterface_LocalOnly
) qp
= &m
->LocalOnlyQuestions
;
5529 while (*qp
&& *qp
!= question
) qp
=&(*qp
)->next
;
5530 if (*qp
) *qp
= (*qp
)->next
;
5534 if (question
->ThisQInterval
>= 0) // Only log error message if the query was supposed to be active
5536 LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
5537 question
->qname
.c
, DNSTypeName(question
->qtype
));
5541 return(mStatus_BadReferenceErr
);
5544 // Take care to cut question from list *before* calling UpdateQuestionDuplicates
5545 UpdateQuestionDuplicates(m
, question
);
5546 // But don't trash ThisQInterval until afterwards.
5547 question
->ThisQInterval
= -1;
5549 // If there are any cache records referencing this as their active question, then see if there is any
5550 // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
5551 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5553 if (rr
->CRActiveQuestion
== question
)
5556 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
5557 if (ActiveQuestion(q
) && ResourceRecordAnswersQuestion(&rr
->resrec
, q
))
5559 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q
, CRDisplayString(m
,rr
));
5560 rr
->CRActiveQuestion
= q
; // Question used to be active; new value may or may not be null
5561 if (!q
) m
->rrcache_active
--; // If no longer active, decrement rrcache_active count
5565 // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
5566 // bump its pointer forward one question.
5567 if (m
->CurrentQuestion
== question
)
5569 debugf("mDNS_StopQuery_internal: Just deleted the currently active question: %##s (%s)",
5570 question
->qname
.c
, DNSTypeName(question
->qtype
));
5571 m
->CurrentQuestion
= question
->next
;
5574 if (m
->NewQuestions
== question
)
5576 debugf("mDNS_StopQuery_internal: Just deleted a new question that wasn't even answered yet: %##s (%s)",
5577 question
->qname
.c
, DNSTypeName(question
->qtype
));
5578 m
->NewQuestions
= question
->next
;
5581 if (m
->NewLocalOnlyQuestions
== question
) m
->NewLocalOnlyQuestions
= question
->next
;
5583 // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
5584 question
->next
= mDNSNULL
;
5586 // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
5588 // And finally, cancel any associated GetZoneData operation that's still running.
5589 // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
5590 // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
5591 // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
5592 // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
5593 if (question
->nta
) { CancelGetZoneData(m
, question
->nta
); question
->nta
= mDNSNULL
; }
5594 if (question
->tcp
) { DisposeTCPConn(question
->tcp
); question
->tcp
= mDNSNULL
; }
5595 if (question
->LocalSocket
) { mDNSPlatformUDPClose(question
->LocalSocket
); question
->LocalSocket
= mDNSNULL
; }
5596 if (!mDNSOpaque16IsZero(question
->TargetQID
) && question
->LongLived
)
5598 // Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
5600 for (q
= m
->Questions
; q
; q
=q
->next
)
5601 if (!mDNSOpaque16IsZero(q
->TargetQID
) && q
->LongLived
) break;
5604 if (!m
->LLQNAT
.clientContext
) // Should never happen, but just in case...
5605 LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL");
5608 LogOperation("Stopping LLQNAT");
5609 mDNS_StopNATOperation_internal(m
, &m
->LLQNAT
);
5610 m
->LLQNAT
.clientContext
= mDNSNULL
; // Means LLQ NAT Traversal not running
5614 // If necessary, tell server it can delete this LLQ state
5615 if (question
->state
== LLQ_Established
)
5617 question
->ReqLease
= 0;
5618 sendLLQRefresh(m
, question
);
5619 // If we need need to make a TCP connection to cancel the LLQ, that's going to take a little while.
5620 // We clear the tcp->question backpointer so that when the TCP connection completes, it doesn't
5621 // crash trying to access our cancelled question, but we don't cancel the TCP operation itself --
5622 // we let that run out its natural course and complete asynchronously.
5625 question
->tcp
->question
= mDNSNULL
;
5626 question
->tcp
= mDNSNULL
;
5629 #if APPLE_OSX_mDNSResponder
5630 UpdateAutoTunnelDomainStatuses(m
);
5634 return(mStatus_NoError
);
5637 mDNSexport mStatus
mDNS_StartQuery(mDNS
*const m
, DNSQuestion
*const question
)
5641 status
= mDNS_StartQuery_internal(m
, question
);
5646 mDNSexport mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
)
5650 status
= mDNS_StopQuery_internal(m
, question
);
5655 // Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
5656 // Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
5657 // We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
5658 // specifically to catch and report if the client callback does try to make API calls
5659 mDNSexport mStatus
mDNS_StopQueryWithRemoves(mDNS
*const m
, DNSQuestion
*const question
)
5665 // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
5666 for (qq
= m
->NewQuestions
; qq
; qq
=qq
->next
) if (qq
== question
) break;
5668 status
= mDNS_StopQuery_internal(m
, question
);
5669 if (status
== mStatus_NoError
&& !qq
)
5672 const mDNSu32 slot
= HashSlot(&question
->qname
);
5673 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, question
->qnamehash
, &question
->qname
);
5674 LogOperation("Generating terminal removes for %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
5675 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
5676 if (rr
->resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& SameNameRecordAnswersQuestion(&rr
->resrec
, question
))
5678 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
5679 if (question
->QuestionCallback
)
5680 question
->QuestionCallback(m
, question
, &rr
->resrec
, mDNSfalse
);
5687 mDNSexport mStatus
mDNS_Reconfirm(mDNS
*const m
, CacheRecord
*const cr
)
5691 status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
5692 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
5697 mDNSexport mStatus
mDNS_ReconfirmByValue(mDNS
*const m
, ResourceRecord
*const rr
)
5699 mStatus status
= mStatus_BadReferenceErr
;
5702 cr
= FindIdenticalRecordInCache(m
, rr
);
5703 debugf("mDNS_ReconfirmByValue: %p %s", cr
, RRDisplayString(m
, rr
));
5704 if (cr
) status
= mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
5705 if (status
== mStatus_NoError
) ReconfirmAntecedents(m
, cr
->resrec
.name
, cr
->resrec
.namehash
, 0);
5710 mDNSexport mStatus
mDNS_StartBrowse(mDNS
*const m
, DNSQuestion
*const question
,
5711 const domainname
*const srv
, const domainname
*const domain
,
5712 const mDNSInterfaceID InterfaceID
, mDNSBool ForceMCast
, mDNSQuestionCallback
*Callback
, void *Context
)
5714 question
->InterfaceID
= InterfaceID
;
5715 question
->Target
= zeroAddr
;
5716 question
->qtype
= kDNSType_PTR
;
5717 question
->qclass
= kDNSClass_IN
;
5718 question
->LongLived
= mDNSfalse
;
5719 question
->ExpectUnique
= mDNSfalse
;
5720 question
->ForceMCast
= ForceMCast
;
5721 question
->ReturnIntermed
= mDNSfalse
;
5722 question
->QuestionCallback
= Callback
;
5723 question
->QuestionContext
= Context
;
5724 if (!ConstructServiceName(&question
->qname
, mDNSNULL
, srv
, domain
)) return(mStatus_BadParamErr
);
5726 #ifndef UNICAST_DISABLED
5727 if (Question_uDNS(question
))
5729 question
->LongLived
= mDNStrue
;
5730 question
->ThisQInterval
= InitialQuestionInterval
;
5731 question
->LastQTime
= m
->timenow
- question
->ThisQInterval
;
5733 #endif // UNICAST_DISABLED
5734 return(mDNS_StartQuery(m
, question
));
5737 mDNSlocal mDNSBool
MachineHasActiveIPv6(mDNS
*const m
)
5739 NetworkInterfaceInfo
*intf
;
5740 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
5741 if (intf
->ip
.type
== mDNSAddrType_IPv6
) return(mDNStrue
);
5745 mDNSlocal
void FoundServiceInfoSRV(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5747 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
5748 mDNSBool PortChanged
= !mDNSSameIPPort(query
->info
->port
, answer
->rdata
->u
.srv
.port
);
5749 if (!AddRecord
) return;
5750 if (answer
->rrtype
!= kDNSType_SRV
) return;
5752 query
->info
->port
= answer
->rdata
->u
.srv
.port
;
5754 // If this is our first answer, then set the GotSRV flag and start the address query
5757 query
->GotSRV
= mDNStrue
;
5758 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
5759 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
5760 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
5761 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
5762 mDNS_StartQuery(m
, &query
->qAv4
);
5763 // Only do the AAAA query if this machine actually has IPv6 active
5764 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
5766 // If this is not our first answer, only re-issue the address query if the target host name has changed
5767 else if ((query
->qAv4
.InterfaceID
!= query
->qSRV
.InterfaceID
&& query
->qAv4
.InterfaceID
!= answer
->InterfaceID
) ||
5768 !SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
))
5770 mDNS_StopQuery(m
, &query
->qAv4
);
5771 if (query
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &query
->qAv6
);
5772 if (SameDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
) && !PortChanged
)
5774 // If we get here, it means:
5775 // 1. This is not our first SRV answer
5776 // 2. The interface ID is different, but the target host and port are the same
5777 // This implies that we're seeing the exact same SRV record on more than one interface, so we should
5778 // make our address queries at least as broad as the original SRV query so that we catch all the answers.
5779 query
->qAv4
.InterfaceID
= query
->qSRV
.InterfaceID
; // Will be mDNSInterface_Any, or a specific interface
5780 query
->qAv6
.InterfaceID
= query
->qSRV
.InterfaceID
;
5784 query
->qAv4
.InterfaceID
= answer
->InterfaceID
;
5785 AssignDomainName(&query
->qAv4
.qname
, &answer
->rdata
->u
.srv
.target
);
5786 query
->qAv6
.InterfaceID
= answer
->InterfaceID
;
5787 AssignDomainName(&query
->qAv6
.qname
, &answer
->rdata
->u
.srv
.target
);
5789 debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query
->qAv4
.qname
.c
, DNSTypeName(query
->qAv4
.qtype
));
5790 mDNS_StartQuery(m
, &query
->qAv4
);
5791 // Only do the AAAA query if this machine actually has IPv6 active
5792 if (MachineHasActiveIPv6(m
)) mDNS_StartQuery(m
, &query
->qAv6
);
5794 else if (query
->ServiceInfoQueryCallback
&& query
->GotADD
&& query
->GotTXT
&& PortChanged
)
5796 if (++query
->Answers
>= 100)
5797 debugf("**** WARNING **** Have given %lu answers for %##s (SRV) %##s %u",
5798 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.srv
.target
.c
,
5799 mDNSVal16(answer
->rdata
->u
.srv
.port
));
5800 query
->ServiceInfoQueryCallback(m
, query
);
5802 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5803 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5806 mDNSlocal
void FoundServiceInfoTXT(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5808 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
5809 if (!AddRecord
) return;
5810 if (answer
->rrtype
!= kDNSType_TXT
) return;
5811 if (answer
->rdlength
> sizeof(query
->info
->TXTinfo
)) return;
5813 query
->GotTXT
= mDNStrue
;
5814 query
->info
->TXTlen
= answer
->rdlength
;
5815 query
->info
->TXTinfo
[0] = 0; // In case answer->rdlength is zero
5816 mDNSPlatformMemCopy(query
->info
->TXTinfo
, answer
->rdata
->u
.txt
.c
, answer
->rdlength
);
5818 verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query
->info
->name
.c
, query
->GotADD
);
5820 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5821 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5822 if (query
->ServiceInfoQueryCallback
&& query
->GotADD
)
5824 if (++query
->Answers
>= 100)
5825 debugf("**** WARNING **** have given %lu answers for %##s (TXT) %#s...",
5826 query
->Answers
, query
->qSRV
.qname
.c
, answer
->rdata
->u
.txt
.c
);
5827 query
->ServiceInfoQueryCallback(m
, query
);
5831 mDNSlocal
void FoundServiceInfo(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
5833 ServiceInfoQuery
*query
= (ServiceInfoQuery
*)question
->QuestionContext
;
5834 //LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
5835 if (!AddRecord
) return;
5837 if (answer
->rrtype
== kDNSType_A
)
5839 query
->info
->ip
.type
= mDNSAddrType_IPv4
;
5840 query
->info
->ip
.ip
.v4
= answer
->rdata
->u
.ipv4
;
5842 else if (answer
->rrtype
== kDNSType_AAAA
)
5844 query
->info
->ip
.type
= mDNSAddrType_IPv6
;
5845 query
->info
->ip
.ip
.v6
= answer
->rdata
->u
.ipv6
;
5849 debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer
->name
->c
, answer
->rrtype
, DNSTypeName(answer
->rrtype
));
5853 query
->GotADD
= mDNStrue
;
5854 query
->info
->InterfaceID
= answer
->InterfaceID
;
5856 verbosedebugf("FoundServiceInfo v%ld: %##s GotTXT=%d", query
->info
->ip
.type
, query
->info
->name
.c
, query
->GotTXT
);
5858 // CAUTION: MUST NOT do anything more with query after calling query->Callback(), because the client's
5859 // callback function is allowed to do anything, including deleting this query and freeing its memory.
5860 if (query
->ServiceInfoQueryCallback
&& query
->GotTXT
)
5862 if (++query
->Answers
>= 100)
5863 debugf(answer
->rrtype
== kDNSType_A
?
5864 "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
5865 "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
5866 query
->Answers
, query
->qSRV
.qname
.c
, &answer
->rdata
->u
.data
);
5867 query
->ServiceInfoQueryCallback(m
, query
);
5871 // On entry, the client must have set the name and InterfaceID fields of the ServiceInfo structure
5872 // If the query is not interface-specific, then InterfaceID may be zero
5873 // Each time the Callback is invoked, the remainder of the fields will have been filled in
5874 // In addition, InterfaceID will be updated to give the interface identifier corresponding to that response
5875 mDNSexport mStatus
mDNS_StartResolveService(mDNS
*const m
,
5876 ServiceInfoQuery
*query
, ServiceInfo
*info
, mDNSServiceInfoQueryCallback
*Callback
, void *Context
)
5881 query
->qSRV
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5882 query
->qSRV
.InterfaceID
= info
->InterfaceID
;
5883 query
->qSRV
.Target
= zeroAddr
;
5884 AssignDomainName(&query
->qSRV
.qname
, &info
->name
);
5885 query
->qSRV
.qtype
= kDNSType_SRV
;
5886 query
->qSRV
.qclass
= kDNSClass_IN
;
5887 query
->qSRV
.LongLived
= mDNSfalse
;
5888 query
->qSRV
.ExpectUnique
= mDNStrue
;
5889 query
->qSRV
.ForceMCast
= mDNSfalse
;
5890 query
->qSRV
.ReturnIntermed
= mDNSfalse
;
5891 query
->qSRV
.QuestionCallback
= FoundServiceInfoSRV
;
5892 query
->qSRV
.QuestionContext
= query
;
5894 query
->qTXT
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5895 query
->qTXT
.InterfaceID
= info
->InterfaceID
;
5896 query
->qTXT
.Target
= zeroAddr
;
5897 AssignDomainName(&query
->qTXT
.qname
, &info
->name
);
5898 query
->qTXT
.qtype
= kDNSType_TXT
;
5899 query
->qTXT
.qclass
= kDNSClass_IN
;
5900 query
->qTXT
.LongLived
= mDNSfalse
;
5901 query
->qTXT
.ExpectUnique
= mDNStrue
;
5902 query
->qTXT
.ForceMCast
= mDNSfalse
;
5903 query
->qTXT
.ReturnIntermed
= mDNSfalse
;
5904 query
->qTXT
.QuestionCallback
= FoundServiceInfoTXT
;
5905 query
->qTXT
.QuestionContext
= query
;
5907 query
->qAv4
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5908 query
->qAv4
.InterfaceID
= info
->InterfaceID
;
5909 query
->qAv4
.Target
= zeroAddr
;
5910 query
->qAv4
.qname
.c
[0] = 0;
5911 query
->qAv4
.qtype
= kDNSType_A
;
5912 query
->qAv4
.qclass
= kDNSClass_IN
;
5913 query
->qAv4
.LongLived
= mDNSfalse
;
5914 query
->qAv4
.ExpectUnique
= mDNStrue
;
5915 query
->qAv4
.ForceMCast
= mDNSfalse
;
5916 query
->qAv4
.ReturnIntermed
= mDNSfalse
;
5917 query
->qAv4
.QuestionCallback
= FoundServiceInfo
;
5918 query
->qAv4
.QuestionContext
= query
;
5920 query
->qAv6
.ThisQInterval
= -1; // So that mDNS_StopResolveService() knows whether to cancel this question
5921 query
->qAv6
.InterfaceID
= info
->InterfaceID
;
5922 query
->qAv6
.Target
= zeroAddr
;
5923 query
->qAv6
.qname
.c
[0] = 0;
5924 query
->qAv6
.qtype
= kDNSType_AAAA
;
5925 query
->qAv6
.qclass
= kDNSClass_IN
;
5926 query
->qAv6
.LongLived
= mDNSfalse
;
5927 query
->qAv6
.ExpectUnique
= mDNStrue
;
5928 query
->qAv6
.ForceMCast
= mDNSfalse
;
5929 query
->qAv6
.ReturnIntermed
= mDNSfalse
;
5930 query
->qAv6
.QuestionCallback
= FoundServiceInfo
;
5931 query
->qAv6
.QuestionContext
= query
;
5933 query
->GotSRV
= mDNSfalse
;
5934 query
->GotTXT
= mDNSfalse
;
5935 query
->GotADD
= mDNSfalse
;
5939 query
->ServiceInfoQueryCallback
= Callback
;
5940 query
->ServiceInfoQueryContext
= Context
;
5942 // info->name = Must already be set up by client
5943 // info->interface = Must already be set up by client
5944 info
->ip
= zeroAddr
;
5945 info
->port
= zeroIPPort
;
5948 // We use mDNS_StartQuery_internal here because we're already holding the lock
5949 status
= mDNS_StartQuery_internal(m
, &query
->qSRV
);
5950 if (status
== mStatus_NoError
) status
= mDNS_StartQuery_internal(m
, &query
->qTXT
);
5951 if (status
!= mStatus_NoError
) mDNS_StopResolveService(m
, query
);
5957 mDNSexport
void mDNS_StopResolveService (mDNS
*const m
, ServiceInfoQuery
*q
)
5960 // We use mDNS_StopQuery_internal here because we're already holding the lock
5961 if (q
->qSRV
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qSRV
);
5962 if (q
->qTXT
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qTXT
);
5963 if (q
->qAv4
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv4
);
5964 if (q
->qAv6
.ThisQInterval
>= 0) mDNS_StopQuery_internal(m
, &q
->qAv6
);
5968 mDNSexport mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
5969 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
5971 question
->InterfaceID
= InterfaceID
;
5972 question
->Target
= zeroAddr
;
5973 question
->qtype
= kDNSType_PTR
;
5974 question
->qclass
= kDNSClass_IN
;
5975 question
->LongLived
= mDNSfalse
;
5976 question
->ExpectUnique
= mDNSfalse
;
5977 question
->ForceMCast
= mDNSfalse
;
5978 question
->ReturnIntermed
= mDNSfalse
;
5979 question
->QuestionCallback
= Callback
;
5980 question
->QuestionContext
= Context
;
5981 if (DomainType
> mDNS_DomainTypeMax
) return(mStatus_BadParamErr
);
5982 if (!MakeDomainNameFromDNSNameString(&question
->qname
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
5983 if (!dom
) dom
= &localdomain
;
5984 if (!AppendDomainName(&question
->qname
, dom
)) return(mStatus_BadParamErr
);
5985 return(mDNS_StartQuery(m
, question
));
5988 // ***************************************************************************
5989 #if COMPILER_LIKES_PRAGMA_MARK
5991 #pragma mark - Responder Functions
5994 mDNSexport mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
)
5998 status
= mDNS_Register_internal(m
, rr
);
6003 mDNSexport mStatus
mDNS_Update(mDNS
*const m
, AuthRecord
*const rr
, mDNSu32 newttl
,
6004 const mDNSu16 newrdlength
, RData
*const newrdata
, mDNSRecordUpdateCallback
*Callback
)
6006 #ifndef UNICAST_DISABLED
6007 mDNSBool unicast
= !(rr
->resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(rr
->resrec
.name
));
6009 mDNSBool unicast
= mDNSfalse
;
6012 if (!ValidateRData(rr
->resrec
.rrtype
, newrdlength
, newrdata
))
6014 LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr
->resrec
, &newrdata
->u
, m
->MsgBuffer
));
6015 return(mStatus_Invalid
);
6020 // If TTL is unspecified, leave TTL unchanged
6021 if (newttl
== 0) newttl
= rr
->resrec
.rroriginalttl
;
6023 // If we already have an update queued up which has not gone through yet,
6024 // give the client a chance to free that memory
6025 if (!unicast
&& rr
->NewRData
)
6027 RData
*n
= rr
->NewRData
;
6028 rr
->NewRData
= mDNSNULL
; // Clear the NewRData pointer ...
6029 if (rr
->UpdateCallback
)
6030 rr
->UpdateCallback(m
, rr
, n
); // ...and let the client free this memory, if necessary
6033 rr
->NewRData
= newrdata
;
6034 rr
->newrdlength
= newrdlength
;
6035 rr
->UpdateCallback
= Callback
;
6037 if (unicast
) { mStatus status
= uDNS_UpdateRecord(m
, rr
); mDNS_Unlock(m
); return(status
); }
6039 if (rr
->resrec
.rroriginalttl
== newttl
&&
6040 rr
->resrec
.rdlength
== newrdlength
&& mDNSPlatformMemSame(rr
->resrec
.rdata
->u
.data
, newrdata
->u
.data
, newrdlength
))
6041 CompleteRDataUpdate(m
, rr
);
6045 domainname type
, domain
;
6046 DeconstructServiceName(rr
->resrec
.name
, &name
, &type
, &domain
);
6047 rr
->AnnounceCount
= InitialAnnounceCount
;
6048 // iChat often does suprious record updates where no data has changed. For the _presence service type, using
6049 // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
6050 // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
6051 // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
6052 // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
6053 if (SameDomainLabel(type
.c
, (mDNSu8
*)"\x6_ichat")) rr
->AnnounceCount
= 1;
6054 InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
));
6055 while (rr
->NextUpdateCredit
&& m
->timenow
- rr
->NextUpdateCredit
>= 0) GrantUpdateCredit(rr
);
6056 if (!rr
->UpdateBlocked
&& rr
->UpdateCredits
) rr
->UpdateCredits
--;
6057 if (!rr
->NextUpdateCredit
) rr
->NextUpdateCredit
= NonZeroTime(m
->timenow
+ kUpdateCreditRefreshInterval
);
6058 if (rr
->AnnounceCount
> rr
->UpdateCredits
+ 1) rr
->AnnounceCount
= (mDNSu8
)(rr
->UpdateCredits
+ 1);
6059 if (rr
->UpdateCredits
<= 5)
6061 mDNSu32 delay
= 6 - rr
->UpdateCredits
; // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
6062 if (!rr
->UpdateBlocked
) rr
->UpdateBlocked
= NonZeroTime(m
->timenow
+ (mDNSs32
)delay
* mDNSPlatformOneSecond
);
6063 rr
->ThisAPInterval
*= 4;
6064 rr
->LastAPTime
= rr
->UpdateBlocked
- rr
->ThisAPInterval
;
6065 LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
6066 rr
->resrec
.name
->c
, delay
, delay
> 1 ? "s" : "");
6068 rr
->resrec
.rroriginalttl
= newttl
;
6072 return(mStatus_NoError
);
6075 // NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change
6076 // the record list and/or question list.
6077 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6078 mDNSexport mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
)
6082 status
= mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
6087 // Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
6088 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
);
6090 mDNSlocal NetworkInterfaceInfo
*FindFirstAdvertisedInterface(mDNS
*const m
)
6092 NetworkInterfaceInfo
*intf
;
6093 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6094 if (intf
->Advertise
) break;
6098 mDNSlocal
void AdvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
6100 char buffer
[MAX_REVERSE_MAPPING_NAME
];
6101 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
6102 if (!primary
) primary
= set
; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
6104 // Send dynamic update for non-linklocal IPv4 Addresses
6105 mDNS_SetupResourceRecord(&set
->RR_A
, mDNSNULL
, set
->InterfaceID
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNS_HostNameCallback
, set
);
6106 mDNS_SetupResourceRecord(&set
->RR_PTR
, mDNSNULL
, set
->InterfaceID
, kDNSType_PTR
, kHostNameTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
6107 mDNS_SetupResourceRecord(&set
->RR_HINFO
, mDNSNULL
, set
->InterfaceID
, kDNSType_HINFO
, kHostNameTTL
, kDNSRecordTypeUnique
, mDNSNULL
, mDNSNULL
);
6109 #if ANSWER_REMOTE_HOSTNAME_QUERIES
6110 set
->RR_A
.AllowRemoteQuery
= mDNStrue
;
6111 set
->RR_PTR
.AllowRemoteQuery
= mDNStrue
;
6112 set
->RR_HINFO
.AllowRemoteQuery
= mDNStrue
;
6114 // 1. Set up Address record to map from host name ("foo.local.") to IP address
6115 // 2. Set up reverse-lookup PTR record to map from our address back to our host name
6116 AssignDomainName(&set
->RR_A
.namestorage
, &m
->MulticastHostname
);
6117 if (set
->ip
.type
== mDNSAddrType_IPv4
)
6119 set
->RR_A
.resrec
.rrtype
= kDNSType_A
;
6120 set
->RR_A
.resrec
.rdata
->u
.ipv4
= set
->ip
.ip
.v4
;
6121 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
6122 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.",
6123 set
->ip
.ip
.v4
.b
[3], set
->ip
.ip
.v4
.b
[2], set
->ip
.ip
.v4
.b
[1], set
->ip
.ip
.v4
.b
[0]);
6125 else if (set
->ip
.type
== mDNSAddrType_IPv6
)
6128 set
->RR_A
.resrec
.rrtype
= kDNSType_AAAA
;
6129 set
->RR_A
.resrec
.rdata
->u
.ipv6
= set
->ip
.ip
.v6
;
6130 for (i
= 0; i
< 16; i
++)
6132 static const char hexValues
[] = "0123456789ABCDEF";
6133 buffer
[i
* 4 ] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] & 0x0F];
6134 buffer
[i
* 4 + 1] = '.';
6135 buffer
[i
* 4 + 2] = hexValues
[set
->ip
.ip
.v6
.b
[15 - i
] >> 4];
6136 buffer
[i
* 4 + 3] = '.';
6138 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
6141 MakeDomainNameFromDNSNameString(&set
->RR_PTR
.namestorage
, buffer
);
6142 set
->RR_PTR
.AutoTarget
= Target_AutoHost
; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
6143 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
6145 set
->RR_A
.RRSet
= &primary
->RR_A
; // May refer to self
6147 mDNS_Register_internal(m
, &set
->RR_A
);
6148 mDNS_Register_internal(m
, &set
->RR_PTR
);
6150 if (!NO_HINFO
&& m
->HIHardware
.c
[0] > 0 && m
->HISoftware
.c
[0] > 0 && m
->HIHardware
.c
[0] + m
->HISoftware
.c
[0] <= 254)
6152 mDNSu8
*p
= set
->RR_HINFO
.resrec
.rdata
->u
.data
;
6153 AssignDomainName(&set
->RR_HINFO
.namestorage
, &m
->MulticastHostname
);
6154 set
->RR_HINFO
.DependentOn
= &set
->RR_A
;
6155 mDNSPlatformMemCopy(p
, &m
->HIHardware
, 1 + (mDNSu32
)m
->HIHardware
.c
[0]);
6157 mDNSPlatformMemCopy(p
, &m
->HISoftware
, 1 + (mDNSu32
)m
->HISoftware
.c
[0]);
6158 mDNS_Register_internal(m
, &set
->RR_HINFO
);
6162 debugf("Not creating HINFO record: platform support layer provided no information");
6163 set
->RR_HINFO
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
6167 mDNSlocal
void DeadvertiseInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
)
6169 NetworkInterfaceInfo
*intf
;
6171 // If we still have address records referring to this one, update them
6172 NetworkInterfaceInfo
*primary
= FindFirstAdvertisedInterface(m
);
6173 AuthRecord
*A
= primary
? &primary
->RR_A
: mDNSNULL
;
6174 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6175 if (intf
->RR_A
.RRSet
== &set
->RR_A
)
6176 intf
->RR_A
.RRSet
= A
;
6178 // Unregister these records.
6179 // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
6180 // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
6181 // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
6182 // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
6183 if (set
->RR_A
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_A
, mDNS_Dereg_normal
);
6184 if (set
->RR_PTR
. resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_PTR
, mDNS_Dereg_normal
);
6185 if (set
->RR_HINFO
.resrec
.RecordType
) mDNS_Deregister_internal(m
, &set
->RR_HINFO
, mDNS_Dereg_normal
);
6188 mDNSexport
void mDNS_SetFQDN(mDNS
*const m
)
6190 domainname newmname
;
6191 NetworkInterfaceInfo
*intf
;
6195 if (!AppendDomainLabel(&newmname
, &m
->hostlabel
)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6196 if (!AppendLiteralLabelString(&newmname
, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
6197 if (SameDomainNameCS(&m
->MulticastHostname
, &newmname
)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
6201 AssignDomainName(&m
->MulticastHostname
, &newmname
);
6202 // 1. Stop advertising our address records on all interfaces
6203 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6204 if (intf
->Advertise
) DeadvertiseInterface(m
, intf
);
6206 // 2. Start advertising our address records using the new name
6207 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6208 if (intf
->Advertise
) AdvertiseInterface(m
, intf
);
6210 // 3. Make sure that any SRV records (and the like) that reference our
6211 // host name in their rdata get updated to reference this new host name
6212 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
6213 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
) if (rr
->AutoTarget
) SetTargetToHostName(m
, rr
);
6218 mDNSlocal
void mDNS_HostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
6220 (void)rr
; // Unused parameter
6224 char *msg
= "Unknown result";
6225 if (result
== mStatus_NoError
) msg
= "Name registered";
6226 else if (result
== mStatus_NameConflict
) msg
= "Name conflict";
6227 debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
6231 if (result
== mStatus_NoError
)
6233 // Notify the client that the host name is successfully registered
6234 if (m
->MainCallback
)
6235 m
->MainCallback(m
, mStatus_NoError
);
6237 else if (result
== mStatus_NameConflict
)
6239 domainlabel oldlabel
= m
->hostlabel
;
6241 // 1. First give the client callback a chance to pick a new name
6242 if (m
->MainCallback
)
6243 m
->MainCallback(m
, mStatus_NameConflict
);
6245 // 2. If the client callback didn't do it, add (or increment) an index ourselves
6246 // This needs to be case-insensitive compare, because we need to know that the name has been changed so as to
6247 // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
6248 if (SameDomainLabelCS(m
->hostlabel
.c
, oldlabel
.c
))
6249 IncrementLabelSuffix(&m
->hostlabel
, mDNSfalse
);
6251 // 3. Generate the FQDNs from the hostlabel,
6252 // and make sure all SRV records, etc., are updated to reference our new hostname
6254 LogMsg("Local Hostname %#s.local already in use; will try %#s.local instead", oldlabel
.c
, m
->hostlabel
.c
);
6256 else if (result
== mStatus_MemFree
)
6258 // .local hostnames do not require goodbyes - we ignore the MemFree (which is sent directly by
6259 // mDNS_Deregister_internal), and allow the caller to deallocate immediately following mDNS_DeadvertiseInterface
6260 debugf("mDNS_HostNameCallback: MemFree (ignored)");
6263 LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result
, rr
->resrec
.name
->c
);
6266 mDNSlocal
void UpdateInterfaceProtocols(mDNS
*const m
, NetworkInterfaceInfo
*active
)
6268 NetworkInterfaceInfo
*intf
;
6269 active
->IPv4Available
= mDNSfalse
;
6270 active
->IPv6Available
= mDNSfalse
;
6271 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6272 if (intf
->InterfaceID
== active
->InterfaceID
)
6274 if (intf
->ip
.type
== mDNSAddrType_IPv4
&& intf
->McastTxRx
) active
->IPv4Available
= mDNStrue
;
6275 if (intf
->ip
.type
== mDNSAddrType_IPv6
&& intf
->McastTxRx
) active
->IPv6Available
= mDNStrue
;
6279 mDNSexport mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
6282 ServiceRecordSet
*s
;
6283 mDNSBool FirstOfType
= mDNStrue
;
6284 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
6286 if (!set
->InterfaceID
)
6287 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set
->ip
); return(mStatus_Invalid
); }
6289 if (!mDNSAddressIsValidNonZero(&set
->mask
))
6290 { LogMsg("Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set
->ip
, &set
->mask
); return(mStatus_Invalid
); }
6294 // Assume this interface will be active now, unless we find a duplicate already in the list
6295 set
->InterfaceActive
= mDNStrue
;
6296 set
->IPv4Available
= (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
);
6297 set
->IPv6Available
= (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
);
6299 // Scan list to see if this InterfaceID is already represented
6304 LogMsg("Error! Tried to register a NetworkInterfaceInfo that's already in the list");
6306 return(mStatus_AlreadyRegistered
);
6309 if ((*p
)->InterfaceID
== set
->InterfaceID
)
6311 // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
6312 set
->InterfaceActive
= mDNSfalse
;
6313 if (set
->ip
.type
== (*p
)->ip
.type
) FirstOfType
= mDNSfalse
;
6314 if (set
->ip
.type
== mDNSAddrType_IPv4
&& set
->McastTxRx
) (*p
)->IPv4Available
= mDNStrue
;
6315 if (set
->ip
.type
== mDNSAddrType_IPv6
&& set
->McastTxRx
) (*p
)->IPv6Available
= mDNStrue
;
6321 set
->next
= mDNSNULL
;
6325 AdvertiseInterface(m
, set
);
6327 LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set
->InterfaceID
, set
->ifname
, &set
->ip
,
6328 set
->InterfaceActive
?
6329 "not represented in list; marking active and retriggering queries" :
6330 "already represented in list; marking inactive for now");
6332 // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6333 // giving the false impression that there's an active representative of this interface when there really isn't.
6334 // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
6335 // even if we believe that we previously had an active representative of this interface.
6336 if (set
->McastTxRx
&& ((m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) || FirstOfType
|| set
->InterfaceActive
))
6339 // If flapping, delay between first and second queries is eight seconds instead of one
6340 mDNSs32 delay
= flapping
? mDNSPlatformOneSecond
* 5 : 0;
6341 mDNSu8 announce
= flapping
? (mDNSu8
)1 : InitialAnnounceCount
;
6343 // Use a small amount of randomness:
6344 // In the case of a network administrator turning on an Ethernet hub so that all the
6345 // connected machines establish link at exactly the same time, we don't want them all
6346 // to go and hit the network with identical queries at exactly the same moment.
6347 if (!m
->SuppressSending
) m
->SuppressSending
= m
->timenow
+ (mDNSs32
)mDNSRandom((mDNSu32
)InitialQuestionInterval
);
6351 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set
->ifname
, &set
->ip
);
6352 if (!m
->SuppressProbes
||
6353 m
->SuppressProbes
- (m
->timenow
+ delay
) < 0)
6354 m
->SuppressProbes
= (m
->timenow
+ delay
);
6357 for (q
= m
->Questions
; q
; q
=q
->next
) // Scan our list of questions
6358 if (mDNSOpaque16IsZero(q
->TargetQID
))
6359 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
) // If non-specific Q, or Q on this specific interface,
6360 { // then reactivate this question
6361 mDNSBool dodelay
= flapping
&& (q
->FlappingInterface1
== set
->InterfaceID
|| q
->FlappingInterface2
== set
->InterfaceID
);
6362 mDNSs32 initial
= dodelay
? InitialQuestionInterval
* QuestionIntervalStep2
: InitialQuestionInterval
;
6363 mDNSs32 qdelay
= dodelay
? mDNSPlatformOneSecond
* 5 : 0;
6364 if (dodelay
) LogOperation("No cache records expired for %##s (%s); okay to delay questions a little", q
->qname
.c
, DNSTypeName(q
->qtype
));
6366 if (!q
->ThisQInterval
|| q
->ThisQInterval
> initial
)
6368 q
->ThisQInterval
= initial
;
6369 q
->RequestUnicast
= 2; // Set to 2 because is decremented once *before* we check it
6371 q
->LastQTime
= m
->timenow
- q
->ThisQInterval
+ qdelay
;
6372 q
->RecentAnswerPkts
= 0;
6373 SetNextQueryTime(m
,q
);
6376 // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
6377 // we now need them to re-probe if necessary, and then re-announce.
6378 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6379 if (!AuthRecord_uDNS(rr
))
6380 if (!rr
->resrec
.InterfaceID
|| rr
->resrec
.InterfaceID
== set
->InterfaceID
)
6382 if (rr
->resrec
.RecordType
== kDNSRecordTypeVerified
&& !rr
->DependentOn
) rr
->resrec
.RecordType
= kDNSRecordTypeUnique
;
6383 rr
->ProbeCount
= DefaultProbeCountForRecordType(rr
->resrec
.RecordType
);
6384 if (rr
->AnnounceCount
< announce
) rr
->AnnounceCount
= announce
;
6385 InitializeLastAPTime(m
, rr
, DefaultAPIntervalForRecordType(rr
->resrec
.RecordType
));
6389 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
6390 if (AuthRecord_uDNS(rr
))
6392 LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", rr
->resrec
.name
->c
);
6393 if (rr
->nta
) CancelGetZoneData(m
, rr
->nta
);
6394 rr
->nta
= StartGetZoneData(m
, rr
->resrec
.name
, ZoneServiceUpdate
, RecordRegistrationGotZoneData
, rr
);
6397 for (s
= m
->ServiceRegistrations
; s
; s
= s
->uDNS_next
)
6399 LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", s
->RR_SRV
.resrec
.name
->c
);
6400 if (s
->nta
) CancelGetZoneData(m
, s
->nta
);
6401 s
->nta
= StartGetZoneData(m
, s
->RR_SRV
.resrec
.name
, ZoneServiceUpdate
, ServiceRegistrationGotZoneData
, s
);
6405 return(mStatus_NoError
);
6408 // NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
6409 // the record list and/or question list.
6410 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6411 mDNSexport
void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
6413 NetworkInterfaceInfo
**p
= &m
->HostInterfaces
;
6415 mDNSBool revalidate
= mDNSfalse
;
6416 // If this platform has the "phantom interfaces" known bug (e.g. Jaguar), we have to revalidate records every
6417 // time an interface goes away. Otherwise, when you disconnect the Ethernet cable, the system reports that it
6418 // still has an IPv6 address, and if we don't revalidate those records don't get deleted in a timely fashion.
6419 if (m
->KnownBugs
& mDNS_KnownBug_PhantomInterfaces
) revalidate
= mDNStrue
;
6423 // Find this record in our list
6424 while (*p
&& *p
!= set
) p
=&(*p
)->next
;
6425 if (!*p
) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m
); return; }
6427 // Unlink this record from our list
6429 set
->next
= mDNSNULL
;
6431 if (!set
->InterfaceActive
)
6433 // If this interface not the active member of its set, update the v4/v6Available flags for the active member
6434 NetworkInterfaceInfo
*intf
;
6435 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6436 if (intf
->InterfaceActive
&& intf
->InterfaceID
== set
->InterfaceID
)
6437 UpdateInterfaceProtocols(m
, intf
);
6441 NetworkInterfaceInfo
*intf
;
6442 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6443 if (intf
->InterfaceID
== set
->InterfaceID
)
6447 LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
6448 " making it active", set
->InterfaceID
, set
->ifname
, &set
->ip
);
6449 intf
->InterfaceActive
= mDNStrue
;
6450 UpdateInterfaceProtocols(m
, intf
);
6452 // See if another representative *of the same type* exists. If not, we mave have gone from
6453 // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid.
6454 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
6455 if (intf
->InterfaceID
== set
->InterfaceID
&& intf
->ip
.type
== set
->ip
.type
)
6457 if (!intf
) revalidate
= mDNStrue
;
6467 LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
6468 " marking questions etc. dormant", set
->InterfaceID
, set
->ifname
, &set
->ip
);
6471 LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
6472 set
->ifname
, &set
->ip
);
6474 // 1. Deactivate any questions specific to this interface, and tag appropriate questions
6475 // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
6476 for (q
= m
->Questions
; q
; q
=q
->next
)
6478 if (q
->InterfaceID
== set
->InterfaceID
) q
->ThisQInterval
= 0;
6479 if (!q
->InterfaceID
|| q
->InterfaceID
== set
->InterfaceID
)
6481 q
->FlappingInterface2
= q
->FlappingInterface1
;
6482 q
->FlappingInterface1
= set
->InterfaceID
; // Keep history of the last two interfaces to go away
6486 // 2. Flush any cache records received on this interface
6487 revalidate
= mDNSfalse
; // Don't revalidate if we're flushing the records
6488 FORALL_CACHERECORDS(slot
, cg
, rr
)
6489 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
6491 // If this interface is deemed flapping,
6492 // postpone deleting the cache records in case the interface comes back again
6493 if (!flapping
) mDNS_PurgeCacheResourceRecord(m
, rr
);
6496 // We want these record to go away in 30 seconds
6497 // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
6498 // if the interface does come back, any relevant questions will be reactivated anyway
6499 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
6500 rr
->UnansweredQueries
= MaxUnansweredQueries
;
6504 // 3. Any DNS servers specific to this interface are now unusable
6505 for (s
= m
->DNSServers
; s
; s
= s
->next
)
6506 if (s
->interface
== set
->InterfaceID
)
6508 s
->interface
= mDNSInterface_Any
;
6509 s
->teststate
= DNSServer_Disabled
;
6514 // If we were advertising on this interface, deregister those address and reverse-lookup records now
6515 if (set
->Advertise
) DeadvertiseInterface(m
, set
);
6517 // If we have any cache records received on this interface that went away, then re-verify them.
6518 // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
6519 // giving the false impression that there's an active representative of this interface when there really isn't.
6520 // Don't need to do this when shutting down, because *all* interfaces are about to go away
6521 if (revalidate
&& !m
->ShutdownTime
)
6526 m
->NextCacheCheck
= m
->timenow
;
6527 FORALL_CACHERECORDS(slot
, cg
, rr
)
6528 if (rr
->resrec
.InterfaceID
== set
->InterfaceID
)
6529 mDNS_Reconfirm_internal(m
, rr
, kDefaultReconfirmTimeForFlappingInterface
);
6535 mDNSlocal
void ServiceCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
6537 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
6538 (void)m
; // Unused parameter
6542 char *msg
= "Unknown result";
6543 if (result
== mStatus_NoError
) msg
= "Name Registered";
6544 else if (result
== mStatus_NameConflict
) msg
= "Name Conflict";
6545 else if (result
== mStatus_MemFree
) msg
= "Memory Free";
6546 debugf("ServiceCallback: %##s (%s) %s (%ld)", rr
->resrec
.name
->c
, DNSTypeName(rr
->resrec
.rrtype
), msg
, result
);
6550 // Only pass on the NoError acknowledgement for the SRV record (when it finishes probing)
6551 if (result
== mStatus_NoError
&& rr
!= &sr
->RR_SRV
) return;
6553 // If we got a name conflict on either SRV or TXT, forcibly deregister this service, and record that we did that
6554 if (result
== mStatus_NameConflict
)
6556 sr
->Conflict
= mDNStrue
; // Record that this service set had a conflict
6557 mDNS_DeregisterService(m
, sr
); // Unlink the records from our list
6561 if (result
== mStatus_MemFree
)
6563 // If the PTR record or any of the subtype PTR records are still in the process of deregistering,
6564 // don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
6566 if (sr
->RR_PTR
.resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
6567 for (i
=0; i
<sr
->NumSubTypes
; i
++) if (sr
->SubTypes
[i
].resrec
.RecordType
!= kDNSRecordTypeUnregistered
) return;
6569 // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
6570 // then we can now report the NameConflict to the client
6571 if (sr
->Conflict
) result
= mStatus_NameConflict
;
6574 // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
6575 // function is allowed to do anything, including deregistering this service and freeing its memory.
6576 if (sr
->ServiceCallback
)
6577 sr
->ServiceCallback(m
, sr
, result
);
6580 mDNSlocal
void NSSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
6582 ServiceRecordSet
*sr
= (ServiceRecordSet
*)rr
->RecordContext
;
6583 if (sr
->ServiceCallback
)
6584 sr
->ServiceCallback(m
, sr
, result
);
6587 mDNSlocal mStatus
uDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*srs
)
6590 ServiceRecordSet
**p
= &m
->ServiceRegistrations
;
6591 while (*p
&& *p
!= srs
) p
=&(*p
)->uDNS_next
;
6592 if (*p
) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs
, srs
->RR_SRV
.resrec
.name
->c
); return(mStatus_AlreadyRegistered
); }
6594 srs
->uDNS_next
= mDNSNULL
;
6597 srs
->RR_SRV
.resrec
.rroriginalttl
= kHostNameTTL
;
6598 srs
->RR_TXT
.resrec
.rroriginalttl
= kStandardTTL
;
6599 srs
->RR_PTR
.resrec
.rroriginalttl
= kStandardTTL
;
6600 for (i
= 0; i
< srs
->NumSubTypes
;i
++) srs
->SubTypes
[i
].resrec
.rroriginalttl
= kStandardTTL
;
6602 srs
->srs_uselease
= mDNStrue
;
6604 if (srs
->RR_SRV
.AutoTarget
)
6606 // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
6607 // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
6608 // with the port number in our advertised SRV record automatically tracking the external mapped port.
6609 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, srs
->RR_SRV
.resrec
.name
);
6610 if (!AuthInfo
|| !AuthInfo
->AutoTunnel
) srs
->RR_SRV
.AutoTarget
= Target_AutoHostAndNATMAP
;
6613 if (!GetServiceTarget(m
, srs
))
6615 // defer registration until we've got a target
6616 LogOperation("uDNS_RegisterService - no target for %##s", srs
->RR_SRV
.resrec
.name
->c
);
6617 srs
->state
= regState_NoTarget
;
6618 srs
->nta
= mDNSNULL
;
6619 return mStatus_NoError
;
6622 ActivateUnicastRegistration(m
, &srs
->RR_SRV
);
6623 srs
->state
= regState_FetchingZoneData
;
6624 srs
->nta
= mDNSNULL
;
6625 return mStatus_NoError
;
6629 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
6630 // Type is service type (e.g. "_ipp._tcp.")
6631 // Domain is fully qualified domain name (i.e. ending with a null label)
6632 // We always register a TXT, even if it is empty (so that clients are not
6633 // left waiting forever looking for a nonexistent record.)
6634 // If the host parameter is mDNSNULL or the root domain (ASCII NUL),
6635 // then the default host name (m->MulticastHostname) is automatically used
6636 // If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
6637 mDNSexport mStatus
mDNS_RegisterService(mDNS
*const m
, ServiceRecordSet
*sr
,
6638 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
6639 const domainname
*const host
, mDNSIPPort port
, const mDNSu8 txtinfo
[], mDNSu16 txtlen
,
6640 AuthRecord
*SubTypes
, mDNSu32 NumSubTypes
,
6641 const mDNSInterfaceID InterfaceID
, mDNSServiceCallback Callback
, void *Context
)
6646 sr
->state
= regState_Zero
;
6647 sr
->srs_uselease
= 0;
6648 sr
->TestForSelfConflict
= 0;
6652 sr
->SRSUpdateServer
= zeroAddr
;
6653 sr
->SRSUpdatePort
= zeroIPPort
;
6654 mDNSPlatformMemZero(&sr
->NATinfo
, sizeof(sr
->NATinfo
));
6655 sr
->ClientCallbackDeferred
= 0;
6656 sr
->DeferredStatus
= 0;
6657 sr
->SRVUpdateDeferred
= 0;
6661 sr
->ServiceCallback
= Callback
;
6662 sr
->ServiceContext
= Context
;
6663 sr
->Conflict
= mDNSfalse
;
6665 sr
->Extras
= mDNSNULL
;
6666 sr
->NumSubTypes
= NumSubTypes
;
6667 sr
->SubTypes
= SubTypes
;
6669 // Initialize the AuthRecord objects to sane values
6670 // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
6671 mDNS_SetupResourceRecord(&sr
->RR_ADV
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeAdvisory
, ServiceCallback
, sr
);
6672 mDNS_SetupResourceRecord(&sr
->RR_PTR
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
6673 mDNS_SetupResourceRecord(&sr
->RR_SRV
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
6674 mDNS_SetupResourceRecord(&sr
->RR_TXT
, mDNSNULL
, InterfaceID
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
6676 // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
6677 if (mDNSIPPortIsZero(port
))
6678 return(mDNS_RegisterNoSuchService(m
, &sr
->RR_SRV
, name
, type
, domain
, mDNSNULL
, mDNSInterface_Any
, NSSCallback
, sr
));
6680 // If the client is registering an oversized TXT record,
6681 // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
6682 if (sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
< txtlen
)
6683 sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
= txtlen
;
6685 // Set up the record names
6686 // For now we only create an advisory record for the main type, not for subtypes
6687 // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
6688 if (ConstructServiceName(&sr
->RR_ADV
.namestorage
, (const domainlabel
*)"\x09_services", (const domainname
*)"\x07_dns-sd\x04_udp", domain
) == mDNSNULL
)
6689 return(mStatus_BadParamErr
);
6690 if (ConstructServiceName(&sr
->RR_PTR
.namestorage
, mDNSNULL
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
6691 if (ConstructServiceName(&sr
->RR_SRV
.namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
6692 AssignDomainName(&sr
->RR_TXT
.namestorage
, sr
->RR_SRV
.resrec
.name
);
6694 // 1. Set up the ADV record rdata to advertise our service type
6695 AssignDomainName(&sr
->RR_ADV
.resrec
.rdata
->u
.name
, sr
->RR_PTR
.resrec
.name
);
6697 // 2. Set up the PTR record rdata to point to our service name
6698 // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
6699 AssignDomainName(&sr
->RR_PTR
.resrec
.rdata
->u
.name
, sr
->RR_SRV
.resrec
.name
);
6700 sr
->RR_PTR
.Additional1
= &sr
->RR_SRV
;
6701 sr
->RR_PTR
.Additional2
= &sr
->RR_TXT
;
6703 // 2a. Set up any subtype PTRs to point to our service name
6704 // If the client is using subtypes, it is the client's responsibility to have
6705 // already set the first label of the record name to the subtype being registered
6706 for (i
=0; i
<NumSubTypes
; i
++)
6709 AssignDomainName(&st
, sr
->SubTypes
[i
].resrec
.name
);
6710 st
.c
[1+st
.c
[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
6711 AppendDomainName(&st
, type
);
6712 mDNS_SetupResourceRecord(&sr
->SubTypes
[i
], mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, ServiceCallback
, sr
);
6713 if (ConstructServiceName(&sr
->SubTypes
[i
].namestorage
, mDNSNULL
, &st
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
6714 AssignDomainName(&sr
->SubTypes
[i
].resrec
.rdata
->u
.name
, &sr
->RR_SRV
.namestorage
);
6715 sr
->SubTypes
[i
].Additional1
= &sr
->RR_SRV
;
6716 sr
->SubTypes
[i
].Additional2
= &sr
->RR_TXT
;
6719 // 3. Set up the SRV record rdata.
6720 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.priority
= 0;
6721 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.weight
= 0;
6722 sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
= port
;
6724 // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
6725 if (host
&& host
->c
[0]) AssignDomainName(&sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
, host
);
6726 else { sr
->RR_SRV
.AutoTarget
= Target_AutoHost
; sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0'; }
6728 // 4. Set up the TXT record rdata,
6729 // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
6730 if (txtinfo
== mDNSNULL
) sr
->RR_TXT
.resrec
.rdlength
= 0;
6731 else if (txtinfo
!= sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
)
6733 sr
->RR_TXT
.resrec
.rdlength
= txtlen
;
6734 if (sr
->RR_TXT
.resrec
.rdlength
> sr
->RR_TXT
.resrec
.rdata
->MaxRDLength
) return(mStatus_BadParamErr
);
6735 mDNSPlatformMemCopy(sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, txtinfo
, txtlen
);
6737 sr
->RR_TXT
.DependentOn
= &sr
->RR_SRV
;
6739 #ifndef UNICAST_DISABLED
6740 // If the client has specified an explicit InterfaceID,
6741 // then we do a multicast registration on that interface, even for unicast domains.
6742 if (!(InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(&sr
->RR_SRV
.namestorage
)))
6746 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
6747 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
6748 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
6749 // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
6750 if (!sr
->RR_TXT
.resrec
.rdlength
) { sr
->RR_TXT
.resrec
.rdlength
= 1; sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
[0] = 0; }
6752 status
= uDNS_RegisterService(m
, sr
);
6758 err
= mDNS_Register_internal(m
, &sr
->RR_SRV
);
6759 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_TXT
);
6760 // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
6761 // mDNS_StartExit, the RR_PTR will be the last one to be forcibly deregistered, since that is what triggers
6762 // the mStatus_MemFree callback to ServiceCallback, which in turn passes on the mStatus_MemFree back to
6763 // the client callback, which is then at liberty to free the ServiceRecordSet memory at will. We need to
6764 // make sure we've deregistered all our records and done any other necessary cleanup before that happens.
6765 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_ADV
);
6766 for (i
=0; i
<NumSubTypes
; i
++) if (!err
) err
= mDNS_Register_internal(m
, &sr
->SubTypes
[i
]);
6767 if (!err
) err
= mDNS_Register_internal(m
, &sr
->RR_PTR
);
6771 if (err
) mDNS_DeregisterService(m
, sr
);
6775 mDNSlocal
void DummyCallback(mDNS
*const m
, AuthRecord
*rr
, mStatus result
)
6779 (void)result
; // Unused
6780 LogOperation("DummyCallback %d %s", result
, ARDisplayString(m
, rr
));
6783 mDNSexport mStatus
mDNS_AddRecordToService(mDNS
*const m
, ServiceRecordSet
*sr
,
6784 ExtraResourceRecord
*extra
, RData
*rdata
, mDNSu32 ttl
)
6786 ExtraResourceRecord
**e
;
6789 extra
->next
= mDNSNULL
;
6790 mDNS_SetupResourceRecord(&extra
->r
, rdata
, sr
->RR_PTR
.resrec
.InterfaceID
,
6791 extra
->r
.resrec
.rrtype
, ttl
, kDNSRecordTypeUnique
, ServiceCallback
, sr
);
6792 AssignDomainName(&extra
->r
.namestorage
, sr
->RR_SRV
.resrec
.name
);
6796 while (*e
) e
= &(*e
)->next
;
6798 if (ttl
== 0) ttl
= kStandardTTL
;
6800 extra
->r
.DependentOn
= &sr
->RR_SRV
;
6802 debugf("mDNS_AddRecordToService adding record to %##s %s %d",
6803 extra
->r
.resrec
.name
->c
, DNSTypeName(extra
->r
.resrec
.rrtype
), extra
->r
.resrec
.rdlength
);
6805 status
= mDNS_Register_internal(m
, &extra
->r
);
6806 if (status
== mStatus_NoError
)
6809 #ifndef UNICAST_DISABLED
6810 if (AuthRecord_uDNS(&sr
->RR_SRV
))
6812 extra
->r
.resrec
.RecordType
= kDNSRecordTypeShared
; // don't want it to conflict with the service name (???)
6813 extra
->r
.RecordCallback
= DummyCallback
; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
6814 if (sr
->state
!= regState_Registered
&& sr
->state
!= regState_Refresh
) extra
->r
.state
= regState_ExtraQueued
;
6823 mDNSexport mStatus
mDNS_RemoveRecordFromService(mDNS
*const m
, ServiceRecordSet
*sr
, ExtraResourceRecord
*extra
,
6824 mDNSRecordCallback MemFreeCallback
, void *Context
)
6826 ExtraResourceRecord
**e
;
6831 while (*e
&& *e
!= extra
) e
= &(*e
)->next
;
6834 debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra
->r
.resrec
.name
->c
);
6835 status
= mStatus_BadReferenceErr
;
6839 debugf("mDNS_RemoveRecordFromService removing record from %##s", extra
->r
.resrec
.name
->c
);
6840 extra
->r
.RecordCallback
= MemFreeCallback
;
6841 extra
->r
.RecordContext
= Context
;
6843 status
= mDNS_Deregister_internal(m
, &extra
->r
, mDNS_Dereg_normal
);
6849 mDNSexport mStatus
mDNS_RenameAndReregisterService(mDNS
*const m
, ServiceRecordSet
*const sr
, const domainlabel
*newname
)
6851 // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines
6852 // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
6853 domainlabel name1
, name2
;
6854 domainname type
, domain
;
6855 const domainname
*host
= sr
->RR_SRV
.AutoTarget
? mDNSNULL
: &sr
->RR_SRV
.resrec
.rdata
->u
.srv
.target
;
6856 ExtraResourceRecord
*extras
= sr
->Extras
;
6859 DeconstructServiceName(sr
->RR_SRV
.resrec
.name
, &name1
, &type
, &domain
);
6863 IncrementLabelSuffix(&name2
, mDNStrue
);
6867 if (SameDomainName(&domain
, &localdomain
))
6868 LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type
.c
, name1
.c
, newname
->c
);
6869 else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type
.c
, domain
.c
, name1
.c
, newname
->c
);
6871 err
= mDNS_RegisterService(m
, sr
, newname
, &type
, &domain
,
6872 host
, sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
, sr
->RR_TXT
.resrec
.rdata
->u
.txt
.c
, sr
->RR_TXT
.resrec
.rdlength
,
6873 sr
->SubTypes
, sr
->NumSubTypes
,
6874 sr
->RR_PTR
.resrec
.InterfaceID
, sr
->ServiceCallback
, sr
->ServiceContext
);
6876 // mDNS_RegisterService() just reset sr->Extras to NULL.
6877 // Fortunately we already grabbed ourselves a copy of this pointer (above), so we can now run
6878 // through the old list of extra records, and re-add them to our freshly created service registration
6879 while (!err
&& extras
)
6881 ExtraResourceRecord
*e
= extras
;
6882 extras
= extras
->next
;
6883 err
= mDNS_AddRecordToService(m
, sr
, e
, e
->r
.resrec
.rdata
, e
->r
.resrec
.rroriginalttl
);
6889 // NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback,
6890 // which may change the record list and/or question list.
6891 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
6892 mDNSexport mStatus
mDNS_DeregisterService(mDNS
*const m
, ServiceRecordSet
*sr
)
6894 // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
6895 if (mDNSIPPortIsZero(sr
->RR_SRV
.resrec
.rdata
->u
.srv
.port
)) return(mDNS_DeregisterNoSuchService(m
, &sr
->RR_SRV
));
6897 #ifndef UNICAST_DISABLED
6898 if (!(sr
->RR_SRV
.resrec
.InterfaceID
== mDNSInterface_LocalOnly
|| IsLocalDomain(sr
->RR_SRV
.resrec
.name
)))
6902 status
= uDNS_DeregisterService(m
, sr
);
6907 if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeUnregistered
)
6909 debugf("Service set for %##s already deregistered", sr
->RR_SRV
.resrec
.name
->c
);
6910 return(mStatus_BadReferenceErr
);
6912 else if (sr
->RR_PTR
.resrec
.RecordType
== kDNSRecordTypeDeregistering
)
6914 debugf("Service set for %##s already in the process of deregistering", sr
->RR_SRV
.resrec
.name
->c
);
6915 // Avoid race condition:
6916 // If a service gets a conflict, then we set the Conflict flag to tell us to generate
6917 // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
6918 // If the client happens to deregister the service in the middle of that process, then
6919 // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
6920 // instead of incorrectly promoting it to mStatus_NameConflict.
6921 // This race condition is exposed particularly when the conformance test generates
6922 // a whole batch of simultaneous conflicts across a range of services all advertised
6923 // using the same system default name, and if we don't take this precaution then
6924 // we end up incrementing m->nicelabel multiple times instead of just once.
6925 // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
6926 sr
->Conflict
= mDNSfalse
;
6927 return(mStatus_NoError
);
6933 ExtraResourceRecord
*e
;
6937 // We use mDNS_Dereg_repeat because, in the event of a collision, some or all of the
6938 // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
6939 mDNS_Deregister_internal(m
, &sr
->RR_SRV
, mDNS_Dereg_repeat
);
6940 mDNS_Deregister_internal(m
, &sr
->RR_TXT
, mDNS_Dereg_repeat
);
6942 mDNS_Deregister_internal(m
, &sr
->RR_ADV
, mDNS_Dereg_normal
);
6944 // We deregister all of the extra records, but we leave the sr->Extras list intact
6945 // in case the client wants to do a RenameAndReregister and reinstate the registration
6948 mDNS_Deregister_internal(m
, &e
->r
, mDNS_Dereg_repeat
);
6952 for (i
=0; i
<sr
->NumSubTypes
; i
++)
6953 mDNS_Deregister_internal(m
, &sr
->SubTypes
[i
], mDNS_Dereg_normal
);
6955 // Be sure to deregister the PTR last!
6956 // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
6957 // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
6958 // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
6959 // we've deregistered all our records and done any other necessary cleanup before that happens.
6960 status
= mDNS_Deregister_internal(m
, &sr
->RR_PTR
, mDNS_Dereg_normal
);
6966 // Create a registration that asserts that no such service exists with this name.
6967 // This can be useful where there is a given function is available through several protocols.
6968 // For example, a printer called "Stuart's Printer" may implement printing via the "pdl-datastream" and "IPP"
6969 // protocols, but not via "LPR". In this case it would be prudent for the printer to assert the non-existence of an
6970 // "LPR" service called "Stuart's Printer". Without this precaution, another printer than offers only "LPR" printing
6971 // could inadvertently advertise its service under the same name "Stuart's Printer", which might be confusing for users.
6972 mDNSexport mStatus
mDNS_RegisterNoSuchService(mDNS
*const m
, AuthRecord
*const rr
,
6973 const domainlabel
*const name
, const domainname
*const type
, const domainname
*const domain
,
6974 const domainname
*const host
,
6975 const mDNSInterfaceID InterfaceID
, mDNSRecordCallback Callback
, void *Context
)
6977 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnique
, Callback
, Context
);
6978 if (ConstructServiceName(&rr
->namestorage
, name
, type
, domain
) == mDNSNULL
) return(mStatus_BadParamErr
);
6979 rr
->resrec
.rdata
->u
.srv
.priority
= 0;
6980 rr
->resrec
.rdata
->u
.srv
.weight
= 0;
6981 rr
->resrec
.rdata
->u
.srv
.port
= zeroIPPort
;
6982 if (host
&& host
->c
[0]) AssignDomainName(&rr
->resrec
.rdata
->u
.srv
.target
, host
);
6983 else rr
->AutoTarget
= Target_AutoHost
;
6984 return(mDNS_Register(m
, rr
));
6987 mDNSexport mStatus
mDNS_AdvertiseDomains(mDNS
*const m
, AuthRecord
*rr
,
6988 mDNS_DomainType DomainType
, const mDNSInterfaceID InterfaceID
, char *domname
)
6990 mDNS_SetupResourceRecord(rr
, mDNSNULL
, InterfaceID
, kDNSType_PTR
, kStandardTTL
, kDNSRecordTypeShared
, mDNSNULL
, mDNSNULL
);
6991 if (!MakeDomainNameFromDNSNameString(&rr
->namestorage
, mDNS_DomainTypeNames
[DomainType
])) return(mStatus_BadParamErr
);
6992 if (!MakeDomainNameFromDNSNameString(&rr
->resrec
.rdata
->u
.name
, domname
)) return(mStatus_BadParamErr
);
6993 return(mDNS_Register(m
, rr
));
6996 mDNSexport mDNSOpaque16
mDNS_NewMessageID(mDNS
* const m
)
7000 for (i
=0; i
<10; i
++)
7004 id
= mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
7005 for (r
= m
->ResourceRecords
; r
; r
=r
->next
) if (mDNSSameOpaque16(id
, r
->id
)) continue;
7006 for (q
= m
->Questions
; q
; q
=q
->next
) if (mDNSSameOpaque16(id
, q
->TargetQID
)) continue;
7009 debugf("mDNS_NewMessageID: %5d", mDNSVal16(id
));
7013 // ***************************************************************************
7014 #if COMPILER_LIKES_PRAGMA_MARK
7016 #pragma mark - Startup and Shutdown
7019 mDNSlocal
void mDNS_GrowCache_internal(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
7021 if (storage
&& numrecords
)
7024 debugf("Adding cache storage for %d more records (%d bytes)", numrecords
, numrecords
*sizeof(CacheEntity
));
7025 for (i
=0; i
<numrecords
; i
++) storage
[i
].next
= &storage
[i
+1];
7026 storage
[numrecords
-1].next
= m
->rrcache_free
;
7027 m
->rrcache_free
= storage
;
7028 m
->rrcache_size
+= numrecords
;
7032 mDNSexport
void mDNS_GrowCache(mDNS
*const m
, CacheEntity
*storage
, mDNSu32 numrecords
)
7035 mDNS_GrowCache_internal(m
, storage
, numrecords
);
7039 mDNSexport mStatus
mDNS_Init(mDNS
*const m
, mDNS_PlatformSupport
*const p
,
7040 CacheEntity
*rrcachestorage
, mDNSu32 rrcachesize
,
7041 mDNSBool AdvertiseLocalAddresses
, mDNSCallback
*Callback
, void *Context
)
7047 if (!rrcachestorage
) rrcachesize
= 0;
7051 m
->CanReceiveUnicastOn5353
= mDNSfalse
; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
7052 m
->AdvertiseLocalAddresses
= AdvertiseLocalAddresses
;
7053 m
->mDNSPlatformStatus
= mStatus_Waiting
;
7054 m
->UnicastPort4
= zeroIPPort
;
7055 m
->UnicastPort6
= zeroIPPort
;
7056 m
->MainCallback
= Callback
;
7057 m
->MainContext
= Context
;
7058 m
->rec
.r
.resrec
.RecordType
= 0;
7060 // For debugging: To catch and report locking failures
7062 m
->mDNS_reentrancy
= 0;
7063 m
->ShutdownTime
= 0;
7064 m
->lock_rrcache
= 0;
7065 m
->lock_Questions
= 0;
7066 m
->lock_Records
= 0;
7068 // Task Scheduling variables
7069 result
= mDNSPlatformTimeInit();
7070 if (result
!= mStatus_NoError
) return(result
);
7071 m
->timenow_adjust
= (mDNSs32
)mDNSRandom(0xFFFFFFFF);
7072 timenow
= mDNS_TimeNow_NoLock(m
);
7074 m
->timenow
= 0; // MUST only be set within mDNS_Lock/mDNS_Unlock section
7075 m
->timenow_last
= timenow
;
7076 m
->NextScheduledEvent
= timenow
;
7077 m
->SuppressSending
= timenow
;
7078 m
->NextCacheCheck
= timenow
+ 0x78000000;
7079 m
->NextScheduledQuery
= timenow
+ 0x78000000;
7080 m
->NextScheduledProbe
= timenow
+ 0x78000000;
7081 m
->NextScheduledResponse
= timenow
+ 0x78000000;
7082 m
->NextScheduledNATOp
= timenow
+ 0x78000000;
7083 m
->RandomQueryDelay
= 0;
7084 m
->RandomReconfirmDelay
= 0;
7086 m
->SendDeregistrations
= mDNSfalse
;
7087 m
->SendImmediateAnswers
= mDNSfalse
;
7088 m
->SleepState
= mDNSfalse
;
7090 // These fields only required for mDNS Searcher...
7091 m
->Questions
= mDNSNULL
;
7092 m
->NewQuestions
= mDNSNULL
;
7093 m
->CurrentQuestion
= mDNSNULL
;
7094 m
->LocalOnlyQuestions
= mDNSNULL
;
7095 m
->NewLocalOnlyQuestions
= mDNSNULL
;
7096 m
->rrcache_size
= 0;
7097 m
->rrcache_totalused
= 0;
7098 m
->rrcache_active
= 0;
7099 m
->rrcache_report
= 10;
7100 m
->rrcache_free
= mDNSNULL
;
7102 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++) m
->rrcache_hash
[slot
] = mDNSNULL
;
7104 mDNS_GrowCache_internal(m
, rrcachestorage
, rrcachesize
);
7106 // Fields below only required for mDNS Responder...
7107 m
->hostlabel
.c
[0] = 0;
7108 m
->nicelabel
.c
[0] = 0;
7109 m
->MulticastHostname
.c
[0] = 0;
7110 m
->HIHardware
.c
[0] = 0;
7111 m
->HISoftware
.c
[0] = 0;
7112 m
->ResourceRecords
= mDNSNULL
;
7113 m
->DuplicateRecords
= mDNSNULL
;
7114 m
->NewLocalRecords
= mDNSNULL
;
7115 m
->CurrentRecord
= mDNSNULL
;
7116 m
->HostInterfaces
= mDNSNULL
;
7117 m
->ProbeFailTime
= 0;
7118 m
->NumFailedProbes
= 0;
7119 m
->SuppressProbes
= 0;
7121 #ifndef UNICAST_DISABLED
7122 m
->NextuDNSEvent
= timenow
+ 0x78000000;
7123 m
->NextSRVUpdate
= timenow
+ 0x78000000;
7124 m
->SuppressStdPort53Queries
= 0;
7126 m
->ServiceRegistrations
= mDNSNULL
;
7127 m
->DNSServers
= mDNSNULL
;
7129 m
->Router
= zeroAddr
;
7130 m
->AdvertisedV4
= zeroAddr
;
7131 m
->AdvertisedV6
= zeroAddr
;
7133 m
->AuthInfoList
= mDNSNULL
;
7135 m
->ReverseMap
.ThisQInterval
= -1;
7136 m
->StaticHostname
.c
[0] = 0;
7138 m
->Hostnames
= mDNSNULL
;
7139 m
->AutoTunnelHostAddr
.b
[0] = 0;
7140 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
7141 m
->AutoTunnelLabel
.c
[0] = 0;
7143 m
->RegisterSearchDomains
= mDNSfalse
;
7145 // NAT traversal fields
7146 m
->NATTraversals
= mDNSNULL
;
7147 m
->CurrentNATTraversal
= mDNSNULL
;
7148 m
->retryIntervalGetAddr
= 0; // delta between time sent and retry
7149 m
->retryGetAddr
= timenow
+ 0x78000000; // absolute time when we retry
7150 m
->ExternalAddress
= zerov4Addr
;
7152 m
->NATMcastRecvskt
= mDNSNULL
;
7153 m
->NATMcastRecvsk2
= mDNSNULL
;
7154 m
->LastNATupseconds
= 0;
7155 m
->LastNATReplyLocalTime
= timenow
;
7157 m
->UPnPInterfaceID
= 0;
7158 m
->SSDPSocket
= mDNSNULL
;
7159 m
->SSDPMulticast
= mDNSfalse
;
7160 m
->UPnPRouterPort
= zeroIPPort
;
7161 m
->UPnPSOAPPort
= zeroIPPort
;
7162 m
->UPnPRouterURL
= mDNSNULL
;
7163 m
->UPnPSOAPURL
= mDNSNULL
;
7164 m
->UPnPRouterAddressString
= mDNSNULL
;
7165 m
->UPnPSOAPAddressString
= mDNSNULL
;
7168 #if APPLE_OSX_mDNSResponder
7169 m
->TunnelClients
= mDNSNULL
;
7172 result
= mDNSPlatformInit(m
);
7174 #ifndef UNICAST_DISABLED
7175 // It's better to do this *after* the platform layer has set up the
7176 // interface list and security credentials
7177 uDNS_SetupDNSConfig(m
); // Get initial DNS configuration
7183 mDNSlocal
void DynDNSHostNameCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
7186 debugf("NameStatusCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
7187 mDNSPlatformDynDNSHostNameStatusChanged(rr
->resrec
.name
, result
);
7190 mDNSexport mStatus
uDNS_SetupDNSConfig(mDNS
*const m
)
7198 DNSServer
*ptr
, **p
= &m
->DNSServers
;
7199 const DNSServer
*oldServers
= m
->DNSServers
;
7202 if (m
->RegisterSearchDomains
) uDNS_RegisterSearchDomains(m
);
7206 // Let the platform layer get the current DNS information
7207 // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
7208 // (no need to hit the network with domain enumeration queries until we actually need that information).
7209 for (ptr
= m
->DNSServers
; ptr
; ptr
= ptr
->next
) ptr
->flags
|= DNSServer_FlagDelete
;
7211 mDNSPlatformSetDNSConfig(m
, mDNStrue
, mDNSfalse
, &fqdn
, mDNSNULL
, mDNSNULL
);
7213 // Update our qDNSServer pointers before we go and free the DNSServer object memory
7214 for (q
= m
->Questions
; q
; q
=q
->next
)
7215 if (!mDNSOpaque16IsZero(q
->TargetQID
))
7217 DNSServer
*s
= GetServerForName(m
, &q
->qname
);
7218 DNSServer
*t
= q
->qDNSServer
;
7221 // If DNS Server for this question has changed, reactivate it
7222 LogOperation("Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)",
7223 t
, t
? &t
->addr
: mDNSNULL
, mDNSVal16(t
? t
->port
: zeroIPPort
), t
? t
->domain
.c
: (mDNSu8
*)"",
7224 s
, s
? &s
->addr
: mDNSNULL
, mDNSVal16(s
? s
->port
: zeroIPPort
), s
? s
->domain
.c
: (mDNSu8
*)"",
7225 q
->qname
.c
, DNSTypeName(q
->qtype
));
7227 q
->unansweredQueries
= 0;
7228 ActivateUnicastQuery(m
, q
, mDNStrue
);
7232 // Flush all records that match a new resolver
7233 FORALL_CACHERECORDS(slot
, cg
, cr
)
7235 ptr
= GetServerForName(m
, cr
->resrec
.name
);
7236 if (ptr
&& (ptr
->flags
& DNSServer_FlagNew
) && !cr
->resrec
.InterfaceID
)
7238 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
7239 mDNS_PurgeCacheResourceRecord(m
, cr
);
7241 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7247 if (((*p
)->flags
& DNSServer_FlagDelete
) != 0)
7249 // Scan our cache, looking for uDNS records that we would have queried this server for.
7250 // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
7251 // different DNS servers can give different answers to the same question.
7253 ptr
->flags
&= ~DNSServer_FlagDelete
; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
7254 FORALL_CACHERECORDS(slot
, cg
, cr
)
7255 if (!cr
->resrec
.InterfaceID
&& GetServerForName(m
, cr
->resrec
.name
) == ptr
)
7256 mDNS_Reconfirm_internal(m
, cr
, kDefaultReconfirmTimeForNoAnswer
);
7258 mDNSPlatformMemFree(ptr
);
7262 (*p
)->flags
&= ~DNSServer_FlagNew
;
7267 // 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).
7268 // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
7269 // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour.
7270 // 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.
7271 if ((m
->DNSServers
!= mDNSNULL
) != (oldServers
!= mDNSNULL
))
7274 FORALL_CACHERECORDS(slot
, cg
, cr
) if (!cr
->resrec
.InterfaceID
) { mDNS_PurgeCacheResourceRecord(m
, cr
); count
++; }
7275 LogOperation("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache",
7276 m
->DNSServers
? "DNS server became" : "No DNS servers", count
);
7279 // Did our FQDN change?
7280 if (!SameDomainName(&fqdn
, &m
->FQDN
))
7282 if (m
->FQDN
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &m
->FQDN
);
7284 AssignDomainName(&m
->FQDN
, &fqdn
);
7288 mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1);
7289 mDNS_AddDynDNSHostName(m
, &m
->FQDN
, DynDNSHostNameCallback
, mDNSNULL
);
7295 // handle router and primary interface changes
7296 v4
= v6
= r
= zeroAddr
;
7297 v4
.type
= r
.type
= mDNSAddrType_IPv4
;
7299 if (mDNSPlatformGetPrimaryInterface(m
, &v4
, &v6
, &r
) == mStatus_NoError
&& !mDNSv4AddressIsLinkLocal(&v4
.ip
.v4
))
7301 mDNS_SetPrimaryInterfaceInfo(m
,
7302 !mDNSIPv4AddressIsZero(v4
.ip
.v4
) ? &v4
: mDNSNULL
,
7303 !mDNSIPv6AddressIsZero(v6
.ip
.v6
) ? &v6
: mDNSNULL
,
7304 !mDNSIPv4AddressIsZero(r
.ip
.v4
) ? &r
: mDNSNULL
);
7308 mDNS_SetPrimaryInterfaceInfo(m
, mDNSNULL
, mDNSNULL
, mDNSNULL
);
7309 if (m
->FQDN
.c
[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m
->FQDN
, 1); // Set status to 1 to indicate temporary failure
7312 return mStatus_NoError
;
7315 mDNSexport
void mDNSCoreInitComplete(mDNS
*const m
, mStatus result
)
7317 m
->mDNSPlatformStatus
= result
;
7318 if (m
->MainCallback
)
7321 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
7322 m
->MainCallback(m
, mStatus_NoError
);
7323 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
7328 extern ServiceRecordSet
*CurrentServiceRecordSet
;
7330 mDNSexport
void mDNS_StartExit(mDNS
*const m
)
7332 NetworkInterfaceInfo
*intf
;
7337 m
->ShutdownTime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
* 5);
7339 #ifndef UNICAST_DISABLED
7341 // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
7342 // because we deregister all records and services later in this routine
7343 while (m
->Hostnames
) mDNS_RemoveDynDNSHostName(m
, &m
->Hostnames
->fqdn
);
7346 for (intf
= m
->HostInterfaces
; intf
; intf
= intf
->next
)
7347 if (intf
->Advertise
)
7348 DeadvertiseInterface(m
, intf
);
7350 // Shut down all our active NAT Traversals
7351 while (m
->NATTraversals
)
7353 NATTraversalInfo
*t
= m
->NATTraversals
;
7354 mDNS_StopNATOperation_internal(m
, t
); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
7356 // After stopping the NAT Traversal, we zero out the fields.
7357 // This has particularly important implications for our AutoTunnel records --
7358 // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
7359 // handlers to just turn around and attempt to re-register those same records.
7360 // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
7361 t
->ExternalAddress
= zerov4Addr
;
7362 t
->ExternalPort
= zeroIPPort
;
7364 t
->Result
= mStatus_NoError
;
7367 // Make sure there are nothing but deregistering records remaining in the list
7368 if (m
->CurrentRecord
)
7369 LogMsg("mDNS_StartExit ERROR m->CurrentRecord already set %s", ARDisplayString(m
, m
->CurrentRecord
));
7371 // First we deregister any non-shared records. In particular, we want to make sure we deregister
7372 // any extra records added to a Service Record Set first, before we deregister its PTR record,
7373 // because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record.
7374 m
->CurrentRecord
= m
->ResourceRecords
;
7375 while (m
->CurrentRecord
)
7377 rr
= m
->CurrentRecord
;
7378 if (rr
->resrec
.RecordType
& kDNSRecordTypeUniqueMask
)
7379 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
7380 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
7381 // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
7382 // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
7383 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not auto-advanced, do it ourselves now
7384 m
->CurrentRecord
= rr
->next
;
7387 // Now deregister any remaining records we didn't get the first time through
7388 m
->CurrentRecord
= m
->ResourceRecords
;
7389 while (m
->CurrentRecord
)
7391 rr
= m
->CurrentRecord
;
7392 if (rr
->resrec
.RecordType
!= kDNSRecordTypeDeregistering
)
7394 //LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr));
7395 mDNS_Deregister_internal(m
, rr
, mDNS_Dereg_normal
);
7397 // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when
7398 // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record
7399 // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate
7400 if (m
->CurrentRecord
== rr
) // If m->CurrentRecord was not auto-advanced, do it ourselves now
7401 m
->CurrentRecord
= rr
->next
;
7404 CurrentServiceRecordSet
= m
->ServiceRegistrations
;
7405 while (CurrentServiceRecordSet
)
7407 ServiceRecordSet
*srs
= CurrentServiceRecordSet
;
7408 LogOperation("mDNS_StartExit: Deregistering %##s", srs
->RR_SRV
.resrec
.name
->c
);
7409 uDNS_DeregisterService(m
, srs
);
7410 if (CurrentServiceRecordSet
== srs
)
7411 CurrentServiceRecordSet
= srs
->uDNS_next
;
7414 if (m
->ResourceRecords
) LogOperation("mDNS_StartExit: Sending final record deregistrations");
7415 else LogOperation("mDNS_StartExit: No deregistering records remain");
7417 if (m
->ServiceRegistrations
) LogOperation("mDNS_StartExit: Sending final service deregistrations");
7418 else LogOperation("mDNS_StartExit: No deregistering services remain");
7420 // If any deregistering records remain, send their deregistration announcements before we exit
7421 if (m
->mDNSPlatformStatus
!= mStatus_NoError
) DiscardDeregistrations(m
);
7425 LogOperation("mDNS_StartExit: done");
7428 mDNSexport
void mDNS_FinalExit(mDNS
*const m
)
7430 mDNSu32 rrcache_active
= 0;
7431 mDNSu32 rrcache_totalused
= 0;
7434 ServiceRecordSet
*srs
;
7436 LogOperation("mDNS_FinalExit: mDNSPlatformClose");
7437 mDNSPlatformClose(m
);
7439 rrcache_totalused
= m
->rrcache_totalused
;
7440 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
7442 while (m
->rrcache_hash
[slot
])
7444 CacheGroup
*cg
= m
->rrcache_hash
[slot
];
7447 CacheRecord
*cr
= cg
->members
;
7448 cg
->members
= cg
->members
->next
;
7449 if (cr
->CRActiveQuestion
) rrcache_active
++;
7450 ReleaseCacheRecord(m
, cr
);
7452 cg
->rrcache_tail
= &cg
->members
;
7453 ReleaseCacheGroup(m
, &m
->rrcache_hash
[slot
]);
7456 debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused
, rrcache_active
);
7457 if (rrcache_active
!= m
->rrcache_active
)
7458 LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active
, m
->rrcache_active
);
7460 for (rr
= m
->ResourceRecords
; rr
; rr
= rr
->next
)
7461 LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr
->resrec
.RecordType
, ARDisplayString(m
, rr
));
7463 for (srs
= m
->ServiceRegistrations
; srs
; srs
= srs
->uDNS_next
)
7464 LogMsg("mDNS_FinalExit failed to deregister service: %##s", srs
->RR_SRV
.resrec
.name
->c
);
7466 LogOperation("mDNS_FinalExit: done");