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